JDO2 defines a mechanism whereby a persistable class can be marked as a listener for lifecycle
events. Alternatively a separate listener class can be defined to receive these events. Thereafter
when entities of the particular class go through lifecycle changes events are passed to the
provided methods. Let's look at the two different mechanisms
JDO1 and JDO2 define an interface for PersistenceCapable classes so that they can be notified
of events in their own lifecycle and perform any additional operations that are needed at these
checkpoints. This is a complement to the Lifecycle Listeners
interface which provides listeners for all objects of particular classes, with the events sent
to a listener. With
InstanceCallbacks
the
PersistenceCapable
class is the
destination of the lifecycle events. As a result the
Instance Callbacks
method is more
intrusive than the method of
Lifecycle Listeners
in that it requires methods adding
to each class that wishes to receive the callbacks.
DataNucleus supports the
InstanceCallbacks
interface
.
To give an example of this capability, let us define a class that needs to perform some operation just before
it's object is deleted.
public class MyClass implements InstanceCallbacks
{
String name;
... (class methods)
public void jdoPostLoad() {}
public void jdoPreClear() {}
public void jdoPreStore() {}
public void jdoPreDelete()
{
// Perform some operation just before being deleted.
}
}
So we have implemented
InstanceCallbacks
and have defined the 4 required methods.
Only one of these is of importance in this example.
These methods will be called just before storage in the data store (
jdoPreStore
), just
before clearing (
jdoPreClear
), just after being loaded from the datastore
(
jdoPostLoad
) and just before being deleted (
jdoPreDelete
).
JDO2 adds 2 new callbacks to complement
InstanceCallbacks
. These are
AttachCallback
and
DetachCallback
.
If you want to intercept attach/detach events your class can implement these interfaces.
You will then need to implement the following methods
public interface AttachCallback
{
public void jdoPreAttach();
public void jdoPostAttach(Object attached);
}
public interface DetachCallback
{
public void jdoPreDetach();
public void jdoPostDetach(Object detached);
}
JDO 2.0 defines an interface for the PersistenceManager and PersistenceManagerFactory whereby a
user can register a listener for persistence events. The user provides a listener for either all
classes, or a set of defined classes, and the JDO implementation calls methods on the listener
when the required events occur. This provides the user application with the power to monitor the
persistence process and, where necessary, append related behaviour. Specifying the listeners on
the PersistenceManagerFactory has the benefits that these listeners will be added to all
PersistenceManagers created by that factory, and so is for convenience really. This facility is a
complement to the Instance Callbacks facility which allows
interception of events on an instance by instance basis. The
Lifecycle Listener
process is
much less intrusive than the process provided by
Instance Callbacks
, allowing a class
external to the persistence process to perform the listening.
DataNucleus supports the
InstanceLifecycleListener
interface.
.
To give an example of this capability, let us define a Listener for our persistence process.
public class LoggingLifecycleListener implements CreateLifecycleListener,
DeleteLifecycleListener, LoadLifecycleListener, StoreLifecycleListener
{
public void postCreate(InstanceLifecycleEvent event)
{
log.info("Lifecycle : create for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
public void preDelete(InstanceLifecycleEvent event)
{
log.info("Lifecycle : preDelete for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
public void postDelete(InstanceLifecycleEvent event)
{
log.info("Lifecycle : postDelete for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
public void postLoad(InstanceLifecycleEvent event)
{
log.info("Lifecycle : load for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
public void preStore(InstanceLifecycleEvent event)
{
log.info("Lifecycle : preStore for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
public void postStore(InstanceLifecycleEvent event)
{
log.info("Lifecycle : postStore for " +
((PersistenceCapable)event.getSource()).jdoGetObjectId());
}
}
Here we've provided a listener to receive events for CREATE, DELETE, LOAD, and STORE of objects.
These are the main event types and in our simple case above we will simply log the event. All
that remains is for us to register this listener with the PersistenceManager, or
PersistenceManagerFactory
pm.addInstanceLifecycleListener(new LoggingLifecycleListener(), null);
When using this interface the user should always remember that the listener is called within
the same transaction as the operation being reported and so any changes they then make to the
objects in question will be reflected in that objects state.
Register the listener with the PersistenceManager or PersistenceManagerFactory provide
different effects. Registering with the PersistenceManagerFactory means that all
PersistenceManagers created by it will have the listeners registered on the
PersistenceManagerFactory called. Registering the listener with the PersistenceManager will
only have the listener called only on events raised only by the PersistenceManager instance.
The above diagram displays the sequence of actions for a listener registered only in the
PersistenceManager. Note that a second PersistenceManager will not make calls to the listener
registered in the first PersistenceManager.
The above diagram displays the sequence of actions for a listener registered in the
PersistenceManagerFactory. All events raised in a PersistenceManager obtained from the
PersistenceManagerFactory will make calls to the listener registered in the
PersistenceManagerFactory.
DataNucleus supports the following instance lifecycle listener types
-
AttachLifecycleListener
- all attach events
-
ClearLifecycleListener
- all clear events
-
CreateLifecycelListener
- all object create events
-
DeleteLifecycleListener
- all object delete events
-
DetachLifecycleListener
- all detach events
-
DirtyLifecycleListener
- all dirty events
-
LoadLifecycleListener
- all load events
-
StoreLifecycleListener
- all store events
The default JDO2 lifecycle listener
StoreLifecycleListener
only informs the
listener of the object being stored. It doesn't provide information about the fields
being stored in that event. DataNucleus extends the JDO2 specification and on the
"preStore" event it will return an instance of
org.datanucleus.jdo.FieldInstanceLifecycleEvent
(which extends the JDO2
InstanceLifecycleEvent) and provides access to the names of the fields being stored.
public class FieldInstanceLifecycleEvent extends InstanceLifecycleEvent
{
...
/**
* Accessor for the field names affected by this event
* @return The field names
*/
public String[] getFieldNames()
...
}
If the store event is the persistence of the object then this will return all field names.
If instead just particular fields are being stored then you just receive those fields in
the event. So the only thing to do to utilise this DataNucleus extension is cast the
received event to
org.datanucleus.FieldInstanceLifecycleEvent