/* This file is part of the db4o object database http://www.db4o.com
Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com
db4o is free software; you can redistribute it and/or modify it under
the terms of version 3 of the GNU General Public License as published
by the Free Software Foundation.
db4o is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see http://www.gnu.org/licenses/. */
package com.db4o.internal;
import com.db4o.foundation.*;
import com.db4o.reflect.*;
/** @exclude */
public final class EventDispatchers {
public static final EventDispatcher NULL_DISPATCHER = new EventDispatcher() {
public boolean dispatch(Transaction trans, Object obj, int eventID) {
return true;
}
public boolean hasEventRegistered(int eventID) {
return false;
}
};
private static final String[] events = {
"objectCanDelete",
"objectOnDelete",
"objectOnActivate",
"objectOnDeactivate",
"objectOnNew",
"objectOnUpdate",
"objectCanActivate",
"objectCanDeactivate",
"objectCanNew",
"objectCanUpdate"
};
static final int CAN_DELETE = 0;
static final int DELETE = 1;
static final int ACTIVATE = 2;
static final int DEACTIVATE = 3;
static final int NEW = 4;
public static final int UPDATE = 5;
static final int CAN_ACTIVATE = 6;
static final int CAN_DEACTIVATE = 7;
static final int CAN_NEW = 8;
static final int CAN_UPDATE = 9;
static final int DELETE_COUNT = 2;
static final int COUNT = 10;
private static class EventDispatcherImpl implements EventDispatcher {
private final ReflectMethod[] methods;
public EventDispatcherImpl(ReflectMethod[] methods_) {
methods = methods_;
}
public boolean hasEventRegistered(int eventID) {
return methods[eventID] != null;
}
public boolean dispatch(Transaction trans, Object obj, int eventID) {
if (methods[eventID] == null) {
return true;
}
Object[] parameters = new Object[] { trans.objectContainer() };
ObjectContainerBase container = trans.container();
int stackDepth = container.stackDepth();
int topLevelCallId = container.topLevelCallId();
container.stackDepth(0);
try {
Object res = methods[eventID].invoke(obj, parameters);
if (res instanceof Boolean) {
return ((Boolean) res).booleanValue();
}
} finally {
container.stackDepth(stackDepth);
container.topLevelCallId(topLevelCallId);
}
return true;
}
}
public static EventDispatcher forClass(ObjectContainerBase container, ReflectClass classReflector) {
if (container == null || classReflector == null) {
throw new ArgumentNullException();
}
if (!container.dispatchsEvents()) {
return NULL_DISPATCHER;
}
int count = eventCountFor(container);
if (count == 0) {
return NULL_DISPATCHER;
}
final ReflectMethod[] handlers = eventHandlerTableFor(container, classReflector);
return hasEventHandler(handlers)
? new EventDispatcherImpl(handlers)
: NULL_DISPATCHER;
}
private static ReflectMethod[] eventHandlerTableFor(ObjectContainerBase container, ReflectClass classReflector) {
ReflectClass[] parameterClasses = { container._handlers.ICLASS_OBJECTCONTAINER };
ReflectMethod[] methods = new ReflectMethod[COUNT];
for (int i = COUNT - 1; i >= 0; i--) {
ReflectMethod method = classReflector.getMethod(events[i], parameterClasses);
if (null == method) {
method = classReflector.getMethod(toPascalCase(events[i]), parameterClasses);
}
if (method != null) {
methods[i] = method;
}
}
return methods;
}
private static boolean hasEventHandler(ReflectMethod[] methods) {
return Iterators.any(Iterators.iterate(methods), new Predicate4() {
public boolean match(Object candidate) {
return candidate != null;
}});
}
private static int eventCountFor(ObjectContainerBase container) {
CallBackMode callbackMode = container.configImpl().callbackMode();
if(callbackMode == CallBackMode.ALL) {
return COUNT;
}
if(callbackMode == CallBackMode.DELETE_ONLY) {
return DELETE_COUNT;
}
return 0;
}
private static String toPascalCase(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}
}