JPOX and Tapestry : The Developer's Guide to the Petshop Example

Document version 0.91.

© 2004 David Ezzio. All rights reserved.

The Petshop example uses Tapestry and JPOX This document is a guide for building the Petshop example from source. It also discusses the recommended design choices followed by the example code, and it compares the use of JPOX to the use of the Data-Access-Object (DAO) design pattern. JPOX provides a downloadable sample with the code described here. While this sample is for JPOX, it can be converted to DataNucleus easily.



What is the Petshop example?

This example, called Petshop, is a port of the Petshop example (Version 0.41) created and distributed by Luis Neves. Like the VLib example that is also distributed with DataNucleus, the Petshop example shows how a Tapestry Web application can use JDO.

The original Petshop example is, I believe, a recreation of the J2EE Petstore example. The fictitious business case for the Petshop is an on-line business that sells pets. The Petshop Web application allows people to browse or search the catalog of pets, select pets for purchase, and complete the order. Luis Neves shows off Tapestry’s support for internationalization by supporting both a Portuguese and English version of the site. This port continues to do the same.

The original Petshop example uses JDBC and the Data Access Object (DAO) pattern to access the database and provide the persistence layer. The ported example uses JDO to provide the persistence layer.



Who is most likely to benefit from this example?

Developers who are familiar with or learning Tapestry will benefit from this example. Developers who are very familiar with the DAO pattern using JDBC and who are thinking of adopting JDO will benefit from comparing this version of the example with the original.

Technical managers who are evaluating whether to use JDO in their development process will benefit from considering the metrics drawn from this example. (See last section.)



What is Tapestry?

Tapestry is a Web application framework from Apache. It can be found at http://jakarta.apache.org/tapestry.

Web applications within Tapestry follow the model-view-controller (MVC) pattern. The view consists of HTML templates, and specifications in XML for JavaScript, as well as style sheets and graphic resources. The controller consists of Java code with page and component wiring in XML. Tapestry does not provide a model, making it an ideal partner for JDO.

Tapestry abstracts from the multi-threadedness of the Servlet API and provides tight coupling between the HTTP request and response handling code. The same components that participate in the rendering of page also accept the user’s response to the page. The handshaking between HTTP responses and the Java code is handled by the framework, so that most dynamic information presented on the page and most user input to the page are represented as properties of the Tapestry page or its components. The user’s next request action results in an invocation of a listener method on the page or one of its components. Every Tapestry page and component is single-threaded by design, and contrary to what you might be inclined to believe, it performs quite well because of object pooling.



How does the Petshop example differ from the original?

The Petshop example is a port (or fork) of the Petshop example that is distributed by Luis Neves.

Unlike the original which uses the DAO pattern and JDBC to implement the model, the Petshop example distributed by DataNucleus uses JDO.

In general, most of the presentation files are unchanged, and those that are changed, are changed very little. The controller code varies class-by-class from no change, to one or two little changes, to many small changes. The model code has been extensively modified, although there is a family resemblance to the original code.



How do I set up the Petshop example in my development environment?

This example is distributed as source only. This section documents the steps you need to follow to successfully build the example from source.

The preliminaries

For many of you, the preliminary configuration steps for a development environment are no-ops, since you will have several of these pieces already installed and ready to use. For the rest of you, this checklist will help you pick up the pieces that you need.

  • Install JDK 1.4 or later. This Petshop example uses the version of java.lang.Throwable with a nested cause exception that was introduced in JDK 1.4. So far as I know, this is the only dependency on JDK 1.4.
  • Install Ant 1.5.3 or later. This product is available from the Apache Foundation.
  • Install Tapestry 3.0. This product is available from the Apache Foundation. If you are just learning Tapestry, you should get the Hangman example working. The book Tapestry in Action from Manning Publications can be quite useful.
  • Tapestry requires two libraries that are not distributed with it. Obtain the JavaAssist library, version 2.6 or later, from the JBoss Group. Obtain the Object Graph Navigation Language library, version 2.6.3 or later from OGNL Technology Inc.. If you create a directory named extras under your Tapestry home directory and place these two jar files there, you’ll have one less configuration step in the build file.
  • Install DataNucleus 1.1.0.A2 (or later). If you are new to JDO, you should work through the DataNucleus tutorial. The book Using and Understanding Java Data Objects from Apress can be quite useful for understanding both the details of JDO and the big picture.

    The DataNucleus 1.1x implementation is a preview implementation of the coming JDO 2.0 specification. This example uses some mapping features found in this branch of DataNucleus that are not found in the 1.0 branch, which is a JDO 1.0.1 implementation. Other than the new mapping features, the Petshop example does not use any of the new features found in JDO 2.0. A later section of this tutorial discusses the reason for using the mapping features.

  • Install the McKoi database version 1.0.2 or later, a lightweight, Java only SQL database. This open-source database is available from http://www.mckoi.org.

    A ready to use set of data files is distributed with this example in the mckoi-db directory as a zip file. Unzip PetshopDB.zip to the root directory of your McKoi install.

    The command files run.bat and stop.bat are included for Windows users. These start and stop the database server. If you are running on Linux or some other environment, you’ll have to create the scripts to start and stop the database.

    In addition, there is a console.bat command file to startup the interactive console to the McKoi Petshop database. This tool can run only when the database server is stopped. Again, those who are not using Windows will have to create the script to start the console. Use this tool to examine the data in the database.

  • Since the Petshop example is a Web application, you need a J2EE Web container, such as Tomcat from the Apache Foundation.
  • Copy the McKoi jbdc driver library mkjdbc.jar found in the McKoi home directory to the appropriate location for your Web container. For Tomcat, the appropriate location is <tomcat-home>/common/lib .
  • Unzip the Petshop example code to a directory of your choice.


