The javax.jdo package contains all the interfaces you should use:
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 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.
The PersistenceManagerFactory is responsible for configuring and creating PersistenceManager instances. It represents the particular JDO implementation you are using; it has methods to determine the properties and optional features the implemention supports. PersistenceManagerFactory also provides methods to control property values used to establish a datastore connection and affect the configuration of the runtime environment in which the PersistenceManager instances run; these methods are covered in Chapter 7.
JDOHelper is a class that provides several static utility methods. As shown in Chapter 1, it is used to construct a PersistenceManagerFactory instance from a Properties object. It also provides methods to interrogate the lifecycle state of instances (covered in Chapter 11).
The Transaction interface provides methods to manage the demarcation (begin and commit/rollback) of transactions. Chapter 7 covers these methods in detail. Each PersistenceManager instance has one associated Transaction instance, accessible via currentTransaction( ). Transaction also has methods for controlling the values of transaction options.
The Extent interface is used to access all the instances of a class (and, potentially, its subclasses). You acquire an Extent by calling the getExtent( ) method of a PersistenceManager. You can either iterate over the Extent or use it to perform a query. Chapter 8 covers the Extent interface in detail.
You use the Query interface to perform queries. A Query instance has several components, and the interface provides methods to specify a value for each of them. The query evaluates a filter expressed in the JDO Query Language (JDOQL). Chapter 9 covers the Query interface in detail.
The InstanceCallbacks interface provides a means for you to specify some behavior to perform when specific lifecycle events occur in an instance of a persistent class. The interface defines methods that are called on an instance when it undergoes a lifecycle change. A persistent class must implement the InstanceCallbacks interface for these methods to be called. Chapter 12 and Chapter 13 cover this interface and its callback methods.
Figure 2-1 illustrates the relationships among the JDO interfaces and shows the method used to create or navigate to the related instance.
Some methods in the JDO interfaces are used to perform advanced operations. Some applications may use advanced JDO features, but a large percentage of the software in such applications will use only a small subset of JDO's methods. The following list of core JDO interfaces provide the majority, and, in many cases, all of the functionality necessary to use JDO:
We demonstrated the use of most of these methods in Chapter 1. The fact that this list of interfaces is so small is a major reason JDO is so easy to use.
Your persistent classes can have fields of the following standard Java types: byte, short, char, int, long, float, double, Byte, Short, Character, Integer, Long, Float, Double, BigInteger, BigDecimal, String, Date, Set, and HashSet. Your persistent classes can contain references to both persistent and transient classes. You can also define inheritance hierarchies and have references that refer to instances of subclasses. JDO directly supports the persistence of your Java object models, without requiring you to learn and use any new datatypes.
There are many opportunities for a component to fail that are not under the application's control. A JDO implementation is often built as a layer on an underlying datastore interface, which itself might use a layered protocol to another tier in a system's architecture. The source of an error may be caused by the application, the JDO implementation, or the underlying datastore on one or several tiers in an architecture.
JDO's exception philosophy is to treat all exceptions as runtime exceptions. This preserves the transparency of JDO's interface as much as possible, allowing you to choose which specific exceptions to catch based upon your application requirements.
JDO exceptions fall into several broad categories, each of which is treated separately:
Program errors that can be corrected and retried
Program errors that cannot be corrected, because the state of underlying components has been changed and cannot be undone
Logic errors internal to the JDO implementation, which should be reported to the vendor's technical support
Errors in the underlying datastore that can be corrected and retried
Errors in the underlying datastore that cannot be corrected, due to a failure of the datastore or the communication path to the datastore
JDO uses several interfaces external to the JDO API itself (e.g., the Collection interfaces). An exception that results from using one of these interfaces is used directly, without modification. If an exception occurs in the underlying datastore, the exception is wrapped inside a JDO exception. If your application causes a JDO exception, the exception contains the reason it was thrown.
Figure 2-2 illustrates the JDO exception inheritance hierarchy. The base exception class is called JDOException, and it extends RuntimeException. The classes that extend JDOException divide exceptions into those that are fatal and those that can be retried. The hierarchy is then extended based on the original source of the error. JDO exceptions are serializable.
This chapter provides complete coverage of the exception classes in the book. Let's examine each exception class:
JDOException is the base class for all JDO exceptions. Since it is a subclass of RuntimeException, JDO exceptions do not need to be declared or caught. The class includes a toString( ) method that returns a value indicating the nature of the exception. If the PersistenceManager is internationalized, the descriptive string is also internationalized.
If an exception is relative to a specific instance of one of your classes, you can call getFailedObject( ) to retrieve the instance. If the exception is caused by multiple instances, then each instance is wrapped in its own exception instance, and all of these exceptions are nested inside an exception that is thrown to the application. Such nested exceptions can occur as a result of multiple underlying exceptions or from an exception that involves multiple instances. You may have called a method that accepts a collection of instances, and multiple instances in the collection failed the operation. Or you may have called commit( ) in Transaction, which can fail on instances accessed during the transaction. In these cases, you can call getNestedExceptions( ) on the thrown exception to retrieve the array of nested exceptions. Each nested exception may have its own failed instance, returned by getFailedObject( ).
JDOException contains all of the functionality needed to access information about the exception. Its subclasses do not add any additional functionality to access information; they are used strictly to categorize the type of exception and provide a means for the application to catch and respond to an exception differently, based on its type and associated category.
This is the base class for exceptions that can be retried.
This is the base class for datastore exceptions that can be retried.
This is the base class for exceptions caused by your application that can be retried.
This exception is thrown if you attempt to use an optional JDO feature that the implementation does not support.
This exception occurs if an attempt is made to fetch an object that does not exist in the datastore.
This is the base class for exceptions that are fatal and cannot be retried. Usually, when this exception is thrown, the transaction has been rolled back and should be abandoned.
This is the base class for all failures within the JDO implementation itself. There is no action that can be taken to recover from this exception. You should report this exception to the JDO vendor for corrective action.
This is the base class for exceptions caused by your application that cannot be retried.
This is the base class for fatal datastore exceptions. When this exception is thrown, the transaction has been rolled back. The cause of the exception may be a connection timeout, an unrecoverable media error, an unrecoverable concurrency conflict, or some other cause outside of the application's control.
A verification step (which is described in Chapter 15) is performed on all instances that are new, modified, or deleted when you make a call to commit an optimistic transaction. If any instances fail this verification step, a JDOOptimisticVerificationException is thrown. It contains an array of nested exceptions; each nested exception contains an instance that failed verification. More details on optimistic transactions and the verification step can be found in Chapter 15.