(since 3.0M1)
TODO: annotations, Modeler support
Users can register callback methods that will be invoked during the lifecycle of persistent objects. Callback mechanism matches closely the one defined in the JPA Specification (except that it works with JDK 1.4 and allows preconfigured listeners). There are seven lifecycle callbacks described below (PrePersist, PostPersist, PreUpdate, PostUpdate, PreRemove, PostRemove, PostLoad). There are two types of invocations for each one of them: callback on a persistent object itself or a callback on an arbitrary listener object.
![]() | Callbacks feature supercedes the following 1.2/2.0 features:
|
Callback on persistent object example:
public class Artist { ... // a valid callback method protected void setDefaultProperties() { ... } }
Callback on a listener class example:
public class MyListener { ... // a valid callback method public void initArtist(Artist a) { ... } }
Valid callback types are defined as int constants in the LifecycleListener interface.
Callback | Invoked... |
---|---|
PrePersist | Within "ObjectContext.newObject()" after ObjectId and ObjectContext are set. |
PreRemove | Before an object is deleted inside "ObjectContext.deleteObject()"; also includes all objects that will be deleted as a result of CASCADE delete rule. |
PreUpdate | Prior to commit (and prior to "validateFor*") within "ObjectContext.commitChanges()" and "ObjectContext.commitChangesToParent()" |
PostPersist | Within "ObjectContext.commitChanges()", after commit of a new object is done. |
PostRemove | Within "ObjectContext.commitChanges()", after commit of a deleted object is done. |
PostUpdate | Within "ObjectContext.commitChanges()", after commit of a modified object is done. |
PostLoad |
|
Listeners and persistent object callbacks can be mapped in the Modeler (TODO: GUI not implemented yet)_
Alternatively callbacks can be registered with LifecycleCallbackRegistry, which is shared by all contexts within DataDomain.
Obtaining the shared registry instance:
import org.apache.cayenne.reflect.LifecycleCallbackRegistry;
...
DataDomain domain = ...
LifecycleCallbackRegistry registry = domain.getEntityResolver().getCallbackRegistry();
Registry obtained this way already contains callbacks mapped in the DataMap. To add extra callbacks in runtimes, use various addListener(...) methods.
Adding a listener object that implements LifecycleListener interface:
import org.apache.cayenne.LifecycleListener public class MyListener implements LifecycleListener { public void prePersist(Object entity) { Persistent p = (Persistent) entity; System.out.println("New object created for entity " + p.getObjectId().getEntityName()); } ... } // listen for events on a single entity - Artist registry.addListener(Artist.class, new MyListener()); // listen for events on ALL entities: registry.addDefaultListener(new MyListener());
Adding a listener of an arbitrary class
public class MyOtherListener { // note that callback method doesn't have to be // public or called any predefined name void onEntityLoad(Object entity) { Persistent p = (Persistent) entity; System.out.println("Object fetched: " + p.getObjectId().getEntityName()); } // also we can pass the object already cast to the entity class // if the method is only going to handle this type of entities void onArtistChange(Artist artist) { System.out.println("Artist changed " + artist.getArtistName()); } ... } Object listener = new MyOtherListener(); // listen for different events on a single entity - Artist. The same // method can be registered for multiple events registry.addListener(LifecycleListener.PRE_PERSIST, Artist.class, listener, "onArtistChange"); registry.addListener(LifecycleListener.PRE_REMOVE, Artist.class, listener, "onArtistChange"); registry.addListener(LifecycleListener.PRE_UPDATE, Artist.class, listener, "onArtistChange"); // register another method to listen for ALL entities registry.addListener(LifecycleListener.POST_LOAD, listener, "onEntityLoad");
Finally a persistent object can implement callbacks as well, being notified of its own events:
// "extends _Artist" implies "implements Persistent" via a superclass public class Artist extends _Artist { // note that callback on entity is a no-arg method. void onLoad() { Persistent p = (Persistent) entity; System.out.println("Object fetched: " + this); } } // register Artist class callback registry.addListener(LifecycleListener.POST_LOAD, Artist.class, "onLoad");
TODO: expect this to be changed to something more user-friendly.
By default callbacks are disable. To building ObjectContext with enabled callbacks, do something like this:
DataChannelCallbackInterceptor postInterceptor = new DataChannelCallbackInterceptor(); postInterceptor.setChannel(domain); ObjectStore objectStore = new ObjectStore(domain.getSharedSnapshotCache()); ObjectContextCallbackInterceptor preInterceptor = new ObjectContextCallbackInterceptor(); preInterceptor.setContext(new DataContext(postInterceptor, objectStore)); ObjectContext userContext = preInterceptor;