It is often necessary to perform various actions at different stages
of a persistent object's lifecycle. JDO includes two mechanisms for
monitoring changes in the lifecycle of your persistent objects: the
InstanceCallbacks
interface, and the
InstanceLifecycleListener
event framework.
Your persistent classes can implement the
InstanceCallbacks
family of interfaces to to receive callbacks when certain JDO
lifecycle events take place. There are four callbacks available:
The LoadCallback.jdoPostLoad
method is called by the JDO implementation after the
default fetch group
fields of your class have been loaded from the datastore.
Default fetch groups are explained in
Chapter 5, Metadata; for
now think of the default fetch group as all of the primitive
fields of the object. No other persistent fields can be
accessed in this method.
jdoPostLoad
is often used to
initialize non-persistent fields whose values depend on
the values of persistent fields. An example of this is
presented below.
StoreCallback.jdoPreStore
is
called just before the persistent values in your object
are flushed to the datastore. You can access all
persistent fields in this method.
jdoPreStore
is the complement to
jdoPostLoad
. While
jdoPostLoad
is most often used to
initialize non-persistent values from persistent data,
jdoPreStore
is usually used
to set persistent fields with information cached in
non-persistent ones. See the example below.
Note that the persistent identity of the object may not
have been assigned yet when this method is called.
The ClearCallback.jdoPreClear
method is called before the persistent fields of your
object are cleared.
JDO implementations clear the persistent state of objects
for several reasons, most of which will be covered later in
this document. You can use jdoPreClear
to clear non-persistent cached data and null
relations to other objects. You should not access the
values of persistent fields in this method.
DeleteCallback.jdoPreDelete
is
called before an object transitions to the deleted state.
Access to persistent fields is valid within this method.
You might
use this method to cascade the deletion to related objects
based on complex criteria, or to perform other cleanup.
Unlike the PersistenceCapable
interface,
you must implement the InstanceCallbacks
interfaces explicitly if you want to receive lifecycle callbacks.
![]() | Note |
---|---|
The |
Example 4.3. Using Callback Interfaces
/** * Example demonstrating the use of the InstanceCallbacks interface to * persist a java.net.InetAddress and implement a privately-owned relation. */ public class Host implements LoadCallback, StoreCallback, DeleteCallback { // the InetAddress field cannot be persisted directly by JDO, so we // use the jdoPostLoad and jdoPreStore methods below to persist it // indirectly through its host name string private transient InetAddress address; // non-persistent private String hostName; // persistent // set of devices attached to this host private Set devices = new HashSet (); // setters, getters, and business logic omitted public void jdoPostLoad () { // form the InetAddress using the persistent host name try { address = InetAddress.getByName (hostName); } catch (IOException ioe) { throw new JDOException ("Invalid host name: " + hostName, ioe); } } public void jdoPreStore () { // store the host name information based on the InetAddress values hostName = address.getHostName (); } public void jdoPreDelete () { // delete certain related devices when this object is deleted, based // on business logic PersistenceManager pm = JDOHelper.getPersistenceManager (this); pm.deletePersistentAll (filterDependents (devices)); } }
![]() | Note |
---|---|
The |
Only persistent classes can implement the
InstanceCallbacks
interfaces. This makes sense for
lifecycle actions such as caching internal state and deleting
dependent relations, but is clumsy for cross-cutting concerns like
logging and auditing. The lifecycle listener event framework solves
this problem by allowing non-persistent classes to subscribe
to lifecycle events. The framework consists of a common event
class, a common super-interface for event listeners, and several
individual listener interfaces. A concrete listener class can
implement any combination of listener interfaces.
InstanceLifecycleEvent
: The
event class. The source of a lifecycle event is the
persistent object for which the event was triggered.
InstanceLifecycleListener
:
Common base interface for all listener types.
InstanceLifecycleListener
has no operations, but
gives a measure of type safety when adding listener objects
to a PersistenceManager
or
PersistenceManagerFactory
.
See Chapter 8, PersistenceManager and
Chapter 7, PersistenceManagerFactory.
LoadLifecycleListener
:
Listens for persistent state loading events. Its
postLoad
method is equivalent to
the InstanceCallbacks.jdoPostLoad
method described above.
StoreLifecycleListener
:
Listens for persistent state flushes. Its
preStore
method is equivalent to
the InstanceCallbacks.jdoPreStore
method described above. Its postStore
handler is invoked after the data for
the source object has been flushed to the database. Unlike
preStore
, the source object is
guaranteed to have a persistent identity by the time
postStore
is triggered.
ClearLifecycleListener
:
Receives notifications when objects clear their persistent
state. Its preClear
method is
equivalent to
InstanceCallbacks.jdoPreClear
.
The postClear
event is sent
just after the source object's state is cleared.
DeleteLifecycleListener
:
Listens for object deletion events. Its
preDelete
method is equivalent
to InstanceCallbacks.jdoPreDelete
.
Its postDelete
handler is triggered
after the source object has transitioned to the deleted
state. Access to persistent fields is not allowed in
postDelete
.
CreateLifecycleListener
:
The postCreate
event is fired when
an object first transitions from unmanaged to
persistent-new, such as during a call to
PersistenceManager.makePersistent
.
DirtyLifecycleListener
:
Dirty events fire when an object is first modified
(in JDO parlance, becomes dirty) within a transaction.
The runtime invokes preDirty
before
applying the change to the object, and postDirty
after applying the change.