4.4. Lifecycle Callbacks
Prev | Chapter 4. PersistenceCapable | Next

## 4.4. Lifecycle Callbacks

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.

### 4.4.1. InstanceCallbacks

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 `javax.jdo.InstanceCallbacks` interface is mainly present for backwards compatibility with previous JDO versions. You will typically implement the specific `javax.jdo.listener` package interfaces for the callbacks you want to receive. However, it may be convenient to implement `InstanceCallbacks` rather than the individual interfaces when your class utilizes several callbacks.

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));
        }
    }

### 4.4.2. InstanceLifecycleListener

| Note
The `kodo.event` package contains additional Kodo events beyond the JDO standard; see Section 9.8, “Transaction Events” of the Reference Guide and the package Javadoc for details.

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.

Prev | Up | Next
4.3. Restrictions on Persistent Classes | Home | 4.5. JDO Identity