Chapter 7: Helpers, Callbacks, and Exceptions


This chapter examines the JDOHelper class, the InstanceCallbacks interface, and the exception classes of JDO. The JDOHelper is a utility class that performs miscellaneous tasks. The InstanceCallbacks interface provides notification of life cycle transitions in persistent application data objects. The JDO implementation uses the class hierarchy formed by JDOException and its subclasses to indicate most error conditions.

The JDOHelper Utility Class

Each operation of the JDOHelper class is a static method, and for that reason, there is no need to instantiate an instance of this class. Figure 7-1 shows the eleven methods of this class. Although static methods are normally underlined in UML class diagrams, this is avoided in Figure 7-1 to make the diagram more readable.

click to expand
Figure 7-1: The class diagram of the JDOHelper class

The methods in JDOHelper divide into two groups: those that perform miscellaneous tasks and those that identify the application data object's management state.

Miscellaneous Utility Methods in JDOHelper

The miscellaneous operations in the JDOHelper class perform the following tasks:

  • Get a persistence manager factory.

  • Mark a persistent object's field dirty.

  • Get the persistence manager that is managing an application data object, if there is one.

  • Get the identity object for an application data object, if there is one.

The next sections look at the methods for each of these tasks.

Acquiring a Persistence Manager Factory

JDOHelper provides two factory methods to acquire an object that implements the PersistenceManagerFactory interface.

 public static PersistenceManagerFactory getPersistenceManagerFactory(       Properties props) public static PersistenceManagerFactory getPersistenceManagerFactory(       Properties props,       ClassLoader cloader) 

Chapter 6 describes in detail the first getPersistenceManagerFactory method. This method loads the implementation class specified by the javax.jdo.PersistenceManagerFactoryClass property in props. It uses the class loader returned by the current Thread object's getContextClassLoader method. In most circumstances, this is the class loader that you want to use. The second method handles the odd case where you need to specify a different class loader.

Explicitly Marking Dirty a Data Object's Managed Field

The JDOHelper class provides the makeDirty method to explicitly indicate to JDO that the managed field of a managed object has been modified. The application uses this method to assist JDO in tracking changes to the entries of managed array fields.

 public static void makeDirty(Object ado, String fieldName) 

This method does the work that JDO normally does transparently when the application changes the value of a managed field. The only difference is that makeDirty does not change the managed field's value.

The fieldname parameter can be the field name as declared in the class, for example, "myManagedField". It can also be the class name, or fully qualified class name, concatenated with the field name by using the dot notation, such as "com.ysoft.jdo.book.example.MyAppDataClass.myManagedField".

In a class hierarchy, a derived class can declare a field using the same name used to declare a field in one of its superclasses. To determine which field is named when there are multiple fields by the same declared name in the class hierarchy, the makeDirty method begins its search either with the class named in the dot notation or, when the field name is unqualified by a class name, with the object's instance class. If the field is not found in the class where the search starts, then the method proceeds up the hierarchy of classes looking for the field in each application data class. The makeDirty method stops its search as soon as it finds the named field in an application data class, and as a result, at most one field is made dirty.

The call to makeDirty returns silently without effect under any of the following circumstances:

  • The object passed is null.

  • The object passed is not an application data object.

  • The object passed is JDO-transient, that is to say, unmanaged.

  • The field name is not the name of a managed field.

If conditions under which the method returns silently without action are avoided but a transaction is not active, then a JDOUserException is thrown.

The makeDirty Method Needed for Array Fields

When a transaction is active and the application stores a new value in the managed field of a managed application data object, JDO transparently marks the field as dirty. Several side effects can occur when a field becomes dirty. One, the object's management state becomes transactional, if it isn't already. Two, the object's management state becomes dirty, if it isn't already. Three, JDO saves a copy of the object's existing persistent state, called the before-image, if the transaction's RestoreValues property is true and JDO has not yet saved a before-image for the object in the current transaction. These side effects occur only once per modified object per transaction. By marking the persistent field dirty, JDO remembers to write the field to the datastore before the transaction commits. After these side effects occur, JDO applies the change that started the chain of side effects. Because JDO does this work transparently, the application normally does not explicitly mark a managed field dirty when it changes the field's value.

In the case of arrays, these side effects may not occur transparently. Suppose that you have an application data class with the following managed field:

 Integer [] numbers; 

If someplace in your application you execute code that replaces the array with a new array, as shown in the next line of code:

 numbers = new Integer[] {new Integer(1),new Integer(2), new Integer(3)}; 

then the existing array, if any, that is assigned to the numbers field is replaced by the new array. In this case, JDO transparently marks the numbers field dirty.

On the other hand, if someplace in your application you execute code that alters one of the elements of the array, as shown in the next line of code:

 numbers[0] = new Integer(42); 

then JDO may or may not transparently detect the change. For that reason, it may fail to take the appropriate actions. Whether transparent persistence detects the change depends on the implementation and may depend on where the code that makes the change is located. The vendor will provide specific guidance on what their implementation provides when it comes to detecting changes in array elements. To be safe and portable, the application should assume that the implementation cannot detect changes to array elements.

