HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 
Persistence Frameworks, by Mike Jasnowski

Most application architectures are organized into tiers. Presentation, business logic, and data combine to form a complete solution from end to end. The data tier is where your application gets and stores data that's used throughout the application. It could be accessing relational- or object-oriented databases or native file stores or connecting to a mainframe to obtain its data.

Application architectures also need to be designed to minimize impact on various components of the application. Another common goal among many database applications is to take unwieldy rows and columns and turn them into manageable application objects.

Without a good design, database applications have a high potential for problems. Changing table structures and column names can wreak havoc on an application. This article focuses on use of a persistence framework to access application data - TOPLink for Java - in a functioning web-based application. I'll demonstrate how easy it is to create a database application using a persistence framework, the timesaving over hand-coding SQL, and the supporting code to turn it into a Java object. I'll also point out advantages a persistence framework provides in areas other than removing SQL code from your application code. (The listings for this article can be found on the JDJ Web site.)

The toolkit discussed in this article consists of:

  • JDK1.2
  • IBM DB2 Universal Database Personal Edition (sample database)
  • DB2 JDBC driver from IBM
  • TOPLink for Java 2.5
  • Allaire JRun 3.0
See the "Links" section at the end of this article for information on obtaining evaluation copies of some of the software used. My example application requires the use of TOPLink for Java, the other software may be replaced by your preferred choice. (While I discuss the features of this product in some detail, this isn't a product review.)

Persistence
The storage of data used in an application is sometimes referred to as persistence. Data that's used is persisted between uses of the application by an individual user. Things such as account information, user preferences, or application data can be stored and later retrieved by a user. There's more than one type of persistence. Object-relational persistence is one of the more common methods of persisting data. Object-relational persistence involves the mapping of attributes of an object to the rows and columns of a relational database table (see Figure 1).

Figure 1
Figure  1:

Before persistence frameworks, some applications may have been written in a fashion similar to that shown in Listing 1. However, as applications increased in complexity, application designs such as the one in Listing 1 would become unmanageable. An increase in the complexity of the data model could also break it. By providing a framework for managing the access not only to your data but to the process of turning that data into objects, you can reap benefits in both cost and time of development.

TOPLink for Java
TOPLink for Java is an object-relational persistence framework. It's available for other languages but its use in this article will focus on Java. Features include:

  • Handling of different types of mappings, one-to-many, many-to-many
  • Caching of retrieved objects
  • Expression classes for constructing queries
  • Named queries and query keys for abstracting queries from field names in your table
  • Descriptors that are external files used to describe class-to-table relationships
  • A UnitOfWork, which encompasses changes to table(s) inside a transaction as well as rolling back changes (should problems occur), even across multiple tables
  • Indirection, which causes reading of related objects to be deferred until they're accessed
TOPLink allows you to map your objects and attributes to the rows and columns of your relational database tables. You can perform this mapping at runtime using the TOPLink API, or at design time using the TOPLink Builder.

Sample Application
Our sample application will be a simple web-based phonebook. It will present the user with a primary display of a phonebook. Information will be stored for the name, address, and telephone number. Functionally it provides some basic features that will exercise the persistence framework such as reading and adding new records. Following are the steps we'll take to build this example:

  1. Create the database tables.
  2. Create our business objects.
  3. Create our mappings using TOPLink builder.
  4. Create our application logic and user interface.
  5. Run our application.
Create the Tables
The tables used during this application are composed of persons and phonebooks. You can run the following SQL statements to create the necessary tables and insert some dummy data into the phonebook table.

CREATE TABLE PERSONS(
AREACODE CHAR(16) NOT NULL,
NAME CHAR(40) NOT NULL,
ADDRESS CHAR(60) NOT NULL,
TELEPHONE CHAR(15),
PRIMARY KEY(AREACODE,NAME,ADDRESS)
)

CREATE TABLE PHONEBOOK(
AREACODE CHAR(16) NOT NULL,
PRIMARY KEY(AREACODE)
)

INSERT INTO PHONEBOOK (AREACODE) VALUES('12345')
INSERT INTO PHONEBOOK (AREACODE) VALUES('67890')

Create the Business Objects
The business objects used in this application are composed of a class called person and one called phonebook. Phonebook holds a vector of person objects (see Listings 2 and 3).

Create TOPLink Mappings
Once we've created our objects and database tables, we can start creating our TOPLink mappings using the TOPLink builder. Essentially, the steps we need to take are:

  1. Specify the database login information including the JDBC driver to be used.
  2. Import our classes into the TOPLink Builder.
  3. Import our database table into the TOPLink Builder.
  4. Map the classes to the tables.
  5. Save our project.
I won't go into explicit detail on how to accomplish the mappings in the builder, as the TOPLink documentation should cover this. When you're finished, your TOPLink builder project should look similar to Figure 2.

Figure 2
Figure  2:

When developing with TOPLink, there are two items you should note:

  1. TOPLink requires each table or view that's mapped to have a primary key.
  2. Each primary key must be mapped to an attribute in the corresponding Java class.
If you're using the TOPLink builder to perform your mappings, it will indicate which keys are unmapped as well as which tables don't have primary keys specified. If you're not using the TOPLink builder, when your application runs, it will fail with an exception indicating a similar error.

Create the Application Logic and User Interface
Now that we have our objects mapped, we need to create the application logic and the user interface. The UI for this application will allow us to:

  • View all area codes in our phonebook.
  • View the phonebook for a specific area code.
  • Add a new entry to the phonebook for a specific area code.
I've tried to keep the application as simple as possible, although applications significantly more complex are possible with the persistence framework used. This application is broken into an index page, a ViewPhoneBookServlet, and a ViewAreaCodeServlet. This code isn't intended to be production quality. It's designed simply to illustrate the use of a persistence framework in your application. We'll also create a specific class to handle all our TOPLink start-up requirements (see Listing 4). TOPLinkSession makes the connection to our database, providing a session handle through which we can interact with the persistence framework. The class takes care of loading the appropriate JDBC driver and logging into the database. Ideally, the TOPLinkSession should be a single instance, but in this application, each servlet that requires database access creates an instance. See Listings 5-10 for these files:
  • ViewPhoneBookServlet.java: Displays a list of area codes from which to select
  • ViewAreaCodeServlet.java: Displays a list of persons for a specified area code
  • AddNewPersonServlet.java: Displays a page that allows you to add persons to an area code
  • Viewareacode.jsp: Called by ViewAreaCodeServlet to display persons for an area code
  • Addnew.jsp: Called by AddNewPersonServlet to add a new person
  • Phonebooks.jsp: Called by ViewPhoneBookServlet to display area codes
I'll focus on two primary areas of the code, reading and writing to the database, and point them out in the code.

Reading from the Database
The application uses objects and methods of the persistence framework to read data from the database. In ViewPhoneBookServlet (see Listing 5), you'll notice the following line:

Vector pBooks = tlSession.getSession().readAllObjects(PhoneBook.class);

This line of code is all that's required to read data from the phonebook table and assemble it into a vector of PhoneBook objects. It calls the readAllObjects method of the DatabaseSession object contained in our TOPLinkSession class. The DatabaseSession method readAllObjects is just one of the many methods TOPLink provides to read data from the database. The SQL output from TOPLink for the following sequence of code would look something like this:

session(-335903629):
thread(1730053239): connection(-365525901):
SELECT ADDRESS, AREACODE, NAME,
TELEPHONE FROM PERSONS WHERE (AREACODE = '99999')

Writing to the Database
The application also utilizes objects and methods of the persistence framework to write data to the database. In AddNewPersonServlet (see Listing 7), you'll notice the following block of code:

  1. UnitOfWork uow = tlSession.getSes sion().acquireUnitOfWork();
  2. PhoneBook pBookClone = (Phone Book)uow.registerObject(pBook);
  3. Person personClone = (Person)uow.registerObject(newPer son);
  4. personClone.setName(req.getParame ter("NAME"));
  5. personClone.setAddress(req.getPa rameter("ADDRESS"));
  6. personClone.setTelephoneNumber (req.getParameter("TELEPHONE"));
  7. personClone.setAreaCode(req.getPa rameter("AREACODE"));
  8. pBookClone.addPerson(personClone); uow.commit();

Writing requires somewhat more code, but is equally as straightforward. Line 1 acquires a UnitOfWork from the persistence framework. Lines 2 and 3 register the PhoneBook and Person objects we're about to use in our update. Lines 4-8 set the values of our new objects. Line 9 calls the commit method of the UnitOfWork object created in Line 1, and our update takes place, wrapped in a transaction. The SQL output from TOPLink for the following sequence of code would look something like this:

session(727882650): thread(1391369113):
acquire unit of work
session(1868471198): thread(1391369113):
begin unit of work commit
session(727882650): thread(1391369113):
connection(729979802): begin transaction
session(1868471198): thread(1391369113):
connection(729979802):
INSERT INTO PERSONS (ADDRESS, AREACODE, NAME, TELEPHONE)
VALUES ('123 Main St', '99999', 'AnyBody', '405-345-5678')
session(727882650): thread(1391369113):
connection(729979802): commit transaction
session(1868471198): thread(1391369113):
end unit of work commit
session(1868471198): thread(1391369113):
release unit of work

Run the Application
Once you've compiled all your classes and placed them in the appropriate subdirectories, start your browser and point it at http://localhost:8100/servlet/ViewPhoneBookServlet, the starting point of our application. You'll be presented with a list of area codes. Select an area code and press the GO button.

You'll see a page with some headings and an Add button. Press Add and fill out the form. When finished, press Save and you'll be redirected back to see your update. Open up the DB2 Command Center and run the following query, SELECT * FROM PERSONS.

You can see that the new person exists in the database, all without coding a single line of SQL! However, if you're interested in seeing what TOPLink is doing, we can turn on logging and log any SQL to an external file. The following code snippet demonstrates this; it can be added to the TOPLinkSession class.

session.logMessages();
try{
session.setLog(new OutputStreamWriter(new
FileOutputStream("C:\\debugsql.log")));
}catch(Exception ex){System.out.println(ex);}

I'd also like to point out that when retrieving a phonebook, the persistence layer retrieved all persons associated with that phonebook using the AREACODE key.

Advantages/Disadvantages
Using a persistence framework provides the following advantages:

  • Caching of retrieved objects
  • Separation of SQL from application logic
  • Separation of the data access layer from application
  • Caching and indirection can provide performance benefits when accessing application data.
  • Simplified access to complex database structures

    Disadvantages are:

  • Learning curve
  • May require changes in your data model and/or current code
I'd also like you to compare Listings 1 and 5; you'll no doubt notice the difference. Regardless of the disadvantages, an investment in using a persistence framework can yield longer-term benefits as your applications increase in complexity and size.

Links
The following links can be used to obtain free evaluation copies of the software referred to here, as well as some of the other software used. Additionally, TOPLink will function with JDK1.1. The TOPLink for Java evaluation requires a temporary license key, which is e-mailed to you. Good luck!

  1. TOPLink for Java - The Object People/WebGain: www.objectpeople.com
  2. JRun 3.0 - Allaire Corporation: www.allaire.com
  3. Java 2 Standard Edition: http://java.sun.com
Author Bio
Mike Jasnowski, a Sun-certified Java programmer, has over 17 years of programming experience, and over four years with Java. He's a senior software engineer with eXcelon Corporation in Burlington, Massachusetts. [email protected]
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.