org.openmrs.api.db.hibernate.AuditableInterceptor.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.api.db.hibernate.AuditableInterceptor.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
 *
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
 * graphic logo is a trademark of OpenMRS Inc.
 */
package org.openmrs.api.db.hibernate;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

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.OpenmrsObject;
import org.openmrs.api.context.Context;

/**
 * This class looks for {@link OpenmrsObject} and {@link Auditable} that are being inserted into the
 * database. The creator and dateCreated fields are set when inserting or updating objects and the
 * fields are still null. 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 method is only called when inserting new objects.
     * @should return true if dateCreated was null
     * @should return true if creator was null
     * @should return false if dateCreated and creator was not null
     * @should be called when saving OpenmrsObject
     * @return true if the object got the dateCreated and creator fields set
     * @see org.hibernate.EmptyInterceptor#onSave(java.lang.Object, java.io.Serializable,
     *      java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
     */
    @Override
    public boolean onSave(Object entity, Serializable id, Object[] entityCurrentState, String[] propertyNames,
            Type[] types) {
        return setCreatorAndDateCreatedIfNull(entity, entityCurrentState, propertyNames);
    }

    /**
     * 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 set the dateChanged field
     * @should set the changedBy field
     * @should be called when saving an Auditable
     * @should not enter into recursion on entity
     * @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 {
        boolean objectWasChanged;

        objectWasChanged = setCreatorAndDateCreatedIfNull(entity, currentState, propertyNames);

        if (entity instanceof Auditable && propertyNames != null) {
            if (log.isDebugEnabled()) {
                log.debug("Setting changed by fields on " + entity.getClass());
            }

            Map<String, Object> propertyValues = getPropertyValuesToUpdate();
            objectWasChanged = changeProperties(currentState, propertyNames, objectWasChanged, propertyValues,
                    false);
        }
        return objectWasChanged;
    }

    /**
     * Sets the creator and dateCreated fields to the current user and the current time if they are
     * null.
     * if is a Person Object, sets the personCreator and personDateCreated fields to the current user and the current time
     * if they are null.
     *
     * @param entity
     * @param currentState
     * @param propertyNames
     * @return true if creator and dateCreated were changed
     */
    private boolean setCreatorAndDateCreatedIfNull(Object entity, Object[] currentState, String[] propertyNames) {

        boolean objectWasChanged = false;

        if (entity instanceof OpenmrsObject) {
            if (log.isDebugEnabled()) {
                log.debug("Setting creator and dateCreated on " + entity);
            }

            Map<String, Object> propertyValues = getPropertyValuesToSave();
            objectWasChanged = changeProperties(currentState, propertyNames, objectWasChanged, propertyValues,
                    true);
        }
        return objectWasChanged;
    }

    private boolean changeProperties(Object[] currentState, String[] propertyNames, boolean objectWasChanged,
            Map<String, Object> propertyValues, Boolean setNullOnly) {

        for (String property : propertyValues.keySet()) {
            if (changePropertyValue(currentState, propertyNames, property, propertyValues.get(property),
                    setNullOnly)) {
                objectWasChanged = true;
            }
        }
        return objectWasChanged;
    }

    private Map<String, Object> getPropertyValuesToSave() {
        Map<String, Object> propertyValues = new HashMap<String, Object>();
        propertyValues.put("creator", Context.getAuthenticatedUser());
        propertyValues.put("dateCreated", new Date());
        propertyValues.put("personCreator", Context.getAuthenticatedUser());
        propertyValues.put("personDateCreated", new Date());
        return propertyValues;
    }

    private Map<String, Object> getPropertyValuesToUpdate() {
        Map<String, Object> propertyValues = new HashMap<String, Object>();
        propertyValues.put("changedBy", Context.getAuthenticatedUser());
        propertyValues.put("dateChanged", new Date());
        propertyValues.put("personChangedBy", Context.getAuthenticatedUser());
        propertyValues.put("personDateChanged", new Date());
        return propertyValues;
    }

    /**
     * Sets the property to the given value.
     *
     * @param currentState
     * @param propertyNames
     * @param propertyToSet
     * @param value
     * @param setNullOnly
     * @return true if the property was changed
     */
    private boolean changePropertyValue(Object[] currentState, String[] propertyNames, String propertyToSet,
            Object value, boolean setNullOnly) {

        int index = Arrays.asList(propertyNames).indexOf(propertyToSet);

        if (value == null) {
            return false;
        }

        if (index >= 0 && (currentState[index] == null || !setNullOnly) && !value.equals(currentState[index])) {
            currentState[index] = value;
            return true;
        }
        return false;
    }
}