/**
* @Created Nov 4, 2011 9:41:05 AM
* @author cry30
*/
package com.philip.journal.core.dao;
/**
| File: HibernateAuditLogListener.java
| Created: Mar 3, 2008
| Author: Will Hoover
*/
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.StatelessSession;
import org.hibernate.cfg.Configuration;
import org.hibernate.event.AbstractPreDatabaseOperationEvent;
import org.hibernate.event.Initializable;
import org.hibernate.event.PreDeleteEvent;
import org.hibernate.event.PreDeleteEventListener;
import org.hibernate.event.PreInsertEvent;
import org.hibernate.event.PreInsertEventListener;
import org.hibernate.event.PreUpdateEvent;
import org.hibernate.event.PreUpdateEventListener;
import com.philip.core.WarningType;
import com.philip.dao.AuditTrail;
import com.philip.journal.core.bean.User;
/**
* Audit Log Listener is used to log insert, update, delete, and load operations. Complete list of listeners/events can
* be obtained at <tt>org.hibernate.event.EventListeners</tt>.
*
* @see org.hibernate.event.EventListeners
* @author whoover
*/
public final class HibernateAuditLogListener implements PreDeleteEventListener, PreInsertEventListener,
PreUpdateEventListener, Initializable {
/** Class logger. */
private static final Log LOGGER = LogFactory.getLog(HibernateAuditLogListener.class);
/** Insert Operation Type. */
public static final String OP_TYPE_INSERT = "INSERT";
/** Update Operation Type. */
public static final String OP_TYPE_UPDATE = "UPDATE";
@Override
public void initialize(final Configuration cfg)
{
//
}
/** We don't include this in the audit trail. */
private final List<String> auditColumn = Arrays.asList(new String[] {
"creator",
"updater",
"createDate",
"createTime",
"updateDate",
"updateTime" });
/**
* Simply gets the updater in the Entity. Until a session aware method is discovered, we will rely on the client
* side actor set on the entity to determine the actor. Another option is to pass the session data lower down to the
* DAO side.
*
* @param session Hibernate session.
* @param event pre action event.
* @return the current updater set on the Entity.
*/
private String getActorId(final StatelessSession session, final AbstractPreDatabaseOperationEvent event)
{
final EntityMode entityMode = event.getPersister().guessEntityMode(event.getEntity());
User actor = ((User) event.getPersister().getPropertyValue(event.getEntity(), "updater", entityMode));
if (actor == null) {//can happen due to bad data. I do not set the creator and updater before so...
actor = ((User) event.getPersister().getPropertyValue(event.getEntity(), "creator", entityMode));
}
return actor.getUsername();
}
@Override
public boolean onPreDelete(final PreDeleteEvent event)
{
try {
@SuppressWarnings(WarningType.DEPRECATION)
final Serializable entityId = event.getPersister().hasIdentifierProperty() ? event.getPersister()
.getIdentifier(event.getEntity(), event.getPersister().guessEntityMode(event.getEntity())) : null;
final String entityName = event.getEntity().getClass().toString();
final Date transTime = new Date(); // new Date(event.getSource().getTimestamp());
// need to have a separate session for audit save
final StatelessSession session = event.getPersister().getFactory().openStatelessSession();
session.beginTransaction();
final String actorId = getActorId(session, event);
session.insert(new AuditTrail(entityId.toString(), entityName, actorId, transTime));
session.getTransaction().commit();
} catch (final HibernateException e) {
LOGGER.error("Unable to process audit log for DELETE operation", e);
}
return false;
}
@Override
public boolean onPreInsert(final PreInsertEvent event)
{
try {
@SuppressWarnings(WarningType.DEPRECATION)
final String entityId = event.getPersister().hasIdentifierProperty() ? event.getPersister()
.getIdentifier(event.getEntity(), event.getPersister().guessEntityMode(event.getEntity()))
.toString() : "";
final String entityName = event.getEntity().getClass().toString();
final Date transTime = new Date(); // new Date(event.getSource().getTimestamp());
final EntityMode entityMode = event.getPersister().guessEntityMode(event.getEntity());
Object newPropValue = null;
// need to have a separate session for audit save
final StatelessSession session = event.getPersister().getFactory().openStatelessSession();
session.beginTransaction();
final String actorId = getActorId(session, event);
for (final String propertyName : event.getPersister().getPropertyNames()) {
if (!auditColumn.contains(propertyName)) {
newPropValue = event.getPersister().getPropertyValue(event.getEntity(), propertyName, entityMode);
// because we are performing an insert we only need to be concerned will non-null values
if (newPropValue != null && !(newPropValue instanceof Collection)) {
final AuditTrail auditTrail = new AuditTrail(entityId, entityName, OP_TYPE_INSERT, actorId,
transTime).entityProperty(propertyName).entityPropNewValue(
newPropValue == null ? null : newPropValue.toString());
session.insert(auditTrail);
}
}
}
session.getTransaction().commit();
} catch (final HibernateException e) {
LOGGER.error("Unable to process audit log for INSERT operation", e);
}
return false;
}
@Override
public boolean onPreUpdate(final PreUpdateEvent event)
{
try {
@SuppressWarnings(WarningType.DEPRECATION)
final Serializable entityId = event.getPersister().hasIdentifierProperty() ? event.getPersister()
.getIdentifier(event.getEntity(), event.getPersister().guessEntityMode(event.getEntity())) : null;
final String entityName = event.getEntity().getClass().toString();
final Date transTime = new Date(); // new Date(event.getSource().getTimestamp());
final EntityMode entityMode = event.getPersister().guessEntityMode(event.getEntity());
Object oldPropValue = null;
Object newPropValue = null;
// need to have a separate session for audit save
final StatelessSession session = event.getPersister().getFactory().openStatelessSession();
session.beginTransaction();
// get the existing entity from session so that we can extract existing property values
final Object existingEntity = session.get(event.getEntity().getClass(), entityId);
final String actorId = getActorId(session, event);
// cycle through property names, extract corresponding property values and insert new entry in audit trail
for (final String propertyName : event.getPersister().getPropertyNames()) {
if (!auditColumn.contains(propertyName)) {
newPropValue = event.getPersister().getPropertyValue(event.getEntity(), propertyName, entityMode);
oldPropValue = event.getPersister().getPropertyValue(existingEntity, propertyName, entityMode);
// because we are performing an insert we only need to be concerned will non-null values
if (newPropValue != null && !newPropValue.equals(oldPropValue)
&& !(newPropValue instanceof Collection)) {
final AuditTrail auditTrail = new AuditTrail(entityId.toString(), entityName, OP_TYPE_UPDATE,
actorId, transTime).entityProperty(propertyName)
.entityPropOldValue(oldPropValue == null ? null : oldPropValue.toString())
.entityPropNewValue(newPropValue == null ? null : newPropValue.toString());
session.insert(auditTrail);
}
}
}
session.getTransaction().commit();
} catch (final HibernateException e) {
LOGGER.error("Unable to process audit log for UPDATE operation", e);
}
return false;
}
}