]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/events/EventHandlerReflection.java
Sync git svn branch with SVN repository r33144.
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / events / EventHandlerReflection.java
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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 /*\r
13  *\r
14  * @author Toni Kalajainen\r
15  */\r
16 package org.simantics.scenegraph.g2d.events;\r
17 \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
26 \r
27 /**\r
28  * @author Toni Kalajainen\r
29  */\r
30 public class EventHandlerReflection {\r
31 \r
32     @Retention(RetentionPolicy.RUNTIME)\r
33     @Target(ElementType.METHOD)\r
34     public static @interface EventHandler {\r
35         int priority();\r
36     }\r
37 \r
38     /**\r
39      * Scans an object with reflection for all event handler methods and returns\r
40      * an array of IEventHandler and priorities.\r
41      * <p>\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
46      * <p>\r
47      * Example:\r
48      * \r
49      * @EventHandler(priority = Integer.MAX_VALUE) public boolean\r
50      *                        handleEvent(Event e) { return false; }\r
51      * \r
52      * @param obj object to scan\r
53      * @return an array of painters and their priorities\r
54      */\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
59 \r
60         for (final Method m : clazz.getMethods()) {\r
61             EventHandler anno = (EventHandler) m.getAnnotation(EventHandler.class);\r
62             if (anno == null)\r
63                 continue;\r
64 \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
68 \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
73 \r
74             @SuppressWarnings("rawtypes")\r
75             Class argClass = argTypes[0];\r
76 \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
81 \r
82             int priority = anno.priority();\r
83 \r
84             try {\r
85                 m.setAccessible(true);\r
86             } catch (Throwable t) {\r
87                 t.printStackTrace();\r
88                 continue;\r
89             }\r
90 \r
91             final int eventMask = EventTypes.toTypeMask(argClass);\r
92 \r
93             IEventHandler eventHandler = new IEventHandler() {\r
94                 @Override\r
95                 public int getEventMask() {\r
96                     return eventMask;\r
97                 }\r
98                 @Override\r
99                 public boolean handleEvent(Event e1) {\r
100                     try {\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.getCause());\r
108                     }\r
109                 }\r
110             };\r
111             EventHandlerDefinition handler = new EventHandlerDefinition(obj, eventHandler, priority, argClass);\r
112             result.add(handler);\r
113         }\r
114 \r
115         return result.toArray(new EventHandlerDefinition[0]);\r
116     }\r
117 \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
124 \r
125         public EventHandlerDefinition(Object obj, IEventHandler eventHandler, int priority, Class<Event> eventSuperClass) {\r
126             this.obj = obj;\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
133             } else {\r
134                 this.eventHandler = new IEventHandler() {\r
135                     @Override\r
136                     public int getEventMask() {\r
137                         return eventMask;\r
138                     }\r
139 \r
140                     @Override\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
145                         return false;\r
146                     }\r
147 \r
148                     @Override\r
149                     public String toString() {\r
150                         return EventHandlerDefinition.this.toString();\r
151                     }\r
152                 };\r
153             }\r
154         }\r
155 \r
156         @Override\r
157         public String toString() {\r
158             return String.format("[%11d] %s (%s)", priority, obj.getClass().getSimpleName(),\r
159                     eventSuperClass.getSimpleName());\r
160         }\r
161     }\r
162 \r
163 }\r