/******************************************************************************* * 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()); } } }