1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
14 * @author Toni Kalajainen
\r
16 package org.simantics.scenegraph.g2d.events;
\r
18 import java.lang.annotation.ElementType;
\r
19 import java.lang.annotation.Retention;
\r
20 import java.lang.annotation.RetentionPolicy;
\r
21 import java.lang.annotation.Target;
\r
22 import java.lang.reflect.InvocationTargetException;
\r
23 import java.lang.reflect.Method;
\r
24 import java.util.ArrayList;
\r
25 import java.util.List;
\r
28 * @author Toni Kalajainen
\r
30 public class EventHandlerReflection {
\r
32 @Retention(RetentionPolicy.RUNTIME)
\r
33 @Target(ElementType.METHOD)
\r
34 public static @interface EventHandler {
\r
39 * Scans an object with reflection for all event handler methods and returns
\r
40 * an array of IEventHandler and priorities.
\r
42 * The corresponding class of obj must contain methods that meet the
\r
43 * following criteria: 1) must return boolean 2) 1 argument, which is Event
\r
44 * 3) has annotation EventHandler 4) may not throw any Exception 5) method
\r
45 * must be accessible
\r
49 * @EventHandler(priority = Integer.MAX_VALUE) public boolean
\r
50 * handleEvent(Event e) { return false; }
\r
52 * @param obj object to scan
\r
53 * @return an array of painters and their priorities
\r
55 @SuppressWarnings("unchecked")
\r
56 public static EventHandlerDefinition[] getEventHandlers(final Object obj) {
\r
57 List<EventHandlerDefinition> result = new ArrayList<EventHandlerDefinition>();
\r
58 Class<?> clazz = obj.getClass();
\r
60 for (final Method m : clazz.getMethods()) {
\r
61 EventHandler anno = (EventHandler) m.getAnnotation(EventHandler.class);
\r
65 Class<?> returnType = m.getReturnType();
\r
66 if (!returnType.equals(boolean.class))
\r
67 throw new RuntimeException(clazz.getName() + "." + m.getName() + " return type is invalid");
\r
69 @SuppressWarnings("rawtypes")
\r
70 Class[] argTypes = m.getParameterTypes();
\r
71 if (argTypes.length != 1 || !Event.class.isAssignableFrom(argTypes[0]))
\r
72 throw new RuntimeException(clazz.getName() + "." + m.getName() + " invalid arguments");
\r
74 @SuppressWarnings("rawtypes")
\r
75 Class argClass = argTypes[0];
\r
77 @SuppressWarnings("rawtypes")
\r
78 Class[] exceptionTypes = m.getExceptionTypes();
\r
79 if (exceptionTypes.length != 0)
\r
80 throw new RuntimeException(clazz.getName() + "." + m.getName() + " invalid exceptions");
\r
82 int priority = anno.priority();
\r
85 m.setAccessible(true);
\r
86 } catch (Throwable t) {
\r
87 t.printStackTrace();
\r
91 final int eventMask = EventTypes.toTypeMask(argClass);
\r
93 IEventHandler eventHandler = new IEventHandler() {
\r
95 public int getEventMask() {
\r
99 public boolean handleEvent(Event e1) {
\r
101 return (Boolean) m.invoke(obj, e1);
\r
102 } catch (IllegalArgumentException e) {
\r
103 throw new Error(e);
\r
104 } catch (IllegalAccessException e) {
\r
105 throw new RuntimeException(e);
\r
106 } catch (InvocationTargetException e) {
\r
107 throw new RuntimeException(e);
\r
111 EventHandlerDefinition handler = new EventHandlerDefinition(obj, eventHandler, priority, argClass);
\r
112 result.add(handler);
\r
115 return result.toArray(new EventHandlerDefinition[0]);
\r
118 public final static class EventHandlerDefinition {
\r
119 public final Object obj;
\r
120 public final IEventHandler origEventHandler;
\r
121 public final IEventHandler eventHandler;
\r
122 public final int priority;
\r
123 public final Class<Event> eventSuperClass;
\r
125 public EventHandlerDefinition(Object obj, IEventHandler eventHandler, int priority, Class<Event> eventSuperClass) {
\r
127 this.priority = priority;
\r
128 this.eventSuperClass = eventSuperClass;
\r
129 this.origEventHandler = eventHandler;
\r
130 final int eventMask = EventTypes.toTypeMask(eventSuperClass);
\r
131 if (eventSuperClass.equals(Event.class)) {
\r
132 this.eventHandler = eventHandler;
\r
134 this.eventHandler = new IEventHandler() {
\r
136 public int getEventMask() {
\r
141 public boolean handleEvent(Event e) {
\r
142 // Event masking already taken care of, no need to check eventMask
\r
143 if (EventHandlerDefinition.this.eventSuperClass.isAssignableFrom(e.getClass()))
\r
144 return EventHandlerDefinition.this.origEventHandler.handleEvent(e);
\r
149 public String toString() {
\r
150 return EventHandlerDefinition.this.toString();
\r
157 public String toString() {
\r
158 return String.format("[%11d] %s (%s)", priority, obj.getClass().getSimpleName(),
\r
159 eventSuperClass.getSimpleName());
\r