/*
* ome.security.basic.EventListenersFactoryBean
*
* Copyright 2006 University of Dundee. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.security.basic;
// Java imports
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import ome.security.ACLEventListener;
import ome.security.ACLVoter;
import ome.tools.hibernate.EventMethodInterceptor;
import ome.tools.hibernate.ReloadingRefreshEventListener;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.event.EventListeners;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
/**
* configuring all the possible {@link EventListeners event listeners} within
* XML can be cumbersome.
*/
public class EventListenersFactoryBean extends AbstractFactoryBean {
private final EventListeners eventListeners = new EventListeners();
private final Map<String, LinkedList<Object>> map = new HashMap<String, LinkedList<Object>>();
private final CurrentDetails cd;
private final TokenHolder th;
private final ACLVoter voter;
private final OmeroInterceptor interceptor;
// ~ FactoryBean
// =========================================================================
public EventListenersFactoryBean(CurrentDetails cd, TokenHolder th,
ACLVoter voter, OmeroInterceptor interceptor) {
this.cd = cd;
this.th = th;
this.voter = voter;
this.interceptor = interceptor;
}
/**
* this {@link FactoryBean} produces a {@link Map} instance for use in
* {@link LocalSessionFactoryBean#setEventListeners(Map)}
*/
@Override
public Class getObjectType() {
return Map.class;
}
/**
* being a singleton implies that this {@link FactoryBean} will only ever
* create one instance.
*/
@Override
public boolean isSingleton() {
return true;
}
/**
* First, adds all default listeners. These are then overwritten.
*/
@Override
protected Object createInstance() throws Exception {
put("auto-flush", eventListeners.getAutoFlushEventListeners());
put("merge", eventListeners.getMergeEventListeners());
put("create", eventListeners.getPersistEventListeners());
put("create-onflush", eventListeners.getPersistOnFlushEventListeners());
put("delete", eventListeners.getDeleteEventListeners());
put("dirty-check", eventListeners.getDirtyCheckEventListeners());
put("evict", eventListeners.getEvictEventListeners());
put("flush", eventListeners.getFlushEventListeners());
put("flush-entity", eventListeners.getFlushEntityEventListeners());
put("load", eventListeners.getLoadEventListeners());
put("load-collection", eventListeners
.getInitializeCollectionEventListeners());
put("lock", eventListeners.getLockEventListeners());
put("refresh", eventListeners.getRefreshEventListeners());
put("replicate", eventListeners.getReplicateEventListeners());
put("save-update", eventListeners.getSaveOrUpdateEventListeners());
put("save", eventListeners.getSaveEventListeners());
put("update", eventListeners.getUpdateEventListeners());
put("pre-load", eventListeners.getPreLoadEventListeners());
put("pre-update", eventListeners.getPreUpdateEventListeners());
put("pre-delete", eventListeners.getPreDeleteEventListeners());
put("pre-insert", eventListeners.getPreInsertEventListeners());
put("post-load", eventListeners.getPostLoadEventListeners());
put("post-update", eventListeners.getPostUpdateEventListeners());
put("post-delete", eventListeners.getPostDeleteEventListeners());
put("post-insert", eventListeners.getPostInsertEventListeners());
put("post-commit-update", eventListeners
.getPostCommitUpdateEventListeners());
put("post-commit-delete", eventListeners
.getPostCommitDeleteEventListeners());
put("post-commit-insert", eventListeners
.getPostCommitInsertEventListeners());
assertHasAllKeys();
overrides();
additions();
return map;
}
// ~ Configuration
// =========================================================================
protected boolean debugAll = false;
/** for setter injection */
public void setDebugAll(boolean debug) {
this.debugAll = debug;
}
protected void overrides() {
override("merge", new MergeEventListener(cd, th));
override("save", new SaveEventListener(cd, th));
override(new String[] { "replicate", "update" }, getDisablingProxy());
}
protected void additions() {
// This must be prepended because it updates the alreadyRefreshed
// cache before passing the event on the default listener.
prepend("refresh", new ReloadingRefreshEventListener());
for (String key : map.keySet()) {
final String k = key;
EventMethodInterceptor emi = new EventMethodInterceptor(
new EventMethodInterceptor.DisableAction() {
@Override
protected boolean disabled(MethodInvocation mi) {
return cd.isDisabled(k);// getType(mi));
}
});
append(key, getProxy(emi));
}
if (voter != null) {
ACLEventListener acl = new ACLEventListener(voter);
append("post-load", acl);
append("pre-insert", acl);
append("pre-update", acl);
append("pre-delete", acl);
}
EventLogListener ell = new ome.security.basic.EventLogListener(cd);
append("post-insert", ell);
append("post-update", ell);
append("post-delete", ell);
UpdateEventListener uel = new UpdateEventListener(cd);
append("pre-update", uel);
if (debugAll) {
Object debug = getDebuggingProxy();
for (String key : map.keySet()) {
map.get(key).add(debug);
}
}
}
// ~ Helpers
// =========================================================================
private void assertHasAllKeys() {
// eventListeners has only private state. :(
}
private Class[] allInterfaces() {
Set<Class> set = new HashSet<Class>();
for (String str : map.keySet()) {
Class iface = eventListeners.getListenerClassFor(str);
if (iface == null) {
logger.warn("No interface found for " + str);
}
else {
set.add(iface);
}
}
return set.toArray(new Class[set.size()]);
}
private Object getDisablingProxy() {
EventMethodInterceptor disable = new EventMethodInterceptor(
new EventMethodInterceptor.DisableAction());
return getProxy(disable);
}
private Object getDebuggingProxy() {
EventMethodInterceptor debug = new EventMethodInterceptor();
debug.setDebug(true);
return getProxy(debug);
}
private Object getProxy(Advice... adviceArray) {
ProxyFactory factory = new ProxyFactory();
factory.setInterfaces(allInterfaces());
for (Advice advice : adviceArray) {
factory.addAdvice(advice);
}
return factory.getProxy();
}
// ~ Collection methods
// =========================================================================
/** calls override for each key */
protected void override(String[] keys, Object object) {
for (String key : keys) {
override(key, object);
}
}
/** first re-initializes the list for key, and then adds object */
protected void override(String key, Object object) {
put(key, null);
append(key, object);
}
/**
* appends the objects to the existing list identified by key. If no list is
* found, initializes. If there are no objects, just initializes if
* necessary.
*/
protected void append(String key, Object... objs) {
LinkedList<Object> l = map.get(key);
if (l == null) {
put(key, null);
l = map.get(key);
}
if (objs == null) {
return;
}
for (Object object : objs) {
l.addLast(object);
}
}
/**
* adds the objects to the existing list identified by key. If no list is
* found, initializes. If there are no objects, just initializes if
* necessary.
*/
protected void prepend(String key, Object... objs) {
LinkedList<Object> l = map.get(key);
if (l == null) {
put(key, null);
l = map.get(key);
}
if (objs == null) {
return;
}
for (Object object : objs) {
l.addFirst(object);
}
}
/**
* replaces the key with the provided objects or an empty list if none
* provided
*/
protected void put(String key, Object[] objs) {
LinkedList<Object> list = new LinkedList<Object>();
if (objs != null) {
Collections.addAll(list, objs);
}
map.put(key, list);
}
}