/*******************************************************************************
* Copyright (c) 2007, 2010 Association for Decentralized Information Management
* in Industry THTH ry.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
*******************************************************************************/
/*
*
* @author Toni Kalajainen
*/
package org.simantics.scenegraph.g2d.events;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @author Toni Kalajainen
*/
public class EventHandlerReflection {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface EventHandler {
int priority();
}
/**
* Scans an object with reflection for all event handler methods and returns
* an array of IEventHandler and priorities.
*
* The corresponding class of obj must contain methods that meet the
* following criteria: 1) must return boolean 2) 1 argument, which is Event
* 3) has annotation EventHandler 4) may not throw any Exception 5) method
* must be accessible
*
* Example:
*
* @EventHandler(priority = Integer.MAX_VALUE) public boolean
* handleEvent(Event e) { return false; }
*
* @param obj object to scan
* @return an array of painters and their priorities
*/
@SuppressWarnings("unchecked")
public static EventHandlerDefinition[] getEventHandlers(final Object obj) {
List result = new ArrayList();
Class> clazz = obj.getClass();
for (final Method m : clazz.getMethods()) {
EventHandler anno = (EventHandler) m.getAnnotation(EventHandler.class);
if (anno == null)
continue;
Class> returnType = m.getReturnType();
if (!returnType.equals(boolean.class))
throw new RuntimeException(clazz.getName() + "." + m.getName() + " return type is invalid");
@SuppressWarnings("rawtypes")
Class[] argTypes = m.getParameterTypes();
if (argTypes.length != 1 || !Event.class.isAssignableFrom(argTypes[0]))
throw new RuntimeException(clazz.getName() + "." + m.getName() + " invalid arguments");
@SuppressWarnings("rawtypes")
Class argClass = argTypes[0];
@SuppressWarnings("rawtypes")
Class[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes.length != 0)
throw new RuntimeException(clazz.getName() + "." + m.getName() + " invalid exceptions");
int priority = anno.priority();
try {
m.setAccessible(true);
} catch (Throwable t) {
t.printStackTrace();
continue;
}
final int eventMask = EventTypes.toTypeMask(argClass);
IEventHandler eventHandler = new IEventHandler() {
@Override
public int getEventMask() {
return eventMask;
}
@Override
public boolean handleEvent(Event e1) {
try {
return (Boolean) m.invoke(obj, e1);
} catch (IllegalArgumentException e) {
throw new Error(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e.getCause());
}
}
};
EventHandlerDefinition handler = new EventHandlerDefinition(obj, eventHandler, priority, argClass);
result.add(handler);
}
return result.toArray(new EventHandlerDefinition[0]);
}
public final static class EventHandlerDefinition {
public final Object obj;
public final IEventHandler origEventHandler;
public final IEventHandler eventHandler;
public final int priority;
public final Class eventSuperClass;
public EventHandlerDefinition(Object obj, IEventHandler eventHandler, int priority, Class eventSuperClass) {
this.obj = obj;
this.priority = priority;
this.eventSuperClass = eventSuperClass;
this.origEventHandler = eventHandler;
final int eventMask = EventTypes.toTypeMask(eventSuperClass);
if (eventSuperClass.equals(Event.class)) {
this.eventHandler = eventHandler;
} else {
this.eventHandler = new IEventHandler() {
@Override
public int getEventMask() {
return eventMask;
}
@Override
public boolean handleEvent(Event e) {
// Event masking already taken care of, no need to check eventMask
if (EventHandlerDefinition.this.eventSuperClass.isAssignableFrom(e.getClass()))
return EventHandlerDefinition.this.origEventHandler.handleEvent(e);
return false;
}
@Override
public String toString() {
return EventHandlerDefinition.this.toString();
}
};
}
}
@Override
public String toString() {
return String.format("[%11d] %s (%s)", priority, obj.getClass().getSimpleName(),
eventSuperClass.getSimpleName());
}
}
}