Document version 0.91.
© 2004 David Ezzio. All rights reserved.
The Petshop example uses Tapestry and DataNucleus. 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 DataNucleus to the use
of the Data-Access-Object (DAO) design pattern. DataNucleus
provides a downloadable
sample with the code described here.
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.
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.)
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.
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.
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.
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.)
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.
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”.
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.
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.
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.
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.