h1. Lifecycle event model of PlayMorphia and Morphia

p(note). The content of this chapter is only valid for PlayMorphia v1.2.4 or later.

In this chapter we will explorer the lifecycle event model of PlayMorphia (start from v1.2.4) and Morphia.

h2. <a name="create">Create events</a>

!images/lifecycle-create!

h3. <a name="create-play">PlayMorphia create events</a>

|<_.event|<_.description|
|<on add|<triggered before an new entity is saved|
|<added|<triggered after an new entity is saved|

*Event implementation*
|<_.event|<_.annotation|<_.interface|
|<on add|<<code>@OnAdd</code>|@IMorphiaEventHandler.onAdd(Model)@|
|<added|<<code>@Added</code>|@IMorphiaEventHandler.added(Model)@|

h3. <a name="create-morphia">Morphia create events</a>

Morphia does not provide specific create events, however you could use @PrePersist@, @PreSave@ and @PostPerist@ to simulate create events and use @this.isNew()@ to identify if current model instance is an new entity or existing entity. See "Morphia update events":lifecycle-def#update-morphia for detail about @PrePersist@, @PreSave@ and @PostPerist@ events.

h2. <a name="update">Update events</a>

!images/lifecycle-update!

h3. <a name="update-play">PlayMorphia update events</a>

|<_.event|<_.description|
|<on update|<triggered before an existing entity is saved|
|<updated|<triggered after an existing entity is saved|

*Event implementation*
|<_.event|<_.annotation [1]|<_.interface [2]|
|<on update|<<code>@OnUpdate</code>|@IMorphiaEventHandler.onUpdate(Model)@|
|<updated|<<code>@Updated</code>|@IMorphiaEventHandler.updated(Model)@|

fn1. see more about "annotation based PlayMorphia lifecycle event handling":lifecycle#self

fn2. see more about "event handler based PlayMorphia lifecycle event handling":lifecycle#sep

h3. <a name="update-morphia">Morphia update events</a>

|<_.event|<_annotation|<_.description|
|<pre persist|<<code>@PrePersist</code>|triggered *before* a PlayMorphia "model":model instance get converted into a MongoDB's <a href="http://api.mongodb.org/java/2.6/com/mongodb/DBObject.html">@DBObject@</a>|
|<pre save|<<code>@PreSave</code>|<triggered *after* a PlayMorphia "model":model instance get converted into a MongoDB's <a href="http://api.mongodb.org/java/2.6/com/mongodb/DBObject.html">@DBObject@</a> and *before* that @DBObject@ is saved into MongoDB|
|<post persist|<<code>@PostPersist</code>|<triggered *after* the model instance saved into MongoDB|

p(note). Morphia annotation enable you do define methods that accept parameters and return result. Click "here":http://code.google.com/p/morphia/source/browse/trunk/morphia/src/test/java/com/google/code/morphia/TestDatastore.java#82 for examples.

h2. <a name="load">Load events</a>

!images/lifecycle-load!

h3. <a name="load-play">PlayMorphia load events</a>

|<_.event|<_.description|
|<on load|<triggered before an entity is loaded from MongoDB|
|<loaded|<triggered after an entity is loaded from MongoDB|

p(note). @OnLoad@ event is seldom used as when this event triggered, the entity is still empty and waiting for the fields to be filled

*Event implementation*
|<_.event|<_.annotation|<_.interface|
|<on load|<<code>@OnLoad</code>|@IMorphiaEventHandler.onLoad(Model)@|
|<loaded|<<code>@Loaded</code>|@IMorphiaEventHandler.loaded(Model)@|

h3. <a name="load-morphia">Morphia load events</a>

|<_.event|<_annotation|<_.description|
|<pre load|<<code>@PreLoad</code>|triggered *before* a PlayMorphia "model":model instance get loaded from MongoDB|
|<post load|<<code>@PostLoad</code>|<triggered *after* the model instance loaded from MongoDB|

h2. <a name="delete">Delete events</a>

!images/lifecycle-delete!

h3. <a name="delete-play">PlayMorphia delete events</a>

|<_.event|<_.description|
|<on delete|<triggered before an entity is removed from MongoDB|
|<deleted|<triggered after an entity deleted from MongoDB|

*Event implementation*
|<_.event|<_.annotation|<_.interface|
|<on delete|<<code>@OnDelete</code>|@IMorphiaEventHandler.onDelete(Model)@|
|<deleted|<<code>@Deleted</code>|@IMorphiaEventHandler.deleted(Model)@|

h3. <a name="delete-morphia">Morphia delete events</a>

Morphia does not support delete events

h2. <a name="batch-delete">Batch delete events</a>

!images/lifecycle-batch-delete!

h3. <a name="batch-delete-play">PlayMorphia batch delete events</a>

