Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Backstage at the JDC: Registration Management

 
 

Articles Index


Note: Thanks to our ever astute JDC membership for finding a synchronization problem in the UserRegistryJdbcImpl class. A new version of the file with the issues resolved is now available. Please download the new Register.zip file to get the changes.

The previous "behind the scenes" look at the Java Developer Connection (JDC) discussed how the site handles session management. While that article went into some detail as to how the login process itself works, it didn't cover the specifics of how members become registered to begin with.

This edition of "Backstage at the JDC" focuses on the actual registration process--the classes involved, and in particular, the UserRegistry abstraction. If you'd like to go further, you can download the Register.zip file in order to obtain all the classes and sample code featured in the article.

Overview

All JDC member information is maintained within an Oracle database. Because of a key abstraction known as the UserRegistry, however, none of the JDC software depends upon the specifics of any one registry implementation. Rather than having components such as RegisterServlet make database queries directly, the UserRegistry instead provides the necessary abstraction for retrieving and updating member information. The following sections outline the specific classes used in registration, and discuss in greater detail the abstractions found within the JDC.

Why Abstractions?

One key feature of object-oriented software development is the concept of abstractions. Simply stated, an abstraction removes implementation-specific dependencies from your software. In the case of the JDC, having database-specific dependencies strewn throughout the code would make it very difficult to change or modify a given implementation after the fact. Such modifications might then require changes within areas that shouldn't really "care" about the specifics of the database being used. Within the JDC, the UserRegistry provides this data access abstraction (in the form of an interface) for all dependent code.

Another excellent reason for developing abstractions, is that it forces the software engineer to think clearly about the classes being built. In the process, the developer is required to ask, "What are the important operations this abstraction needs to provide?" Thinking about such abstractions helps one to see beyond the mere implementation, and to start viewing the system at a much higher level.

For more information about object-oriented software engineering, see the list of recommended titles at the end of this article.

Basic Components

The UserRegistry abstraction provides two essential methods--getMember and setMember. As the name implies, the getMember method simply retrieves an existent JDCMember instance from the UserRegistry. The setMember method, meanwhile, either updates an already existent member record, or creates a new entry entirely.

There are three key classes relevant to JDC registration: JDCMember, RegisterServlet, and UserRegistry.

  • JDCMember-- provides the methods and variables specific to an individual JDC member instance.
  • RegisterServlet-- provides the big-picture logic and data checking inherent to registration processing.
  • UserRegistry-- provides the relevant member access abstraction

Together, the JDCMember and UserRegistry classes are used for updating, registering, and authenticating (the Authenticator implementation used in the SessionServlet is an implementation of UserRegistry), as well as for processing JDC "Duke Dollars." In short, the two classes are key to the smooth functioning of the JDC infrastructure as a whole.

Note: The UserRegistryHashtableJdbcImpl is an alternative implementation to using a JDBC database.

Registration

Given a well-defined abstraction for accessing member information, Registration then becomes a much easier process. For this article, the original RegisterServlet is simplified to exclude certain complexities pertaining to multiple fields and wild cards. Yet hopefully, the examples still provide sufficient coverage to serve as the basis for a more complete and individualized registration servlet implementation.

The RegisterServlet has two basic responsibilities: to create new entries in the UserRegistry, and to prevent duplicate entries from occurring. The production version of the RegisterServlet presents a variety of registration-related pages. For simplicity's sake, however, this version uses a simple HTML error page. Thus, for any invalid data (such as a duplicate userid), the code simply returns an SC_INTERNAL_SERVER_ERROR (error type 500), along with an appropriate text message. The actual JDC implementation provides a far more elegant registration experience, but the important basics presented here remain the same.

Within the main block of the RegisterServlet (the service method), the code first ensures that a userid and password are entered by the user (line 66). Next, assuming the userId and password variables contain data, the database is checked for a possible duplicate (lines 71-76). Notice that the getMember method potentially returns an array of JDC members. This is a processing artifact from the JDC production usage of getMember (involving wild card searches), where multiple member objects can conceivably be returned.

Assuming a duplicate (already existent) record is found, the code returns an SC_INTERNAL_SERVER_ERROR, along with an appropriate text message. If no duplicate exists, however, we simply add the JDCMember instance to the UserRegistry (thus granting membership), and redirect processing to the SessionServlet (line 84).

That's all there is to registration! But as previously mentioned, most of the work is done within the UserRegistry's JDBC implementation.

Fun with JDBC

Using JDBC makes life a lot easier when accessing a database. JDBC, in a nutshell, is a Java API for an interface to a database. With the JDBC API, it's no longer necessary to write one program to access a Sybase database, another program to access an Oracle database, and so on. One can write a single program using the JDBC API, and the program (given the appropriate JDBC driver) will then be able to issue statements to any given database.

