]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/HintReflection.java
Sync git svn branch with SVN repository r33144.
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / canvas / impl / HintReflection.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 package org.simantics.g2d.canvas.impl;\r
13 \r
14 import java.lang.annotation.ElementType;\r
15 import java.lang.annotation.Retention;\r
16 import java.lang.annotation.RetentionPolicy;\r
17 import java.lang.annotation.Target;\r
18 import java.lang.reflect.Field;\r
19 import java.lang.reflect.InvocationTargetException;\r
20 import java.lang.reflect.Method;\r
21 import java.util.HashMap;\r
22 import java.util.Map;\r
23 \r
24 import org.simantics.utils.datastructures.hints.IHintListener;\r
25 import org.simantics.utils.datastructures.hints.IHintObservable;\r
26 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
27 \r
28 /**\r
29  * @author Toni Kalajainen\r
30  */\r
31 public class HintReflection {\r
32 \r
33         private final static HintListenerDefinition[] EMPTY = new HintListenerDefinition[0]; \r
34         \r
35         @Retention(RetentionPolicy.RUNTIME)\r
36         @Target(ElementType.METHOD)\r
37         public static @interface HintListener {\r
38                 Class<?>        Class();\r
39                 String          Field();                \r
40         }\r
41         \r
42         /**\r
43          * Scans an object for reflections of hint listeners  \r
44          * <p>\r
45          * Example:\r
46          * \r
47          *  @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")\r
48          *      public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
49          *     ...\r
50          *      }\r
51          *      @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")\r
52          *      public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { \r
53          *     ...\r
54          *  }\r
55          * \r
56          * @param obj object to scan\r
57          * @return an array of painters and their priorities\r
58          */\r
59     public static HintListenerDefinition[] getDependencies(final Object obj)\r
60         {\r
61                 Map<Key, HintListenerDefinition> result = new HashMap<Key, HintListenerDefinition>();\r
62                 Class<?> clazz = obj.getClass();\r
63                 _add(obj, clazz, result);\r
64                 //if (result==null) return EMPTY;\r
65                 return result.values().toArray(EMPTY);\r
66         }\r
67 \r
68     private static void _add(final Object obj, Class<?> clazz, Map<Key, HintListenerDefinition> result)\r
69         {\r
70                 try {\r
71                         for (final Method m : clazz.getDeclaredMethods()) {\r
72                                 HintListener anno = (HintListener) m\r
73                                                 .getAnnotation(HintListener.class);\r
74                                 if (anno == null)\r
75                                         continue;\r
76 \r
77                                 Class<?> keyContainerClass = anno.Class();\r
78                                 assert (keyContainerClass != null);\r
79                                 String fieldName = anno.Field();\r
80                                 assert (fieldName != null);\r
81                                 Field field;\r
82                                 field = keyContainerClass.getField(fieldName);\r
83                                 assert (field != null);\r
84                                 field.setAccessible(true);\r
85                                 Object value = field.get(field != null);\r
86                                 assert (value != null);\r
87                                 assert (value instanceof Key);\r
88                                 Key key = (Key) value;\r
89 \r
90                                 Class<?> returnType = m.getReturnType();\r
91                                 assert (returnType == void.class);\r
92                                 Class<?>[] params = m.getParameterTypes();\r
93                                 assert (params.length == 4 || params.length == 3);\r
94                                 assert (params[0].equals(IHintObservable.class));\r
95                                 assert (params[1].equals(Key.class));\r
96                                 assert (params[2].equals(Object.class));\r
97 \r
98                                 if (params.length == 4) \r
99                                         assert (params[3].equals(Object.class));\r
100 \r
101                                 HintListenerDefinition def = result.get(key);\r
102                                 if (def==null) {\r
103                                         def = new HintListenerDefinition(key, obj);\r
104                                         result.put(key, def);\r
105                                 }                                       \r
106                                 \r
107                                 m.setAccessible(true);                                  \r
108                                 if (params.length == 4)\r
109                                         def.changedHandlerMethod = m;\r
110                                 else\r
111                                         def.removedHandlerMethod = m;\r
112                         }\r
113                 } catch (SecurityException e) {\r
114                         throw new Error(e);\r
115                 } catch (NoSuchFieldException e) {\r
116                         throw new Error(e);\r
117                 } catch (IllegalAccessException e) {\r
118                         throw new Error(e);\r
119                 }\r
120                 /*\r
121                 for (final Field f : clazz.getDeclaredFields()) {\r
122                         Class c = f.getType();\r
123                         Dependency dep = (Dependency) f.getAnnotation(Dependency.class);\r
124                         Reference ref = (Reference) f.getAnnotation(Reference.class);\r
125                         if (dep==null && ref==null) continue;\r
126                         assert(ICanvasParticipant.class.isAssignableFrom( c ));                         \r
127                         assert(!(dep!=null && ref!=null));\r
128                         ReferenceDefinition rd = new ReferenceDefinition();\r
129                         rd.dependency = dep!=null;\r
130                         rd.field = f;\r
131                         rd.requirement = c;\r
132                         f.setAccessible(true);\r
133                         result.add(rd);\r
134                 }\r
135                 */\r
136                 \r
137                 Class<?> superClass = clazz.getSuperclass();\r
138                 if (superClass!=null)\r
139                         _add(obj, superClass, result);\r
140         }\r
141 \r
142         \r
143         public final static class HintListenerDefinition implements IHintListener {\r
144                 public final Key key;\r
145                 public final Object object;\r
146                 public Method changedHandlerMethod;\r
147                 public Method removedHandlerMethod;\r
148                 \r
149                 public HintListenerDefinition(Key key, Object object) {\r
150                         this.key = key;\r
151                         this.object = object;\r
152                 }\r
153                 \r
154                 @Override\r
155                 public void hintChanged(IHintObservable sender, Key key,\r
156                                 Object oldValue, Object newValue) {\r
157                         if (changedHandlerMethod==null) return;\r
158                         try {\r
159                                 changedHandlerMethod.invoke(object, sender, key, oldValue, newValue);\r
160                         } catch (IllegalArgumentException e) {\r
161                                 throw new Error(e);\r
162                         } catch (IllegalAccessException e) {\r
163                                 throw new Error(e);\r
164                         } catch (InvocationTargetException e) {\r
165                                 throw new RuntimeException(e.getCause());\r
166                         }\r
167                 }\r
168                 @Override\r
169                 public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {\r
170                         if (removedHandlerMethod==null) return;\r
171                         try {\r
172                                 removedHandlerMethod.invoke(object, sender, key, oldValue);\r
173                         } catch (IllegalArgumentException e) {\r
174                                 throw new Error(e);\r
175                         } catch (IllegalAccessException e) {\r
176                                 throw new Error(e);\r
177                         } catch (InvocationTargetException e) {\r
178                                 throw new RuntimeException(e.getCause());\r
179                         }\r
180                 }\r
181                 \r
182                 \r
183         }       \r
184         \r
185 }\r