package fr.openwide.core.jpa.more.business.audit.hibernate; import java.io.Serializable; import java.util.Date; import org.hibernate.CallbackException; import org.hibernate.type.Type; import com.google.common.base.Objects; import fr.openwide.core.jpa.hibernate.interceptor.AbstractChainableInterceptor; import fr.openwide.core.jpa.more.business.audit.model.embeddable.AbstractAuditableProperty; public abstract class AbstractAuditablePropertyUpdateInterceptor extends AbstractChainableInterceptor { @Override public abstract boolean applyTo(Object entity); protected void updateProperty(AbstractAuditableProperty<?> property) { property.setLastEditDate(new Date()); } @Override public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { boolean stateChanged = false; for (int i = 0 ; i < state.length ; ++i) { Type type = types[i]; if (AbstractAuditableProperty.class.isAssignableFrom(type.getReturnedClass())) { stateChanged = true; refreshAuditableProperty(state, i, type); } } return stateChanged; } @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { boolean stateChanged = false; for (int i = 0 ; i < currentState.length ; ++i) { Type type = types[i]; Object currentProperty = currentState[i]; Object oldProperty = previousState[i]; if (AbstractAuditableProperty.class.isAssignableFrom(type.getReturnedClass()) && (currentProperty == null || !Objects.equal(currentProperty, oldProperty))) { stateChanged = true; refreshAuditableProperty(currentState, i, type); } } return stateChanged; } private void refreshAuditableProperty(Object[] currentState, int index, Type type) { try { if (currentState[index] == null) { currentState[index] = (AbstractAuditableProperty<?>) type.getReturnedClass().newInstance(); } updateProperty((AbstractAuditableProperty<?>) currentState[index]); } catch (InstantiationException e) { throw auditablePropertyInstanciationException(e); } catch (IllegalAccessException e) { throw auditablePropertyInstanciationException(e); } } private CallbackException auditablePropertyInstanciationException(Exception e) { return new CallbackException("Could not instanciate an AbstractAuditableProperty property using default constructor. Every auditable property should be declared in entities using its concrete type and this type should provide a public default constructor.", e); } }