Configure the build file

Before running the build file you must configure it for your development environment. To do this, assign the correct values for your development environment to the properties defined near the top of the build file. Here is a short description of each property found there.

  • webapps.dir : Path to the directory where the Web application war file should be deployed.
  • jpox.home : Path to the DataNucleus home directory.
  • jpox-jar : Path to the DataNucleus runtime jar file.
  • jpox-enhancer-jar : Path to the DataNucleus enhancer jar file.
  • bcel-jar : Path to the BCEL jar used by the DataNucleus enhancer.
  • tapestry.home : Path to the Tapestry home directory.
  • tapestry-extras.dir : Path to the directory where you placed the extra libraries required by Tapestry. (See above section.)


Build and deploy

The two main build targets are clean and deploy . Invoke Ant in the customary way. The Ant download provides ample documentation for getting started with Ant.

Invoke first the clean task, then the deploy task. In both cases, you should see a message that indicates that the build was successful.



Test the Petshop Web application

After the task deploys the Petshop Web application, start up the Web server if it is not already running. Visit the site by using an URL like the following, http://localhost:8080/petshop/app . The host name and port may differ for your development environment. If everything has gone well, you’ll see a web page like the following.

The site is easy to use. It has a link to the help page that tells you more. The password for the “j2ee” user is “j2ee”.



What databases does the Petshop example support?

The original Petshop example comes with data definition language (DDL) scripts to initialize a McKoi database, a Microsoft SQL Server database, or a PostgreSQL database. DataNucleus itself supports a large number of relational databases.

When building applications that use JDO, real world requirements often include the need to support an existing database schema. For that reason, I adopted the requirement that the port of Petshop to DataNucleus would support the existing McKoi data schema. This requirement led to three results. One, the port does support the same McKoi data schema as the original Petshop example. No changes whatsoever to the existing tables. DataNucleus does add its own DataNucleus_TABLE, which it uses to keep track of the persistent classes. Two, in order to get the mapping functionality that I needed to meet this requirement, I had to adopt the DataNucleus 1.1 line which has already implemented some of the mapping functionality found in the coming JDO 2.0 specification. Three, to minimize the amount of testing, I limited myself to only the McKoi database schema.

If someone wants to support either Microsoft SQL Server or PostgreSQL using the original DDL (shipped with this example), the changes required, which may not be many, should be limited to the JDO metadata. If someone wants to lift the restriction that an existing schema must be supported, again the metadata must change, and in addition, a means must be devised to initialize the test data for the schema that DataNucleus will automatically generate.



Is the Petshop example dependent on DataNucleus?

Most of the features of JDO that the Petshop example uses are required features in every JDO 1.0 compatible implementation. In one case, the Petshop example uses a JDO optional feature, nontransactional-read, which is implemented by DataNucleus and nearly every JDO implementation.

The coming JDO 2.0 standard will likely include better support for specifying the object-to-relational mapping in the JDO metadata. The DataNucleus 1.1.x line of releases is currently a preview version for the coming JDO 2.0 standard as expressed in the early release draft. For the moment, the JDO metadata for the Petshop is definitely tied to the DataNucleus 1.1.x line, but it is anticipated that this metadata will become standard JDO 2.0 metadata with little change. As it stands now, the Petshop metadata file does not use any extension tags, which are the tags that allow the use of vendor specific features in the metadata.