|<_.event|<_.description|
|<on batch delete|<triggered before a set of entities defined by a PlayMorphia query removed from MongoDB|
|<batch deleted|<triggered after a set of entities defined by a PlayMorphia query deleted from MongoDB|

*Event implementation*
|<_.event|<_.annotation|<_.interface|
|<on batch delete|<<code>@OnBatchDelete</code>|@IMorphiaEventHandler.onBatchDelete(MorphiaQuery)@|
|<batch deleted|<<code>@BatchDeleted</code>|@IMorphiaEventHandler.batchDeleted(MorphaQuery)@|

h3. <a name="batch-delete-morphia">Morphia batch delete events</a>

Morphia does not support batch delete events

h2. <a name="notes">Additional notes</a>

h3. <a name="sig-1">PlayMorphia annotated lifecycle event handler signature</a>

No return object and method parameters should be defined for the following annotation based event handler: <code>@OnLoad, @Loaded, @OnAdd, @Added, @OnUpdate, @Updated, @OnDelete, @Deleted</code>:

bc. @Entity MyMode extends Model {
    // correct signature 
    @OnLoad void onLoad() {}
    @Loaded void loaded() {}
    @OnAdd void onAdd() {}
    @Added void added() {}
    @OnUpdate void onUpdate() {}
    @Updated void updated() {}
    @OnDelete void onDelete() {}
    @Deleted void deleted() {}
    // the following method's signatures are not correct and they will not be triggered at all
    @OnLoad Model myOnLoad() {...}
    @Loaded void myLoaded(String xx) {...}
    @OnAdd String myOnAdd(Model xx) {...}
}

You could make those methods static or non-static, but it's highly recommend to use non-static methods for the above event handling as you get the access to the entity which is experiencing the lifecycle events via "this" pointer.

There is completely no requirements on method scope, you can make it either one of "public", "protected", "private" or default package level, the functionality will not impact by changing the method scope.

Unlike the above events, the two batch events (<code>@OnBatchDelete</code> and <code>@BatchDeleted</code>) have a bit different method signature:

bc. @Entity MyModel extends Model {
    @OnBatchDelete static void onBatchDelete(MorphiaQuery q) {...}
    @BatchDeleted static void BatchDeleted(MorphiaQuery q) {...}
}

As you could see, we have 2 differences in the batch event handler definition compare to that of the other event handlers:

# A MorphiaQuery type parameter is required. This is mandatory, otherwise your method will not be called when the batch delete event triggered.
# the batch event handling methods are defined as static methods. This is optional but recommended practice.

p(note). There are different method signature requirements when you are writing Morphia annotation marked lifecycle event handlers, please refer to "this":http://code.google.com/p/morphia/wiki/LifecycleMethods page for detail.

h3. <a name="more-on-batch-delete">More on @BatchDeleted@ event</a>

A common error is to use the @MorphiaQuery@ argument passed into @BatchDeleted@ event handler to query for which models has been deleted. However that will always return an empty list as all those entities has been removed from MongoDB already. One way to get the deleted entities is to remember them in the @OnBatchDelete@ event handler:

bc. @Entity MyModel extends Model {
    private Map<MorphiaQuery, List<MyModel>> deleteModels_ = new HashMap<MorphiaQuery, List<MyModel>>();
    @OnBatchDelete static void onBatchDelete(MorphiaQuery q) {
        List<MyModel> list = q.asList();
        deleteModels_.put(q, list);
    }
    @BatchDeleted static void batchDeleted(MorphiaQuery q) {
        List<MyModel> list = deleteModels_.get(q);
        // do whatever you want on the deleted models
        ...
    }
}

h3. <a name="why">Why do you prefer PlayMorphia event handling framework to Morphia one</a>

# More clear. PlayMorphia events distiguish between add (new) and update (existing) entities while Morphia events don't
# Performance. There are very little performance gain if you choose PlayMorphia event handling model. PlayMorphia code enhancer will burn the relevant code into final byte code so at runtime there is no reflection at all. While Morphia needs one time reflection for event handler call and then cache it to hash map for later on calls.
# More complete. PlayMorphia support delete and batch delete events while Mophia doesn't.

h3. <a name="perf">Performance consideration</a>

p(note). You are NOT required to do the same thing as shown in the above code. Calling to the event handler methods is executed in the current thread, the more logic you put into the event handlers the more performance is impact. So please do as simple as possible in any of the event handlers. Implement only the logic you need. If you don't need to bother with batch delete events then you shouldn't add batch delete event handler. Actually in most cases you don't need to implement any lifecycle event handlers. This is ture for both PlayMorphia and Morphia event handling model.

h2. <a name="resource">See also</a>

# "Lifecycle handling introduction":lifecycle
# "PlayMorphia model introduction":model
# "Use of PlayMorphia model: crud":crud

