/** * 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.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CallbackException; import org.hibernate.EntityMode; import org.hibernate.Interceptor; import org.hibernate.Transaction; import org.hibernate.type.Type; /** * Used by the {@link HibernateSessionFactoryBean} to keep track of multiple interceptors <br/> * Each of the methods in {@link Interceptor} are called for each interceptor that is added to this * class * * @since 1.9 */ public class ChainingInterceptor implements Interceptor { private static final Log log = LogFactory.getLog(ChainingInterceptor.class); // using a linkedhashset to preserve insert order and maintain a list of unique objects public Collection<Interceptor> interceptors = new LinkedHashSet<Interceptor>(); /** * Adds the given interceptor to the list of interceptors to be applied to hibernate sessions. * Interceptors are called in the added order, with core interceptors being called first * * @param interceptor the interceptor to add to the queue */ public void addInterceptor(Interceptor interceptor) { // do nothing if adding ourself to the list. This would cause infinite looping if (interceptor == this) { log.error("Attempting to add self to chain. This would result in epic failures."); return; } log.debug("Adding " + interceptor + " to interceptor chain"); if (interceptors == null) interceptors = new LinkedHashSet<Interceptor>(); interceptors.add(interceptor); } public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { for (Interceptor i : interceptors) i.onDelete(entity, id, state, propertyNames, types); } public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { boolean objectChanged = false; for (Interceptor i : interceptors) // must be in this order so that java doesn't skip the method call for optimizations objectChanged = i.onFlushDirty(entity, id, currentState, previousState, propertyNames, types) || objectChanged; return objectChanged; } public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { boolean objectChanged = false; for (Interceptor i : interceptors) // must be in this order so that java doesn't skip the method call for optimizations objectChanged = i.onLoad(entity, id, state, propertyNames, types) || objectChanged; return objectChanged; } public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { boolean objectChanged = false; for (Interceptor i : interceptors) // must be in this order so that java doesn't skip the method call for optimizations objectChanged = i.onSave(entity, id, state, propertyNames, types) || objectChanged; return objectChanged; } @SuppressWarnings("unchecked") public void postFlush(Iterator entities) { for (Interceptor i : interceptors) i.postFlush(entities); } @SuppressWarnings("unchecked") public void preFlush(Iterator entities) { for (Interceptor i : interceptors) i.preFlush(entities); } public Boolean isTransient(Object entity) { Boolean returnValue = null; // by default let hibernate figure it out for (Interceptor i : interceptors) { Boolean tmpReturnValue = i.isTransient(entity); // if (tmpReturnValue != null) { if (returnValue == null) returnValue = tmpReturnValue; else returnValue = returnValue && tmpReturnValue; } } return returnValue; } // returns the first non-null response from all interceptors public Object instantiate(String entityName, EntityMode entityMode, Serializable id) { for (Interceptor i : interceptors) { Object o = i.instantiate(entityName, entityMode, id); if (o != null) return o; } return null; } public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { List<Integer> uniqueIndices = new LinkedList<Integer>(); for (Interceptor i : interceptors) { int[] indices = i.findDirty(entity, id, currentState, previousState, propertyNames, types); if (indices != null) { for (int index : indices) { if (!uniqueIndices.contains(index)) uniqueIndices.add(index); } } } if (uniqueIndices.isEmpty()) return null; // turn it back into an array and return it int[] uniquePrimitiveIndices = new int[uniqueIndices.size()]; for (int x = 0; x < uniqueIndices.size(); x++) uniquePrimitiveIndices[x] = uniqueIndices.get(x).intValue(); return uniquePrimitiveIndices; } // returns the first non-null name from the interceptors public String getEntityName(Object object) { for (Interceptor i : interceptors) { String name = i.getEntityName(object); if (name != null) return name; } return null; } public Object getEntity(String entityName, Serializable id) { for (Interceptor i : interceptors) { Object o = i.getEntity(entityName, id); if (o != null) return o; } return null; } public void afterTransactionBegin(Transaction tx) { for (Interceptor i : interceptors) i.afterTransactionBegin(tx); } public void afterTransactionCompletion(Transaction tx) { for (Interceptor i : interceptors) i.afterTransactionCompletion(tx); } public void beforeTransactionCompletion(Transaction tx) { for (Interceptor i : interceptors) i.beforeTransactionCompletion(tx); } // passes the sql returned from each previous onPrepareStatement onto the next public String onPrepareStatement(String sql) { for (Interceptor i : interceptors) { sql = i.onPrepareStatement(sql); } return sql; } public void onCollectionRemove(Object collection, Serializable key) throws CallbackException { for (Interceptor i : interceptors) i.onCollectionRemove(collection, key); } public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException { for (Interceptor i : interceptors) i.onCollectionRecreate(collection, key); } public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException { for (Interceptor i : interceptors) i.onCollectionUpdate(collection, key); } }