Cayenne User Documentation
Lifecycle Callbacks

## Lifecycle Callbacks

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: Interception of object state transitions inside `"Persistent.setPersistenceState()"`. Event mechanism defined in `"org.apache.cayenne.access.event"` package. Scheduled for removal in 3.0. `"DataObject.validateForX"` - it is a good idea to use it strictly for validation; updating the state before commit should be done via callbacks. `"DataObject.fetchFinished()"` - scheduled for removal in 3.0

## Callback Method Semantics

- No formal interface is required to mark a method to be used for callback (although `org.apache.cayenne.LifecycleListener` can optionally be implemented for type-safety and to simplify registration).
- A callback method signature looks like `"void someMethod()"` for persistent classes.
- It looks like `"void method(Type entityObject)"` for listener classes.
- A callback method can have an arbitrary name.
- A callback method can use public, private, protected or default access.
- They must NOT be static.
- Callback methods are polymorphic - registering a callback on a superclass (even if the superclass does not map to an entity) will ensure the callback will be invoked on all entity subclasses, using the overriding subclass method if applicable.

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) {
          ...
       }
    }

## Types of Callbacks

Valid callback types are defined as Java enumerated constants in the `org.apache.cayenne.map.LifecycleEvent` enumeration.

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 | Within `"ObjectContext.performQuery()"` after the object is fetched. Within `"ObjectContext.rollbackChanges()"` after the object is reverted. Anytime a faulted object is resolved (i.e. if a relationship is fetched.

## Registering Callbacks

Normally listeners and persistent object callbacks are mapped in the Modeler, but here we'll show how to do that in the code. 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");

.
Copyright ©2001-2008 Apache Software Foundation