BUY THIS BOOK
Add to Cart

Print Book $39.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £28.50

What is this?

Looking to Reprint this content?


Java Data Objects
Java Data Objects

By David Jordan, Craig Russell
Price: $39.95 USD
£28.50 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: An Initial Tour
Java is a language that defines a runtime environment in which user-defined classes execute. Instances of these user-defined classes may represent real-world data that is stored in a database, filesystem, or mainframe transaction processing system. Additionally, small-footprint environments often require a means of managing persistent data in local storage.
Because data-access techniques are different for each type of data source, accessing the data presents a challenge to application developers, who need to use a different application programming interface (API) for each type of data source. This means that you need to know at least two languages to develop business logic for these data sources: the Java programming language and the specialized data-access language required by the data source. The data-access language is likely to be different for each data source, driving up the costs to learn and use each data source.
Prior to the release of Java Data Objects (JDO), three standards existed for storing Java data: serialization, Java DataBase Connectivity (JDBC), and Enterprise JavaBeans (EJB) Container Managed Persistence (CMP). Serialization is used to write the state of an object, and the graph of objects it references, to an output stream. It preserves the relationships of Java objects such that the complete graph can be reconstructed at a later point in time. But serialization does not support transactions, queries, or the sharing of data among multiple users. It allows access only at the granularity of the original serialization and becomes cumbersome when the application needs to manage multiple serializations. Serialization is only used for persistence in the simplest of applications or in embedded environments that cannot support a database effectively.
JDBC requires you to manage the values of fields explicitly and map them into relational database tables. The developer is forced to deal with two very different data-model, language, and data-access paradigms: Java and SQL's relational data model. The development effort to implement your own mapping between the relational data model and your Java object model is so great that most developers never define an object model for their data; they simply write procedural Java code to manipulate the tables of the underlying relational database. The end result is that they are not benefiting from the advantages of object-oriented development.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Defining a Persistent Object Model
Figure 1-1 is a Unified Modeling Language (UML) diagram of the classes and interrelationships in the Media Mania object model. A Movie instance represents a particular movie. Each actor who has played a role in at least one movie is represented by an instance of Actor. The Role class represents the specific roles an actor has played in a movie and thus represents a relationship between Movie and Actor that includes an attribute (the name of the role). Each movie has one or more roles. An actor may have played a role in more than one movie or may have played multiple roles in a single movie.
Figure 1-1: UML diagram of the Media Mania object model
We will place these persistent classes and the application programs used to manage their instances in the Java com.mediamania.prototype package.
We will make the Movie, Actor, and Role classes persistent, so their instances can be stored in a datastore. First we will examine the complete source code for each of these classes. An import statement is included for each class, so it is clear which package contains each class used in the example.
Example 1-1 provides the source code for the Movie class. JDO is defined in the javax.jdo package. Notice that the class does not require you to import any JDO-specific classes. Java references and collections defined in the java.util package are used to represent the relationships between our classes, which is the standard practice used by most Java applications.
The fields of the Movie class use standard Java types such as String, Date, and int. You can declare fields to be private; it is not necessary to define a public get and set method for each field. The Movie class includes some methods to get and set the private fields in the class, though those methods are used by other parts of the application and are not required by JDO. You can use encapsulation, providing only the methods that support the abstraction being modeled. The class also has static fields; these are not stored in the datastore.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Project Build Environment
In this section, we examine a development environment to compile and run our JDO application. This includes the project directory structure, the jar files necessary to build applications, and the syntax for enhancing persistent classes. We describe class enhancement later in this section. The environment setup partly depends on which JDO implementation you use. Your specific project's development environment and directory structure may differ.
You can use either the Sun JDO reference implementation or another implementation of your choosing. The examples in this book use the JDO reference implementation. You can download the JDO reference implementation by visiting http://www.jcp.org and selecting JSR-12. Once you have installed a JDO implementation, you will need to establish a project directory structure and define a classpath that includes all the directories and jar files necessary to build and run your application.
JDO introduces a new step in your build process, called class enhancement. Each persistent class must be enhanced so that it can be used in a JDO runtime environment. Your persistent classes are compiled using a Java compiler that produces a class file. An enhancer program reads these class files and JDO metadata and creates new class files that have been enhanced to operate in a JDO environment. Your JDO application should load these enhanced class files. The JDO reference implementation includes an enhancer called the reference enhancer.
When using the JDO reference implementation, you should include the following jar files in your classpath during development. At runtime, all of these jar files should be in your classpath.
jdo.jar
The standard interfaces and classes defined in the JDO specification.
jdori.jar
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Establish a Datastore Connection and Transaction
Now that our classes have been enhanced, their instances can be stored in a datastore. We now examine how an application establishes a connection with a datastore and executes operations within a transaction. We begin to write software that makes direct use of the JDO interfaces. All JDO interfaces used by an application are defined in the javax.jdo package.
JDO has an interface called PersistenceManager that has a connection with a datastore. A PersistenceManager has an associated instance of the JDO Transaction interface used to control the start and completion of a transaction. The Transaction instance is acquired by calling currentTransaction( ) on the PersistenceManager instance.
A PersistenceManagerFactory is used to configure and acquire a PersistenceManager. Methods in the PersistenceManagerFactory are used to set properties that control the behavior of the PersistenceManager instances acquired from the factory. Therefore, the first step performed by a JDO application is the acquisition of a PersistenceManagerFactory instance. To get this instance, call the following static method of the JDOHelper class:
static PersistenceManagerFactory getPersistenceManagerFactory(Properties props);
The Properties instance can be populated programmatically or by loading property values from a property file. Example 1-6 lists the contents of the property file we will use in our Media Mania application. The PersistenceManagerFactoryClass property on line [1] specifies which JDO implementation we are using by providing the name of the implementation's class that implements the PersistenceManagerFactory interface. In this case, we specify the class defined in Sun's JDO reference implementation. Other properties listed in Example 1-6 include the connection URL used to connect to a particular datastore and a username and password, which may be necessary to establish a connection to the datastore
Example 1-6.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Operations on Instances
Now we have a datastore in which we can store instances of our classes. Each application needs to acquire a PersistenceManager to access and update the datastore. Example 1-8 provides the source for the MediaManiaApp class, which serves as the base class for each application in this book. Each application is a concrete subclass of MediaManiaApp that implements its application logic in the execute( ) method.
MediaManiaApp has a constructor that loads the properties from jdo.properties (line [1]). After loading properties from the file, it calls getPropertyOverrides( ) and merges the returned properties into jdoproperties. An application subclass can redefine getPropertyOverrides( ) to provide any additional properties or change properties that are set in the jdo.properties file. The constructor gets a PersistenceManagerFactory (line [2]) and then acquires a PersistenceManager (line [3]). We also provide the getPersistenceManager( ) method to access the PersistenceManager from outside the MediaManiaApp class. The Transaction associated with the PersistenceManager is acquired on line [4].
The application subclasses make a call to executeTransaction( ), defined in the MediaManiaApp class. This method begins a transaction on line [5]. It then calls execute( ) on line [6], which will execute the subclass-specific functionality.
We chose this particular design for application classes to simplify and reduce the amount of redundant code in the examples for establishing an environment to run. This is not required in JDO; you can choose an approach that is best suited for your application environment.
After the return from the execute( ) method (implemented by a subclass), an attempt is made to commit the transaction (line [7]). If any exceptions are thrown, the transaction is rolled back and the exception is printed to the error stream.
Example 1-8. MediaManiaApp base class
package com.mediamania;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import java.util.Map;
import java.util.HashMap;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.PersistenceManager;
import javax.jdo.Transaction;

