Who Are You, Anyway?
By Al Williams
One hallmark of a great restaurant is that the staff knows your name and remembers you when you visit. How many movies have you seen where someone orders "the usual" and the waiter or bartender knows what to do? Personally, I've only been to a few places that offer that level of servicemaybe times have changed, or maybe it's just me.
The best Web sites do the same thingthey remember you. Maybe they know what background color you like, or what sports teams you follow. Some e-commerce sites remember your basic information so you don't have to retype it for each order.
Unfortunately, remembering data about users isn't one of those things that comes easily on the Web. Each Internet transaction is typically an anonymous one-time affair. This has resulted in the emergence of a variety of techniques that let you identify and store data that pertains to a user.
Sessions
The HTTP protocol supports cookiessmall bits of data that the server can deposit and retrieve from the user's browser. If the server assigns each browser a unique identifier, the server can identify repeated requests from the same browser. (There are other ways to make this association, but cookies are the cleanest and most common.) Browsers don't have to accept cookies, but because so many sites require them, most users don't completely shut them off.
JavaServer Pages (JSPs), like many similar systems, artificially create the notion of a session. The first time a browser requests a page, the server assigns the browser a unique ID and stores it in a client-side cookie. Subsequent requests contain this cookie and the server knows they originated from the same browser.
Session management is important in many cases. For example, when a customer fills a shopping cart, you'll want to remember the contents of that cart the entire time the customer visits the site. However, session management goes only so far. A browser can arbitrarily erase cookies whenever it wants to do so, and cookies eventually expire. Typically, a session cookie will last around 30 minutes (each page view restarts the clock). It would be unusual to find a session that lasts for days or even hours. Also, cookies belong to a particular browser on a particular computer. Your session at work won't apply to your session at home.
The solution is to store session data in a persistent form, like in a database. Coupled with a way to let users identify themselves, you can recall preferences and other data on a per-user basis, instead of only for the session.
Beans and JSP
JSP has all the pieces you need to handle this situation easily. However, the logic is a bit complexmaybe too confusing to code completely in JSP. Instead, I decided to make a user property database JavaBean that you could easily use from within JSP. The core bean is abstract specific implementations could store data in a flat file, a property file, an XML file, a database, or any place you want to store the data. The bean lets you easily associate a user name (that's password-protected) with a set of properties.
JSP is a simplified way to create servlets. Most people would agree that creating a JSP script is simpler than writing a servlet from scratch. However, writing too much Java code in a JSP is often bad form. One of JSP's strengths is that it lets HTML authors and designers focus on the page structure and simply sprinkle in Java code where it's required. However, when the code overwhelms the HTML markup, much of this benefit evaporates.
Fortunately, there's a middle ground. You can write a custom JavaBean that you can easily incorporate into the JSP page. Don't worry about the complexity of JavaBeans. You'll find it's easy enough to create beansthey're little more than ordinary Java objects that follow a few naming conventions. In fact, you don't really have to create a JavaBean at all. However, JSP is especially adept at including beans, and the extra trouble to create one is minimal.
What makes a JavaBean? For the purposes of this discussion, a bean is any public Java class that doesn't expose public fields. That doesn't mean the object can't have fields, or even that the object can't share fields with outside programsin a way. Instead of fields, beans have properties. A property appears to be similar to a field. However, when you change or read a property, you're really calling special functions within the bean to do the work. If you want a property named
xyz
, you'd providegetXyz
andsetXyz
methods. Many bean-aware programs automatically generate these method calls when you request access to a property. Bean-aware programs understand that this is really a property.
Of course, the
get
andset
methods might simply provide access to a nonpublic field. On the other hand, some properties don't directly correspond to a variable. For example, you might have a field calledisServerUp
that indicates if another machine is available on the network. ThegetIsServerUp
method might not reflect a variable at all. Instead, it would poll to see if the server was running using a socket. There might not be asetIsServerUp
method since that wouldn't make much sense. In that case, the property is read-only.
Is that all there is to JavaBeans? No. However, for adding functions to JSPs, it's all you really need to know.
Design
The base class for the property database is
UserDB
(see Listing 1). The class provides abstract methods that handle the actual transfer of data. In particular:
getProperty
Fetches a property for the current user from the database.
writeProperty
Writes a property for the current user (not necessarily saving it).
save
Saves the property database to persistent storage.
load
Loads the database for a specific user (validating the password).
create
Creates a new user.
Although the abstract base class doesn't provide any of these functions, it does provide support for them. In particular, the base class maintains the user name, a directory prefix to identify the location of the data (this isn't necessarily an actual directory nameit could be, for example, a dataset name), an auto- save flag, and a dirty flag. If you set the autosave flag, and the database is dirty (that is, changed), the base class code will automatically issue a save when the session expires.
To detect session expiration, the base class has to implement the simple two-method
HttpSessionBindingListener
interface. This interface lets you detect when a session begins and ends.
In general, a session begins when the user first views a page. It expires after a certain amount of time elapses with no activity from the user, or when your script explicitly invalidates the session. You can release an active session with the following code:
request.getSession(). invalidate();
Because the abstract base class fully implements
HttpSessionBindingListener
, there's no need for the derived classes to know anything about session management. All the work occurs behind the scenes.
Implementation
One possible database for user information is a collection of ordinary Java property files. I've used property files in a few projects lately, and they offer an easy-to-understand, simplified database for Java programs. Of course, for industrial-strength Web sites, you'd want to use a better database, but property files are easy to use for a modest site and they keep the example code simple. The base class has no prejudiceyou can easily derive a new class to use the database of your choice.
The property file implementation appears in Listing 2. You'll see that the only methods of substance are
create
,load
,save
,getProperty
, andwriteProperty
. As you'd expect, these map to various methods of a protected instance of theProperties
object. Each user has his or her own property file stored in the directory specified. The password appears unencrypted in the property file, so the directory shouldn't be accessible via the Web server.
By default, the autosave feature is off, so you'll have to explicitly call
save
when you want to update the underlying property file. You can also turn on automatic saving so that the file updates when the session ends.
The hardest part of building the bean is making the JSP container recognize it. You want to put your beans in a directory along the server's class path. Exactly where to put your class files depends on what container you're usingand your particular setup.
Using the beans requires a few pages, no matter what. First, you need a login page that accepts the user's ID and password. Next, you probably want a page that lets you create a new ID. It's also handy to have a page that forces an end to the user's session. This effectively logs the user out of the system.
The key to making this system viable is to create the database bean with session scope. When you include a bean in a JSP page, you can specify the scope and name that you want it to have. Each time you include the bean, the JSP container first checks to see if the bean already exists in that scope. If it does, you simply get that instance of the bean. If it doesn't, the container creates a new bean for you.
Beans with session scope persist until the session is over. That means if you create a database bean with session scope, every page the user visits will use the same bean. That lets you initialize the bean on the login page without having to reinitialize it on every successive page. Because each user has a separate session, you don't have any privacy problems with one user accessing a different user's settings. Of course, this simple system is far from secure. You'll want to avoid storing sensitive informationlike credit card numbers, for examplein a plain-text property file.
Here's the JSP tag that creates (or finds) the bean:
<jsp:useBean id="upd" class="UserDBProp" scope="session"/>
The bean's name in this case is
upd
. In a way, this is similar to writing:
UserDBProp upd = new UserDBProp();
The big difference, however, is that if
upd
already exists with session scope, you'll simply retrieve the existing instance of the class.
You can also use special tags to access the properties of the bean (although you can refer to them in ordinary JSP scriptlets, as well). For example, here's a tag that sets the
dir
property:
<jsp:setProperty name="upd" property="dir" value="c:/tmp"/>
Don't forget that this results in the actual bean receiving a call to
setDir
. This tag doesn't directly attempt to access a field nameddir
, even though that seems to be the case.
You can find an example login script in Listing 3. The form submits data back to itself. If it detects data entry, it attempts to load the user's properties. If this fails (that is, load returns false), then the same form will appear with an additional error message in red. If the load is successful, the script redirects to the home page automatically (see Listing 4).
Creating a new user is practically the same operation (see Listing 5). The only difference is that in this case, the user must not already exist, and upon success, the script creates the property file and redirects the user back to the login page.
Enhancements
Of course, one obvious enhancement you could make to this system is to use a true database like MySQL or Access to store the data. Improved data security would also be nice. Another useful feature would be to remember the user's ID and password in a cookie for future logins, or to offer a way for the user to retrieve a lost password via email.
You could even use this system to implement a rudimentary security system. Each page could include a JSP file that checked to see if the user's login was accepted. If not, it could redirect the user to the login page. This would make it nearly impossible to view a page without entering your password. A variation on this theme is to assign users a security clearance that controls what they can see. Certain pages might not be accessible unless your clearance is over, say, 100.
Even if you don't want to remember your users, I hope you'll remember this: It's easy to add sophisticated features to JSP by using simple beans. Not only will you be able to teach your Web pages some new tricks, but your JSP pages won't be cluttered with abstruse Java code.
(Get the source code for this article here.)
Al is a consultant who lives near Houston, TX. You can find him on the Web at www.al-williams.com.