/**
* 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.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.hibernate.CallbackException;
import org.hibernate.EntityMode;
import org.hibernate.Interceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 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 Logger log = LoggerFactory.getLogger(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);
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
for (Interceptor i : interceptors) {
i.onDelete(entity, id, state, propertyNames, types);
}
}
@Override
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;
}
@Override
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;
}
@Override
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;
}
@Override
public void postFlush(Iterator entities) {
for (Interceptor i : interceptors) {
i.postFlush(entities);
}
}
@Override
public void preFlush(Iterator entities) {
for (Interceptor i : interceptors) {
i.preFlush(entities);
}
}
@Override
public Boolean isTransient(Object entity) {
// by default let hibernate figure it out
Boolean returnValue = null;
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
@Override
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;
}
@Override
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
@Override
public String getEntityName(Object object) {
for (Interceptor i : interceptors) {
String name = i.getEntityName(object);
if (name != null) {
return name;
}
}
return null;
}
@Override
public Object getEntity(String entityName, Serializable id) {
for (Interceptor i : interceptors) {
Object o = i.getEntity(entityName, id);
if (o != null) {
return o;
}
}
return null;
}
@Override
public void afterTransactionBegin(Transaction tx) {
for (Interceptor i : interceptors) {
i.afterTransactionBegin(tx);
}
}
@Override
public void afterTransactionCompletion(Transaction tx) {
for (Interceptor i : interceptors) {
i.afterTransactionCompletion(tx);
}
}
@Override
public void beforeTransactionCompletion(Transaction tx) {
for (Interceptor i : interceptors) {
i.beforeTransactionCompletion(tx);
}
}
// passes the sql returned from each previous onPrepareStatement onto the next
@Override
public String onPrepareStatement(String sql) {
for (Interceptor i : interceptors) {
sql = i.onPrepareStatement(sql);
}
return sql;
}
@Override
public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
for (Interceptor i : interceptors) {
i.onCollectionRemove(collection, key);
}
}
@Override
public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
for (Interceptor i : interceptors) {
i.onCollectionRecreate(collection, key);
}
}
@Override
public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
for (Interceptor i : interceptors) {
i.onCollectionUpdate(collection, key);
}
}
}