public abstract class MediaManiaApp {
    protected PersistenceManagerFactory pmf;
    protected PersistenceManager        pm;
    protected Transaction               tx;
    
    public abstract void execute(  );  // defined in concrete application subclasses

    protected static Map getPropertyOverrides(  ) {
        return new HashMap(  );
    }
    public MediaManiaApp(  ) {
        try {
            InputStream propertyStream = new FileInputStream("jdo.properties");
            Properties jdoproperties = new Properties(  );
            jdoproperties.load(propertyStream);     
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Summary
As you can see, a large portion of an application can be written in a completely JDO-independent manner using conventional Java modeling, syntax, and programming techniques. You can define your application's persistent information model solely in terms of a Java object model. Once you access instances from the datastore via an extent or query, your software looks no different from any other Java software that accesses instances in memory. You do not need to learn any other data model or access language like SQL. You do not need to figure out how to provide a mapping of your data between a database representation and an in-memory object representation. You can fully exploit the object-oriented capabilities of Java without any limitation. This includes use of inheritance and polymorphism, which are not possible using technologies like JDBC and the Enterprise JavaBeans (EJB) architecture. In addition, you can develop an application using an object model with much less software than when using competitive architectures. Plain, ordinary Java objects can be stored in a datastore and accessed in a transparent manner. JDO provides a very easy-to-learn and productive environment to build Java applications that manage persistent data.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: An Overview of JDO Interfaces
JDO's interfaces are defined in two packages: javax.jdo and javax.jdo.spi . You use the interfaces defined in the javax.jdo package to write your applications. This chapter introduces and describes each of these interfaces at a high level. Each method defined in these interfaces is covered thoroughly in this book. You can use the index to find information on a particular method.
The javax.jdo.spi package contains interfaces that JDO implementations use (spi stands for service provider interface). It is a common practice to have such a package that defines interfaces for use by the implementation of a Java API, distinct from the package that contains the interfaces for use of the API. You should not directly use any of the interfaces defined in javax.jdo.spi. We provide brief coverage of a few of the javax.jdo.spi interfaces that are directly involved in the management of persistent class instances. If you are interested in a thorough understanding of the interfaces in javax.jdo.spi, we encourage you to read the JDO specification.
We conclude this chapter by enumerating the optional features in JDO.
The javax.jdo package contains all the interfaces you should use:
  • PersistenceManager
  • PersistenceManagerFactory
  • Transaction
  • Extent
  • Query
  • InstanceCallbacks
It also contains the JDOHelper class and a set of exception classes.
This is the complete set of JDO application interfaces! JDO has a relatively small API, allowing you to learn it quickly and become productive applying it. JDO uses your Java classes as the data model for representing and managing data, which is major contributing factor in its simplicity and ease of use.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The javax.jdo Package
The javax.jdo package contains all the interfaces you should use:
  • PersistenceManager
  • PersistenceManagerFactory
  • Transaction
  • Extent
  • Query
  • InstanceCallbacks
It also contains the JDOHelper class and a set of exception classes.
This is the complete set of JDO application interfaces! JDO has a relatively small API, allowing you to learn it quickly and become productive applying it. JDO uses your Java classes as the data model for representing and managing data, which is major contributing factor in its simplicity and ease of use.
Every method in each of these interfaces is described somewhere in this book. We introduce basic JDO concepts first and gradually progress to more advanced topics. Semantically related methods are often covered in the same section, but coverage of the methods for a particular interface is usually dispersed throughout the text. Appendix C provides the signature for every method in each interface. The index provides a reference to each place in the book where a method is covered. Here's a brief description of each interface in the package:
PersistenceManager
PersistenceManager is your primary interface when using JDO. It provides methods to create query and transaction objects, and it manages the lifecycle of persistent instances. Each chapter introduces a few PersistenceManager methods. The interface is used for the basic and advanced features in JDO.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The javax.jdo.spi Package
The javax.jdo.spi package defines interfaces used by JDO implementations. Your application should not use the interfaces in this package. However, a few interfaces in this package are useful for you to be aware of, as they are directly responsible for managing the state of persistent instances.
PersistenceCapable
The PersistenceCapable interface allows an implementation to manage the values of fields and the lifecycle state of persistent instances. Every instance managed by a PersistenceManager needs to be of a class that implements PersistenceCapable. When you enhance a persistent class, code is added to the class to implement the PersistenceCapable interface.
You should not directly use the PersistenceCapable methods added by the enhancer. Some of its methods provide information useful to your application; these methods are made accessible to you through the JDOHelper and PersistenceManager interfaces.
StateManager
Every persistent and transactional instance has a reference to a StateManager instance. (Chapter 13 covers transactional instances.) A StateManager interfaces with the PersistenceManager and is responsible for managing the values of fields and state transitions of an instance. (Chapter 11 covers state transitions.)
JDOPermission
The JDOPermission class is used to grant the JDO implementation permission to perform privileged operations if you have a Java security manager in your Java runtime environment. JDOPermission extends java.security.BasicPermission. The following permissions are defined:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Optional Features
JDO defines some features that are optional; JDO-compliant implementations are not required to implement them. Each optional feature is identified by a unique name, which includes a javax.jdo.option prefix. You can call the supportedOptions( ) method, defined in PersistenceManagerFactory, to determine which options an implementation supports; it returns a Collection of Strings that contain an option string. Chapter 7 presents an example using this method. Here we enumerate all the optional features and their names.
The optional features can be grouped into the following categories:
  • Identity options
  • Optional collections
  • Transaction-related optional features
Each instance managed in a JDO environment must have a unique identifier. The following options are associated with identity:
  • javax.jdo.option.ApplicationIdentity
  • javax.jdo.option.DatastoreIdentity
  • javax.jdo.option.NonDurableIdentity
  • javax.jdo.option.ChangeApplicationIdentity
The first three options represent different kinds of identity. The fourth option indicates whether you can change the value of the fields that represent the application identity of an instance.
Support for each form of identity is optional. However, an implementation must support either datastore or application identity, and may support both. In Chapter 1 we used datastore identity, which is supported by all of the current JDO implementations. Until we cover identity in depth in Chapter 10, all of our examples will use datastore identity.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: JDO Architectures
One of JDO's primary objectives is to provide you with a transparent, Java-centric view of persistent information stored in a wide variety of datastores. You can use the Java programming model to represent the data in your application domain and transparently retrieve and store this data from various systems, without needing to learn a new data-access language for each type of datastore. The JDO implementation provides the necessary mapping from your Java objects to the special datatypes and relationships of the underlying datastore. Chapter 4 discusses Java modeling capabilities you can use in your applications. This chapter provides a high-level overview of the architectural aspects of JDO, as well as examples of environments in which JDO can be used. We cannot enumerate all such environments in this book, because JDO is capable of running in a wide variety of architectures.
A JDO implementation is a collection of classes that implement the interfaces defined in the JDO specification. The implementation may be provided by an Enterprise Information System (EIS) vendor or a third-party vendor; in this context, we refer to both as JDO vendors. A JDO implementation provided by an EIS vendor will most likely be optimized for the specific EIS.
The JDO architecture simplifies the development of scalable, secure, and transactional JDO implementations that support the JDO interface. You can access a wide variety of storage solutions that have radically different architectures and data models, but you can use a single, consistent, Java-centric view of the information from all the datastores.
The JDO architecture can be used to access and manage data contained in local storage systems and heterogeneous EISs, such as enterprise resource planning (ERP) systems, mainframe transaction processing systems, and database systems. JDO was designed to be suitable for a wide range of uses, from embedded small-footprint systems to large-scale enterprise application servers. A JDO implementation may provide an object-relational mapping tool that supports a broad array of relational databases. JDO vendors can build implementations directly on the filesystem or as a layer on top of a protocol stack with multiple components.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Architecture Within Application JVM
JDO supports a variety of architectures within the application's JVM context. Your application can have one or multiple PersistenceManagers accessing the same or different datastores concurrently. Each PersistenceManager has its own persistent instance cache and its own associated Transaction instance, which manages a distinct transactional context. A JDO implementation may also maintain a shared cache of instances (not visible to applications) to optimize the application's access of data in the datastore.
The simplest JDO application architecture has a single PersistenceManager, as illustrated in Figure 3-1. A PersistenceManager is the primary interface used by the application to access persistent services. It is an interface that is implemented by an instance of the JDO implementation. The persistent instances are managed in a cache, where they are used directly by the application. The JDO implementation manages the persistent instances both by using application control (e.g., using PersistenceManager and Query methods), and transparently (when the application accesses a field that is not loaded). The cache contains other artifacts, used to track the identity and state of the instances, but these artifacts are not visible to the application. Whenever we mention the cache, we are referring to the cache of persistent instances.
Figure 3-1: Application using a single PersistenceManager to access a datastore
The application cache is not a specific region of memory, as Figure 3-1 might imply; it is simply part of the JVM's object heap. Each persistent class has a field, named jdoStateManager , added by the enhancer to reference a StateManager . The StateManager manages the field values and lifecycle state of the instance, and has a reference to its associated PersistenceManager. A PersistenceManager may use one or more StateManager
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Datastore Access
We have explored the architecture in the application's JVM and discussed the application cache and implementation cache. Now let's examine the architectures of JDO implementations. We'll discuss each type of datastore separately.
These architectures don't affect your application's programming model, but they affect the configuration of the environment in which your application executes. In particular, the ConnectionURL property of the Properties instance used to construct the PersistenceManagerFactory refers to a local or remote datastore.
Some JDO implementations store the objects directly in a local filesystem or datastore. Figure 3-1 illustrates this architecture. There is only a single process context in this architecture. The JDO implementation uses the Java I/O classes directly to manage the storage of the objects in a file. The JDO Reference Implementation implements this architecture, as do some object databases.
Some JDO implementations connect to a separate server that manages the datastore, as illustrated in Figure 3-7. The JDO Reference Implementation implements this architecture, as do most object databases. In this particular example, the JDO implementation itself provides a server built specifically for object storage, which then manages the filesystem directly. The component that executes in the same JVM as the JDO implementation and communicates with the remote server is called a resource adapter . The protocols between the client JVM and the JDO Server are vendor-specific.
Figure 3-7: Client access of a JDO server
Figure 3-8 illustrates the use of a relational database server for object storage. This is the most common architecture used by current commercial JDO implementations. Since the application is written in Java, the JDO implementation uses JDBC to communicate with the database server. When you deploy your application, you use a proprietary tool supplied by the JDO vendor to map your application's Java objects to tables in the relational database. Some JDO implementations use your application's persistent object model to create the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
System Architectures with a JDO Application
Now we'll examine where JDO objects and application logic can be placed relative to an application's overall system architecture, including both managed and nonmanaged environments. In the remaining examples in this chapter, we don't show the details of how the JDO implementation manages the storage for the persistent instances.
The simplest form of system architecture is a one- or two-tier application that may be executed from the command line, from a shell script, or via a graphical user interface. We refer to the application as a rich client to distinguish it from a browser that simply displays HTML and executes applets. The application uses local filesystem and JDO persistent services directly.
Figure 3-9 illustrates how an application can use JDO to provide persistent services to the implementation of a web servlet or JavaServer Pages (JSP). When using JSP pages, the application typically will use JDO in one of two ways: by calling JDO's APIs directly in Java, or using a JSP tag library to abstract the JDO API (similar to the way the JSP Standard Tag Library abstracts the JDBC API).
Figure 3-9: JDO application running in a web server
With this architecture, the servlet/JSP page gets data from the browser in the form of strings from an HTTP doGet( ) or doPost( ) request and uses JDO to implement the request. Your application may use the Struts framework to implement the servlets and JSP pages in this architecture. We will discuss the web-server access patterns in detail in Chapter 16.
Figure 3-9 also illustrates the use of JDO as the persistence implementation for a web server implementation of a web services endpoint. The web server may register the service using UDDI and a registry service, and clients may find the service via the same registry.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Defining Persistent Classes
A Java program consists of many different kinds of classes, including:
  • Classes that model business objects
  • Classes that serve as user interface objects
  • Classes that provide various kinds of glue between different parts of the application
  • System classes of various sorts
JDO focuses on the classes whose data has a corresponding representation in the underlying datastore: classes that represent business objects or classes that represent application-specific data that must remain persistent between application invocations.
These classes may represent data that comes from a single entity in the datastore, or they may represent data from several entities; JDO doesn't place any limitations on where the data comes from. For example, the data may come from:
  • A single object in an object-oriented database
  • A single row of a relational database
  • The result of a relational database query, consisting of several rows
  • The merging of several tables in a relational database
  • The execution of a method from a data retrieval API that accesses an Enterprise Resource Planning (ERP) system
A JDO implementation maps data from its representation in the datastore to its representation in memory as a Java object, and vice versa. The mapping is based on metadata, which must be available both when the Java class is enhanced and at runtime. JDO does not standardize the mapping to a specific datastore.
First, we must define some terms and provide some distinctions that are essential for understanding JDO. The term "object" often refers to either a class or an instance of a class, which can be confusing sometimes. Therefore, we will use the terms "instance" and "class" instead of "object," because it will be essential for you to understand which we are discussing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Kinds of Classes and Instances
First, we must define some terms and provide some distinctions that are essential for understanding JDO. The term "object" often refers to either a class or an instance of a class, which can be confusing sometimes. Therefore, we will use the terms "instance" and "class" instead of "object," because it will be essential for you to understand which we are discussing.
When using JDO, every class falls into one of the following two categories:
Persistent class
A persistent class can have its instances stored in the datastore. To be persistent, a class must be specified in a metadata file and enhanced. The JDO specification refers to these as persistence-capable classes.
Transient class
A transient class cannot have its instances stored in the datastore. Transient classes are not listed in a metadata file.
Furthermore, classes can be distinguished by their use of the JDO API:
JDO-aware class
A JDO-aware class makes direct use of the JDO API. For example, it can perform a JDO query to retrieve instances from the datastore, or make specific instances persistent.
JDO-transparent class
A JDO-transparent class does not make direct use of the JDO API.
Whether a class is JDO-aware or JDO-transparent is unrelated to whether it is persistent. For example, the persistent classes Movie, Actor, and Role that we introduced in Chapter 1 are JDO-transparent, because they never made an explicit call to the JDO API. On the other hand, the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Java Classes and Metadata
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: private , public , protected , static , transient , abstract , final , synchronized , and volatile . 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.lang, java.io, java.net, etc.) cannot be persistent. They are also not allowed to be the type of a persistent field. This includes classes such as System , Thread , 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
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Fields
Fields contain the state of an instance. JDO provides for the access, management, and storage of an instance's fields in a datastore. All of Java's field type categories are supported: primitive types, reference types, and interface types. JDO also supports all of Java's field modifiers, including private , public , protected , static , transient , final , and volatile . But static and final fields cannot be persistent, as we will discuss later in this chapter.
As we explained earlier, you can have both transient and persistent instances of a persistent class. The individual fields of a persistent class can also be transient or persistent for all of the class's persistent instances. A field's type and modifiers determine whether it is persistent or transient, by default. You can override the default persistence of a field in the metadata. We cover transient fields later in this chapter.
You can specify persistence-related information about a field by using the field metadata element. Its required name attribute should have the name of the field in the Java class declaration. It has attributes to control the field's persistence and the type of its elements if it is a collection. We cover these attributes later in this chapter. If the class uses application identity, one or more fields need to indicate they are a primary-key field; Chapter 10 covers this in detail. Chapter 12 addresses advanced field-management facilities enabled by the remaining field element attributes.
You do not need to provide metadata for every field in a class. Default values are assumed for any fields that lack metadata declarations. These default values usually provide the behavior that you need. So, in many circumstances, you do not need to provide field metadata.
You cannot make many system-defined classes persistent, nor can you have a field of a system-defined class. Table 4-2 lists the system-defined types in the Java language environment that JDO implementations do support.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Datastore Mappings
JDO supports the storage of your object model in a variety of datastore architectures. The primary datastore architectures envisioned for use with JDO are:
Relational database
Organized as a set of tables, each containing a set of rows and columns. A column can store values of a particular atomic type. Each table cell in a particular row and column stores a value of the column's type. The value stored can be a null value. Instances are identified uniquely by the value of primary-key columns. Relationships are defined, and may be enforced, by annotating specific columns as foreign keys that reference columns in a table.
Pure object database
An extension of the JVM object model. Domain objects are stored with their primitive fields, just as instances are stored in the JVM. Instances are identified by a system-generated unique identifier. References are stored as objects, including instances of system-defined classes. Unreferenced instances are garbage collected. An extent is not an intrinsic construct in a pure object database; it is implemented as a class containing a set of objects. In this model, any reference type can be shared among multiple objects, and changes made to the instance of the reference type are visible to all objects that reference it.
Hybrid object database
Organized as a set of class extents, each containing a set of instances in which primitive and complex fields are stored. Domain objects are stored with their primitive fields; some complex field types (e.g., collections of primitive types and reference types) are also stored with the domain object. Instances are identified by a system-generated unique identifier. Unreferenced instances must be deleted explicitly.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Mapping Approaches
Several approaches can be used to establish a mapping between your persistent Java classes and a relational schema:
Generate a relational schema from your persistent Java classes
If you are developing a new application in Java and you do not have an existing relational database schema, you can let the JDO implementation generate a relational schema from your object model. This approach is commonly called forward engineering the model. This approach yields a high level of development productivity because all of the schema design and mapping work is done automatically by the JDO implementation. The JDO specification does not require support for the automatic generation of a schema. Some implementations do not support this approach and require you to define the mapping to an existing schema. Many of the implementations that do support schema generation let you specify some metadata to help direct the algorithms generating the schema.
Generate your persistent Java classes from a relational schema
In many cases, you may already be using a relational database schema and you would like to write a new application with an object view of the data. In this scenario, many implementations provide tools you can use that analyze your relational schema and generate a Java object model for you. This approach lets you develop an object-oriented Java application quickly. It is commonly called reverse-engineering the model.
Define a mapping between Java classes and a relational schema
You may have an existing relational schema and a separately designed object model and you would like to define a mapping between the two. In this case, you can use metadata directives to define how a class and its fields should be mapped to the underlying datastore. This approach is commonly called a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Relational Modeling Constructs
Before we discuss the mapping between Java classes and a relational schema, we will first provide a brief summary of the modeling constructs found in relational schemas. This is not meant to cover all aspects of a relational schema; it will simply define the terms we use in this chapter.
A relational schema is organized as a set of tables. A table is usually defined for each entity in the application domain you are modeling. When you design an object model, an entity is represented by a class. Each table consists of rows and columns. A row contains the data for a specific instance of an entity being modeled. A column contains the values for one of the attributes of the entity. A table cell is the intersection of a particular row and column in the table, and it contains the value of an attribute for a specific entity instance.
The type of a column is the same for all rows of a table. Relational databases do not support Java's capability for a field to reference one of many different types. ANSI SQL 92 defines a standard set of supported column datatypes. Relational database products support these standard datatypes and usually support their own additional, proprietary datatypes. One issue developers often contend with is the use of a datatype that is specific to one database product but not supported by another. JDO helps insulate your applications from these datatype differences, since you only deal with Java types, which are then mapped to the various underlying datastore types.
Often, one or more columns are defined as the table's primary key to identify a row uniquely. A table can have only one primary-key constraint. The primary-key constraint requires that the columns have a unique value for each row, and the primary-key columns cannot contain a null value.
One or more columns in a table may be defined as a foreign-key constraint, which is used to enforce referential integrity in the datastore. A row's foreign-key columns contain the same values as columns in a specific row of the referenced table.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Modeling Constructs in Java and Relational Models
The Java object model and the relational data model are two separate and distinct data models with separate type systems and approaches for representing data and expression computations. Table 5-1 summarizes the typical data-specific mappings that are specified between an object model and a relational schema.
Table 5-1: Mapping between object models and relational schemas
Java modeling construct
Relational modeling construct
Class
Table
Field
Column
Instance
Row
Identity
Primary key
Reference
Foreign key
Interface
No relational equivalent
Collection
No relational equivalent
Class inheritance
One or multiple tables
Collections in JDO can be represented only as memory instances, with no direct representation as a collection in the datastore. They are instantiated on demand and discarded when they are no longer needed. There are exceptions to these general rules, and some implementations support more advanced mappings. This chapter examines several ways of representing a Java collection in a relational datastore.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Mapping Classes to Tables
If your object model does not use inheritance, you usually have a separate relational table for each class. We cover the mapping of classes in an inheritance hierarchy later in this chapter. To establish a mapping from a Java class to a specific table, in most JDO implementations you specify the mapping in your JDO metadata with an extension element nested within the class element. For example, the following example illustrates the metadata necessary to map the MediaItem class to a table called Items:
<class name="MediaItem" >
    <field name="rentalItems">
        <collection 
element-type="RentalItem"/>
    </field>
    <extension 
vendor-name="vendorX" key="table" value="Items" />
    <extension vendor-name="vendorY" key="sqlname" value="Items" />
</class>
You identify the implementation you are using in the vendor-name attribute. As we mentioned previously, the datastore mappings in JDO 1.0.1 are implementation-specific. This may be standardized in JDO 2.0. Each JDO vendor provides documentation explaining which value to use for the vendor-name attribute and which values are supported for the key attribute.
In the previous code, we provided the metadata for two vendors, identified as vendorX and vendorY. An implementation will use only metadata extensions that it recognizes. This allows you to place the metadata for multiple vendors in the same JDO metadata file. vendorX uses a value of "table" for the key attribute to indicate which relational table the MediaItem class should be mapped to, and vendorY uses the value "sqlname". You should check the implementation's documentation to see which values they require. We provide the name of the table (Items) in the relational schema in the value attribute. If you were to port your application to another JDO implementation, you would need to add an extension element that has values in the vendor-name and key attributes that are appropriate for that implementation. However, your Java class would not have to change.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Mapping a Single-Valued Field to a Column
A primitive or single-valued Java field usually is mapped to a single column of a table. Some implementations allow a field to be mapped to multiple columns, but such a feature is not supported by most implementations or needed in most applications. When mapping a Java field to a relational column, you need to consider the name and the type to be used for the associated column. The types are always different, since Java and SQL have their own distinct type systems. The name of the field and column can be either the same or different.
When you're mapping a field in Java to a relational column, you can use different names. In some cases, you may have to