Cambridge Technology PartnersCommunity Documentation
A common requirement for entities is tracking what is being done with them. CDI Query provides a convenient way to support this requirement.
CDI Query does not support creating revisions of entities. If this is a requirement for your audits, have a look at Hibernate Envers.
CDI Query uses an entity listener to update auditing data before entities get created or update. The entity listener must be activated before it can be used. This can either be done globally for all entities of a persistent unit or per entity.
Activation per persistence unit:
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd" version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="com.ctp.cdi.query.audit.AuditEntityListener" />
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
</entity-mappings>
Activation per entity:
@Entity
@EntityListeners(AuditEntityListener.class)
public class AuditedEntity implements Serializable {
...
}
All that has to be done now is annotating the entity properties which are used to audit the entity.
To keep track on creation and modification times, following annotations can be used:
@Entity
public class AuditedEntity implements Serializable {
...
@Temporal(TemporalType.TIMESTAMP)
@CreatedOn
private Date created;
@Temporal(TemporalType.TIMESTAMP)
@ModifiedOn
private Date updated;
...
}
In case the modification date should also be set during entity creation, the annotation can be customized:
@ModifiedOn(setOnCreate=true)
Beside keeping track of when a change has happened, it's also often critical to track who's responsible for the change. Annotate a user tracking field with the following annotation:
@Entity
public class AuditedEntity implements Serializable {
...
@ModifiedBy
private String auditUser;
...
}
Now there's a little help needed. The entity listener needs to be able to resolve the current user - there must be a bean available of the matching type for the annotation property, exposed over a special CDI qualifier:
public class UserProvider {
@Inject
private User user;
@Produces @CurrentUser
public String currentUser() {
return user.getUsername();
}
...
}
If you expose another entity here, make sure this entity is attached to a persistent context. Also, be aware that the CDI container will proxy a scoped bean, which might confuse the persistence provider when peristing / updating the target entity.