There are a great many articles available on how to use JDBC, and several available within the JDC. Also, the book JDBC Database Access with Java is available as part of The Java Series.

The first thing executed in the UserRegistryJdbcImpl (implementation of the UserRegistry interface) is to load the JDBC driver (line 58), and then initiate a connection to the database (line 230). This is done within a static initializer so that there is only one driver for the multiple instances of the class. As you might suspect, this design decision is a simple matter of conserving system resources. In reality, there is generally only one instance of the UserRegistryJdbcImpl created within the servlets in the Java Web Server, but in practice there could always be more than one. Note that the user and password values found in the database connection code, as well as those for the driver and URL (lines 34-37), are specific to this particular demo database implementation. Your own values will, of course, differ depending upon the individual database configuration.

As part of initialization, three prepared statements are also created: _insertStatement, _updateStatement, and _queryStatement (lines 47-49). Once properly loaded with their respective SQL-based text and data, these three statements provide all necessary access to the database.

Getting a Member

The getMember method (line 75) performs a simple query to the database to retrieve data pertaining to a given JDCMember instance. Here, the code is significantly simplified from the actual JDC production version, which anticipates possible wild cards and case sensitivities. The demo method simply takes the passed userId value and sets it in the _queryStatement. The results are returned in an array of JDCMember (the array being an artifact of wild card logic). If no member is found, the method returns a 0 length array.

Note that the _queryStatement parameters are cleared in the finally clause of the try block (line 113). This operation is performed for all three PreparedStatement variables (line 230), and should be done before reissuing any of the commands. Failure to do so may produce unexpected results.

Setting a Member

The setMember method (line 143) returns current data if an entry already exists for that user. By checking whether an entry exists (line 150), setMember implicitly determines whether the given operation will be an insert or an update. For an already existent value, an update operation is performed using the _updateStatement. Otherwise, a new record is added using the _insertStatement.

In both the setMember and getMember methods, an open database connection is first confirmed before processing further. If for whatever reason the connection is closed, reconnection is first established, along with re-creation of the three prepared statements (_insertStatement, _updateStatement, and _queryStatement), see the _init method (line 226.)
 

Another Abstraction.

Some interested readers may not have a database available. If so, one simple way to get around the problem is to create an alternate UserRegistry implementation--one using files for storage, or a Java Hashtable serialized to disk. The specifics of such an implementation are left to the reader as an exercise.

Once the new storage system is in place, however, the RegisterServlet need then only create a new instance of the implementation. After that, the code should work just fine! Such is the elegance of the abstraction concept. Note, however, that if you are using the SessionServlet code from the previous article in the "Backstage" series, be sure that the Authenticator uses the same underlying storage medium as the records you create with the RegisterServlet. One way to ensure data consistency between the Authenticator and UserRegistry is to have the UserRegistry interface extend the Authenticator interface. Then, simply have your UserRegistry extension implement the isAuthorized method.

Conclusion

As with much of the JDC sample code, you can download the Registration Servlet classes and use them for your own web site. But be sure to first purchase the Java Web Server (or some other servlet-compatible product). The Registration Management servlet code runs with JWS 1.0.x. If you are using JWS 1.1 Beta, the code may not work correctly. You can download a copy of JWS 1.0.3 at http://java.sun.com/products/java-server/webserver/index.html.

Further Reading

There are many excellent books on the subject of object-oriented software engineering. The JDC encourages all Java developers to explore the relevant literature. Some recommended titles are:

  • Bertrand Meyer. Object-Oriented Software Construction. Series in Computer Science. Prentice Hall, NJ, 1988.
  • Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns - Elements of Reusable Object-Oriented Software. Addision-Wesley Professional Computing Series. Addision-Wesley Publishing Company, 1995.
  • James Rumbaugh, Michael Blaha, William Premerlani, Fredrick Eddy, and William Lorensen. Object-Oriented Modeling and Design. Prentice Hall, NJ. 1991.
  • Ivar Jacobson, Magnus Christerson, Patrik Jonsson, Gunnar Overgaard. Object-Oriented Software Engineering - A Use Case Driven Approach. Addision-Wesley, 1992.
  • Grady Booch. Object-Oriented Software Engineering. Prentice Hall, NJ, 1993.

coffeecup Tony Squier is a JDC tools engineer. He developed the JDC registration-management code. He invites any feedback you have about the article or the code, such as enhancements or potential bugs. If you have comments please send them to: Tony Squier

Steven Meloan is a writer, journalist, and former software developer. His work has appeared in Wired, Rolling Stone, BUZZ, San Francisco Examiner, ZDTV's "The Site," and American Cybercast's "The Pyramid."