Grails - Tracking Principals
We use the Grails auto timestamp feature in nearly all of our domain classes. It basically allows the definition of two special domain class properties
lastUpdated and automatically
sets the creation and modification date whenever a domain object is inserted or updated.
In addition to
lastUpdated we wanted to have a way to define two additional properties userCreated and userUpdated to save the principal who created, updated or
deleted a domain class (deletion because we have audit log tables that track all table changes, so when an entry is deleted and the principal is set before, we can see who deleted an
Grails provides the concept of GORM events, so we thought its implementation might be a good hint on how to implement our requirement for having
userUpdated. And indeed,
DomainEventListener, a descendant class of
AbstractPersistenceEventListener. It turns out that
DomainEventListener is responsible for executing the GORM event hooks on domain
object inserts, updates and deletes.
The event listener is registered at the application context as the
PersistenceListener interface (which is implemented by
AbstractPersistenceListener) extends from Spring’s
and therefore actually uses the Spring event system.
In order to create a custom persistence listener, we just have to extend
AbstractPersistenceEventListener and listen for the GORM events which are useful to us. Here is the implementation we ended
As you can see in the code above, the implementation intercepts the
PreDelete events. If any of these event types is thrown, the code checks the affected
domain object for the existence of either the
userUpdated property. If available, it uses the
springSecurityService to access the currently logged-in principal and
uuid property, as this is the unique identifier of our users in this application.
To register the
PrincipalPersistenceListener and attach it to a Grails datastore, we need to add the following code to
To make this work, the
springSecurityService needs to be injected, the same is true for
But that’s all we have to do to support our new domain class properties
userUpdated. The last step is to add both properties to the domain class(es) we want to track.
Grails integrates with Spring’s event mechanism and provides the
AbstractPersistenceEventListener base class to listen to certain GORM events. Grails uses this mechanism internally for example for
the GORM event hooks but it can of course be used by the application logic too. This article showed how to introduce support for
userUpdated which are similar to
lastUpdated but store the principal how created, updated or deleted a domain object.