You can make most of your classes persistent in a JDO environment.
JDO has the ability to make plain ordinary Java
objects (POJOs) persistent. This includes classes that
represent the entities in your application domain, utility classes that
model other data, and abstractions you need to support your
application’s functionality. Your classes can also use all of Java’s
class and field modifiers, including:
. In some cases, as we will explore later in this chapter,
some of these modifiers cannot be used with persistent fields.
The persistent state of a persistent class is represented entirely
by the values of its Java fields. If you have a class that has some
state that needs to be preserved and it depends on inaccessible or
remote objects (e.g., it extends
java.net.SocketImpl or uses Java Native Interface (JNI)), you cannot make the class
persistent. You also cannot have a persistent nonstatic inner class, because the state of the inner
class instance depends on the state of its enclosing instance.
With a few exceptions, system-defined classes (those defined in
java.net, etc.) cannot be persistent. They are
also not allowed to be the type of a persistent field. This includes
classes such as
Socket , and
File . We list the system classes that are supported in Table 4-2 later in this
chapter. You may be using an implementation that supports additional
system-defined classes, especially those for modeling state information.
Relying on support for these additional types will make your software
dependent on that implementation.
As discussed in Chapter 1, each persistent class needs to have a no-arg constructor. If your class does not define any constructors, the Java compiler generates a no-arg constructor automatically (called the default constructor). But if you do define one or more constructors with arguments in a persistent class, then you must also define a no-arg constructor manually.
When your application first accesses a persistent instance, the JDO implementation needs to construct an instance, so it calls the no-arg constructor. The availability of a no-arg constructor is the only requirement JDO imposes on your persistent classes. Some JDO enhancers can generate this no-arg constructor for you if it does not already exist, but they are not required to do so.
You may not want other classes in your application calling the
no-arg constructor. If this is the case, you can declare it to be
private. Or, if the class will have
subclasses, declare it to be
protected so that the subclass constructors
can call it.
Every class that you want to be persistent must be declared in a JDO metadata file. This file cannot include any system classes. Any class that is not declared in a metadata file is a transient class, except for the system classes that all implementations support. You typically place additional persistence-related information that is not expressable in Java in the metadata file. This metadata is used when a class is enhanced and also at runtime.
JDO metadata is stored in XML format. An XML Document Type Definition (DTD) defines the elements in a JDO metadata file. The JDO DTD is provided in Appendix B. It should be identical across all implementations.
You can place the metadata for your application’s classes in one or more XML files. A few rules exist for the naming and directory placement of metadata files to assure portability among implementations. For portability, metadata files should be available via resources loaded by the same class loader as the persistent classes.
If you have a metadata file that contains information for a package or multiple packages, then the name of the XML file should be package.jdo. (Here we literally mean the word “package,” not the name of an actual Java package.) The package.jdo file can be placed in one of the following directories:
In this case, package.jdo can contain metadata for any class in your application.
Files like package.jdo should be placed in this directory when deploying a JDO application in a web container.
- (no directory)
The package.jdo file is not in any subdirectory of the classpath.
The package.jdo file is placed in the subdirectory that corresponds to the package defined in the metadata. Thus, if package.jdo contains the metadata for the
com.mediamania.contentpackage, it would placed in the com/mediamania/content directory.
If you have a metadata file that only contains information for a single class named classname, then its filename should be classname.jdo and it should reside in the same directory as the class file, based on the package of the class.
When the JDO implementation needs metadata for a class and the metadata has not been loaded yet, the metadata is searched in the following order:
where <package> represents the directory corresponding to the package of the class and <class> represents the name of the class.
A search for the metadata for the
Customer class in the
com.mediamania.store package is performed
in the following order:
If no metadata is found for the
Customer class in any of these locations,
it is considered a transient class.
Once the metadata for a class has been loaded, it is not replaced. Metadata contained in a file higher in the search order is used instead of metadata lower in the search order. This search order is optimized so that implementations can cache metadata as soon as it is encountered, reducing the number of file accesses that are needed to load the metadata.
Metadata that is not in its natural location may override
metadata that is in its natural location. For example, when the JDO
implementation searches for the metadata for
com.mediamania.content.Movie, it may find
the metadata for the
com.mediamania.store.Rental class in the
file. In this case, a subsequent search for the metadata for
use the metadata that has already been cached, instead of looking in
These rules for the name and location of the metadata files apply both during enhancement and at runtime. From now on, the term “metadata” refers to the aggregate of all the JDO metadata for all packages and classes, regardless of their physical packaging in multiple files and directory placement.
jdo element is the
highest-level XML element in the metadata hierarchy. It does not
have any attributes of its own. It contains one or more nested
package elements. A
package element is
used to represent a specific Java package. It has a single required
contains the completely qualified name of the Java package.
you can nest one or more
class elements. A
class element identifies a
specific Java class in the enclosing package as persistent. The
class element’s only required
name, which is
given the name of the class. You should only list classes in the
metadata that you want to be persistent.
class element has the
following additional optional attributes:
attribute indicates which type of identity should be used with the
class. It defaults to datastore identity, which does not require any
additional effort from you. The
attribute identifies a class defined by the application to serve as
the application identity of the class. Chapter 10 covers the various
forms of identity in detail; until then, we will use datastore
identity in all of our examples. The
requires-extent attribute indicates
whether an extent is maintained for the class. Extents are covered
in Chapter 8. The
identifies the closest superclass in the inheritance hierarchy that
is persistent, if there is one.
specifies vendor-specific metadata extensions in a uniform manner.
All JDO metadata elements can have nested
extension elements. The required
attribute associates the extension with a specific vendor. Each
vendor uses a unique name to identify metadata extensions for their
implementation. The vendor name "
JDORI" is reserved for use with the JDO
reference implementation. A JDO implementation ignores any
extension elements that have a
vendor-name value that does not correspond
to their implementation. The
extension element also has optional
key may or may not have an
value. The vendor
chooses values for these attributes that they recognize and
interpret. Consult your documentation to see what metadata
extensions are provided.
The following illustrates the hierarchical nesting of metadata elements:
jdo package class field collection extension extension field map extension field array extension extension extension extension extension
One or more
elements can be nested within each of these elements (including
extension itself) to provide
vendor-specific information. The field metadata elements (
array) are covered later in this
Each class in an inheritance hierarchy can be transient or persistent, independent of the persistence of other classes in the hierarchy. Thus, a class can be persistent, even if its superclass is not. This allows you have a persistent class that extends a transient class that was not designed to be persistent. Likewise, a subclass of a persistent class may be transient or persistent.
If a persistent class has one or more persistent superclasses,
must identify the most immediate persistent superclass. If the
superclass is in a different package, it must be specified with its
fully qualified name. If the superclass is in the same package, you
can omit the package qualifier. You may wonder why you need to specify
this in the metadata. After all, the Java class declarations specify
the branch of superclasses from a class up to
Object in an inheritance hierarchy, and your
metadata identifies which of these classes are persistent. But the
metadata for a superclass may be specified in a different metadata
file. JDO is designed such that the enhancer can enhance a class in a
stateless fashion, independent from other classes. The order in which
classes are enhanced is irrelevant, and a class can be enhanced
without the presence of any other classes. This greatly supports the
simplicity of enhancer design, ease of use, integration with
classloaders, and—last, but not least—easy reproducability of
To illustrate these concepts, the UML diagram in Figure 4-1 describes two inheritance hierarchies. We use the stereotyping facility in UML to indicate whether a class is persistent or transient. In practice, you are not likely to have an inheritance hierarchy with such a complicated mix of persistent and transient classes. In many cases, the classes in an inheritance hierarchy are either all transient or all persistent. But JDO provides you with the flexibility to choose whether each class in an inheritance hierarchy is transient or persistent, as we have demonstrated here.
The following metadata identifies the persistent superclass for each persistent class shown in Figure 4-1. This metadata is placed in the com/mediamania/inheritexample/package.jdo file.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd"> <jdo> <package name="com.mediamania.inheritexample" > <class name="A" /> <class name="C" persistence-capable-superclass="A"/> <class name="E" persistence-capable-superclass="A"/> <class name="G" persistence-capable-superclass="C"/> <class name="H" persistence-capable-superclass="A"/> <class name="K" /> <class name="M" /> <class name="O" persistence-capable-superclass="K"/> </package> </jdo>
Let’s examine the object model we use in most of the examples
throughout this book. Media Mania, Inc. provides a system in their
stores that contains information about the various forms of media that
customers can rent or purchase. In Chapter 1 we created a prototype
application contained in
com.mediamania.prototype. Now, we replace
this prototype with two new packages:
Java package contains classes that represent generic media content
information. The content handled by the stores includes movies and
Game classes extend an abstract base class
Studio class contains information about the
studio that produced the game or movie. Figure 4-2 illustrates the
relationships among these classes.
Each person involved in a movie, as either the director or an
actor, is represented by an instance of
MediaPerson. Figure 4-3 illustrates the
Movie instance has one or
Role instances representing
the cast of the movie. It also has a reference to the
MediaPerson for the director of the movie.
We assume a movie has a single director (though in real life this is
not always the case). The
class references its
Movie and a
MediaPerson who served as the actor
for the particular role. Given a specific
MediaPerson instance, it is possible to
access all the movies they directed and all the roles they have played
in movies. This model also allows for an actor who has played multiple
roles in the same movie.
In addition to the media content information, each store tracks
the rental and purchase activities of its customers. The
com.mediamania.store package contains the
classes representing store-specific information. Figure 4-4 illustrates the
relationships among these classes.
Figure 4-4. Classes in the com.mediamania.store package (except MediaContent in the content package)
Each customer that has rented or purchased some media content at
the store is represented by an instance of the
Customer class. An
Address instance contains address
information for the customer. The store tracks two kinds of
transactions: rentals and purchases. These are represented by
Purchase classes that extend a
Transaction base class. The store tracks the
current items the customer has out for rent and also keeps a history
of all the customer’s transactions.
represents a particular format of a given
MediaContent item. For example, a
Movie can exist in VHS and DVD formats and a
Game may be supported in formats
for the Playstation, Playstation 2, Xbox, and Nintendo GameCube. The
stock of media items is designated as items to be sold or rented. A
RentalItem instance exists for each
individual item that can be rented to a customer. The items in stock
that are currently available for rent are represented by
RentalItem instances that have a
null value for their
currentRental field. The model does not
track the individual items that are sold, but the
MediaItem class tracks how many items for
purchase are in stock and how many have been sold year-to-date. Each
Purchase instance contains a
reference to the specific
that the customer bought.
The store has different rental policies and prices, based on the
popularity of an item and how recently it became available. A
RentalCode instance maintains information
about a particular rental policy. Each
MediaItem instance is associated with a
RentalCode, which may
change over time.
Rental instance represents
a customer’s rental of a particular media item; it references the
RentalItem rented. This is
necessary so the store can track which item has been rented and update
the customer account when it is returned, taking into account any late
fees that may be due. The
RentalCode associated with the
MediaItem at the time of rental is
associated with the
instance. This is necessary because the
RentalCode for a
MediaItem will change occasionally.
Appendix E provides all
the classes for the model. The following metadata specifies the
packages and persistent classes for the object model. Since it
contains metadata information for the
com.mediamania.store packages, we place the
metadata in a file named com/mediamania/package.jdo, based on their
common base package name.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN" "http://java.sun.com/dtd/jdo_1_0.dtd"> <jdo> <package name="com.mediamania.content" > <class name="Studio" > </class> <class name="MediaContent" /> <class name="Movie" persistence-capable-superclass="MediaContent"> </class> <class name="MediaPerson" > </class> <class name="Game" persistence-capable-superclass="MediaContent"> </class> <class name="Role" /> </package> <package name="com.mediamania.store" > <class name="MediaItem" > </class> <class name="RentalItem"/> <class name="Customer" > </class> <class name="Address" /> <class name="Transaction" /> <class name="Purchase" persistence-capable-superclass="Transaction"/> <class name="Rental" persistence-capable-superclass="Transaction"/> <class name="RentalCode" /> </package> </jdo>
The metadata lists each persistent class in the
store packages. If an inheritance
relationship exists, the metadata specifies the persistent superclass.
Later in this chapter, we will add more information that provides
information about the fields and relationships.