/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.api.db.hibernate; import java.io.Serializable; import java.util.Date; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CallbackException; import org.hibernate.EmptyInterceptor; import org.hibernate.type.Type; import org.openmrs.Auditable; import org.openmrs.User; import org.openmrs.api.context.Context; /** * This class looks for {@link Auditable} that are being inserted into the database. When found, if * the class is an update (instead of an insert) then the changedBy and dateChanged fields are set * to the current user and the current time. <br/> * <br/> * This class replaces the logic that was in the AuditableSaveHandler. It is here so that the * cascading does NOT happen for dateChanged/changedBy to child OpenmrsObjects (because all handlers * recurse on lists of OpenmrsObjects. * * @since 1.9 */ public class AuditableInterceptor extends EmptyInterceptor { private static final Log log = LogFactory.getLog(AuditableInterceptor.class); private static final long serialVersionUID = 1L; /** * This class method is only called when flushing an updated dirty object, not inserting objects * * @return true if the object got the changedBy and dateChanged fields set * @should return false for non Auditable objects * @should set the dateChanged field * @should set the changedBy field * @should be called when saving an Auditable * * @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) */ @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException { if (entity instanceof Auditable && propertyNames != null) { if (log.isDebugEnabled()) log.debug("Setting changed by fields on " + entity); // the return value boolean objectWasChanged = false; // loop over the properties and only change the changedBy and dateChanged fields Date currentDate = new Date(); User authenticatedUser = Context.getAuthenticatedUser(); for (int x = 0; x < propertyNames.length; x++) { if (propertyNames[x].equals("changedBy") && previousState != null && previousState[x] != authenticatedUser) { currentState[x] = authenticatedUser; objectWasChanged = true; } else if (propertyNames[x].equals("dateChanged") && previousState != null && previousState[x] != currentDate) { currentState[x] = currentDate; objectWasChanged = true; } } // tell hibernate that we've changed this object return objectWasChanged; } // if we get here it means we didn't change anything return false; } }