When the implementation cannot detect changes to the elements of the managed array, or this condition is assumed, then the application must assume responsibility for informing JDO that the managed field has become dirty. It does this by calling the makeDirty method in JDOHelper. Using this method expands the one-line assignment shown earlier into two lines:

 JDOHelper.makeDirty(this, "numbers"); numbers[0] = new Integer(42); 

Note that the call to makeDirty comes before the change is applied to the numbers field. This order of calls provides for the same order of events that occurs in transparent persistence. By following this order, you avoid surprises such as storing your change in the before-image or having JDO reload the persistent state when a persistent object becomes transactional in a datastore transaction.

Starting with JDO 1.0.1, the call to makeDirty in the example can be replaced by the following statement:

 numbers = numbers; 

Ordinarily, it depends on the implementation whether a field becomes dirty when the application assigns the value that the field already has, but in the case of array fields, JDO 1.0.1 guarantees that same value assignment always makes the field dirty. However, when optimizing, some compilers may discard the self-assignment statement shown. Therefore, the safest practice is to continue using the makeDirty method.

Getting a Managed Object's Persistence Manager

The JDOHelper class provides the getPersistenceManager method to obtain the persistence manager that is controlling the managed application data object.

 public static PersistenceManager getPersistenceManager(Object ado) 

When the application does not know which persistence manager is controlling an application data object, the application calls this method to obtain the persistence manager. The method takes the object in question as a parameter. The method returns null when the object passed is any of the following:

  • A null reference

  • Not an application data object

  • An unmanaged application data object

Otherwise, the method returns a reference to the object's persistence manager.

Getting a Persistent Object's Identity Object

The JDOHelper class provides two methods to get the identity object associated with a persistent data object.

 public static java.lang.Object getObjectId(Object ado) public static java.lang.Object getTransactionalObjectId(Object ado) 

The getObjectId method in JDOHelper returns the JDO identity of a managed application data object. It returns null when the object passed is a null reference. It also returns null when the object passed is not a persistent application data object. The identity object that the method returns is a copy of the identity object held by the JDO runtime.

When the application data class uses application identity and the JDO implementation supports the javax.jdo.option.ChangeApplicationIdentity implementation option, then the application may change the values of the persistent object's key fields. After one or more key fields have been changed within a transaction, the getObjectId method returns a copy of the original JDO identity object, but the getTransactionalObjectId method returns a copy of the new JDO identity object.

Note

Chapter 6 discusses the implementation options, and Chapter 5 describes how the JDO metadata determines the type of JDO identity for each application data class.

If a transaction is not active or if the application key fields have not been changed, then getTransactionalObjectId behaves in the same fashion as getObjectId.

Determining the Management State of a Data Object

The JDOHelper class has five interrogation methods that determine whether an application data object is persistent, transactional, dirty, new, and/or deleted. Used together, these methods determine the JDO management state of an application data object.

 public static boolean isPersistent(Object ado) public static boolean isTransactional(Object ado) public static boolean isDirty(Object ado) public static boolean isNew(Object ado) public static boolean isDeleted(Object ado) 

As a general rule, the application does not concern itself with the management state of individual data objects. Instead, the application manages queries and transactions and makes decisions whether to add, delete, or modify persistent objects. It relies on JDO to do the right thing with the managed objects. The state interrogation methods therefore do not have a place in the normal business logic of the application. Instead, they are useful for learning about the behavior of the implementation and for debugging situations that the developer does not understand.

When an application data object is persistent, the JDO runtime associates it with a JDO identity object. Sometimes the persistent state of a persistent object is loaded into memory, and sometimes it is not. An application data object is transactional if the JDO runtime has associated the object with a transaction. When a transactional object requires modification of the state stored in the datastore upon commit, the transactional object is dirty. Some objects are dirty because they were modified after they became transactional. Some objects are dirty because they are new and their persistent state is not yet stored in the datastore. Some objects are dirty because they are deleted and their state needs to be removed from the datastore. Upon transaction commit, JDO flushes the persistent state of dirty transactional objects to the datastore by doing the updates, insertions, and deletions required.

For each of the ten JDO management states that application data objects may be in, Table 7-1 shows an "x" when the corresponding JDOHelper method returns true. (The table presented here draws heavily on Table 3 of Sun's JDO 1.0 specification.) If the object passed to the helper method is null or is not an application data object, then false is returned.

Table 7-1: Five Methods That Detect an Object's JDO Management State

Management State

isPersistent

isTransactional

isDirty

isNew

isDeleted

Transient

Transient-clean

x

Transient-dirty

x

x

Persistent-nontransactional

x

Hollow

x

Persistent-clean

x

x

Persistent-dirty

x

x

x

Persistent-deleted

x

x

x

x

Persistent-new

x

x

x

x

Persistent-new-deleted

x

x

x

x

x

As Table 7-1 shows, the five methods do not discriminate between application data objects in the hollow state and those in the persistent-nontransactional state. JDO does not offer a portable way to distinguish between the hollow and persistent-nontransactional states.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net