The Petshop example also uses the expected JDO 2.0 support for the toLowerCase method in JDOQL (JDO’s query language).

In short, the VLib example as written will work only with DataNucleus 1.1.x. It will evolve, as the JDO 2.0 standard and as work on DataNucleus 1.1.x continues, to become dependent only on JDO 2.0.



Does the Petshop example follow the design choices recommended in the tutorial for the VLib example?

In the tutorial for the VLib example, another example of a Tapestry Web application that uses DataNucleus, I identified several design choices and described why I thought they were good choices. Did I follow those recommendations in this example? The following checklist provides the rundown.

  • One persistence manager per HTTP request

    Yes. I really think this rule is hard and fast. You won't catch me breaking it anytime soon.

  • Encapsulate the transactions within the lifetime of the application service that calls JDO

    Yes. In JDO 1.0 this rule is a corollary of the first rule above.

    In JDO 2.0, the Web application may break this rule by using the support for extended optimistic transactions (EOTS) that comes with the detach/attach API. The Petshop example does not have a great need for EOTS, since by its nature it is a mostly-read and write-and-forget application.

  • Divide the model into service and data classes

    Yes. Also added shopping cart classes to the model in a separate package. In a real world application these would likely also be persistent classes, but in this example, the cart exists only in the servlet session space.

  • Use values objects in the controller and presentation code

    Yes. This design choice is excellent for separating the areas of concern. As in the VLib example, I use unmanaged data objects for the value objects. This example does not yet use the detach/attach API. It is still using the homegrown make-a-clone value object pattern that was used in VLib. This pattern works with JDO 1.0. As JDO 2.0 becomes more defined, the example will evolve to use the detach/attach API.

  • Encapsulate mutations of relations in the service methods

    Not applicable. This application does not change any relationships between the persistent objects. It does write out orders and line items, but its job in this regard is to write and forget. If the shopping cart were persistent, then persistent relationships would be modified as items are added and removed from the cart.

  • Define an interface for the value objects

    Yes. The original Petshop example already had these. Their use was retained.

  • Encapsulate JDO transactions within the service methods when possible

    Yes. Another code simplifying design choice.

  • Use extended optimistic transactions (EOTS) to guarantee that objects when changed are consistent with their viewed state.

    Not applicable. This is a read-mostly application. The writes are write-and-forget.



Good news for management

My primary motivation in doing this port was to demonstrate the advantages of using JDO when compared directly to coding the DAO pattern with the use of JDBC.

The Data Access Object (DAO) design pattern provides an adapter between plain, old, Java objects (POJOs) and various databases that can be accessed using JDBC. In essence, the DAO pattern requires that you write the persistence layer for your data classes, and it gives you guidance on how to go about it. By writing DAO code, you expend business resources to create the infrastructure for your application. Expending development resources on coding the DAO pattern is common and not inconsequential.

The following table shows the impact on the Petshop example of switching from the code that implements the DAO pattern with JDBC to the code that uses JDO. Table 1-1 compares original DAO version of Petshop to the new JDO version of Petshop based on two metrics. The SLOC metric is the count of the source lines of code. This count does not include blank lines or comment lines. The CC metric is the count of classes, including interfaces. The Petshop application is broken down into two sections, the model and the controller. Since the view is HTML templates and XML files, it is not included in the analysis of Java code. The view was nearly unchanged by the port.

Table 1-1: Metrics comparing the use of DAO to JDO

DAO JDO Delta
SLOC CC SLOC CC SLOC CC
Model 2773 60 1646 34 -41% -43%
Controller 2156 36 2156 36 0 0
Both 4929 96 3802 70 -23% -27%

As the table shows, the port had no impact on the controller code by these metrics. On the other hand, the impact on the model is dramatic. The amount of model code is reduced by over forty percent. Less code written means less time creating it, less time debugging it, less time testing it, and less time maintaining it. Overall, the amount of Java code for the entire application is reduced by approximately twenty-five percent. Most managers will find it hard to ignore numbers like these.

If you believe as I do, that it is easier to learn to use JDO than to learn to code the DAO pattern with JDBC, and if you believe, as I do, that using a JDO implementation will lead to a more robust and a better performing persistence layer than having your best developers create it from scratch, then the reduction in code coupled with these advantages creates a compelling argument for using JDO in your next development project.