package com.aggrepoint.dao; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.hibernate.EmptyInterceptor; import org.hibernate.type.Type; import com.aggrepoint.jpa.CreatedBy; import com.aggrepoint.jpa.CreatedDate; import com.aggrepoint.jpa.UpdatedBy; import com.aggrepoint.jpa.UpdatedDate; import com.aggrepoint.utils.beanhash.HashUtils; /** * * @author Jiangming Yang (yangjm@gmail.com) * */ public class AuditTrailInterceptor extends EmptyInterceptor { private static final long serialVersionUID = 1L; static class FieldDef { String fieldName; Class<?> annotationType; Class<?> valueType; public FieldDef(String name, Class<?> ann, Class<?> type) { fieldName = name; annotationType = ann; valueType = type; } } static Map<Class<?>, HashMap<String, FieldDef>> AUDIT_FIELDS = new HashMap<Class<?>, HashMap<String, FieldDef>>(); static HashMap<String, FieldDef> getAuditFields(Object entity, String[] propertyNames) { if (AUDIT_FIELDS.containsKey(entity.getClass())) return AUDIT_FIELDS.get(entity.getClass()); HashMap<String, FieldDef> auditFields = new HashMap<String, FieldDef>(); for (Method m : entity.getClass().getMethods()) { String propName = null; for (String prop : propertyNames) if (("get" + prop).equalsIgnoreCase(m.getName())) { propName = prop; break; } if (propName == null) continue; for (Annotation ann : m.getAnnotations()) if (ann instanceof CreatedBy) { auditFields.put(propName, new FieldDef(propName, CreatedBy.class, m.getReturnType())); break; } else if (ann instanceof UpdatedBy) { auditFields.put(propName, new FieldDef(propName, UpdatedBy.class, m.getReturnType())); break; } else if (ann instanceof CreatedDate) { auditFields.put(propName, new FieldDef(propName, CreatedDate.class, m.getReturnType())); break; } else if (ann instanceof UpdatedDate) { auditFields.put(propName, new FieldDef(propName, UpdatedDate.class, m.getReturnType())); break; } } for (Field f : HashUtils.getFields(entity.getClass())) { String propName = null; for (String prop : propertyNames) if (prop.equalsIgnoreCase(f.getName())) { propName = prop; break; } if (propName == null) continue; for (Annotation ann : f.getAnnotations()) if (ann instanceof CreatedBy) { auditFields.put(propName, new FieldDef(propName, CreatedBy.class, f.getType())); break; } else if (ann instanceof UpdatedBy) { auditFields.put(propName, new FieldDef(propName, UpdatedBy.class, f.getType())); break; } else if (ann instanceof CreatedDate) { auditFields.put(propName, new FieldDef(propName, CreatedDate.class, f.getType())); break; } else if (ann instanceof UpdatedDate) { auditFields.put(propName, new FieldDef(propName, UpdatedDate.class, f.getType())); break; } } AUDIT_FIELDS.put(entity.getClass(), auditFields); return auditFields; } @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { HashMap<String, FieldDef> auditFields = getAuditFields(entity, propertyNames); boolean modified = false; for (String prop : auditFields.keySet()) { FieldDef def = auditFields.get(prop); if (def.annotationType == UpdatedBy.class) { setUser(currentState, propertyNames, prop); modified = true; } else if (def.annotationType == UpdatedDate.class) { setDate(currentState, propertyNames, prop, def.valueType); modified = true; } } return modified; } @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { HashMap<String, FieldDef> auditFields = getAuditFields(entity, propertyNames); boolean modified = false; for (String prop : auditFields.keySet()) { FieldDef def = auditFields.get(prop); if (def.annotationType == CreatedBy.class) { setUser(state, propertyNames, prop); modified = true; } else if (def.annotationType == UpdatedBy.class) { setUser(state, propertyNames, prop); modified = true; } else if (def.annotationType == CreatedDate.class) { setDate(state, propertyNames, prop, def.valueType); modified = true; } else if (def.annotationType == UpdatedDate.class) { setDate(state, propertyNames, prop, def.valueType); modified = true; } } return modified; } private void setUser(Object[] currentState, String[] propertyNames, String propertyToSet) { for (int i = 0; i < propertyNames.length; i++) if (propertyNames[i].equals(propertyToSet)) { currentState[i] = UserContext.getUser(); break; } } private void setDate(Object[] currentState, String[] propertyNames, String propertyToSet, Class<?> type) { for (int i = 0; i < propertyNames.length; i++) if (propertyNames[i].equals(propertyToSet)) { if (java.sql.Timestamp.class.isAssignableFrom(type)) { currentState[i] = new java.sql.Timestamp( System.currentTimeMillis()); break; } else if (java.sql.Date.class.isAssignableFrom(type)) { currentState[i] = new java.sql.Date( System.currentTimeMillis()); break; } else if (java.util.Date.class.isAssignableFrom(type)) { currentState[i] = new java.util.Date(); break; } } } }