]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/canvas/impl/SGNodeReflection.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / canvas / impl / SGNodeReflection.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.g2d.canvas.impl;\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 import org.simantics.g2d.canvas.SGDesignation;\r
28 import org.simantics.scenegraph.g2d.G2DParentNode;\r
29 \r
30 \r
31 public class SGNodeReflection {\r
32 \r
33     @Retention(RetentionPolicy.RUNTIME)\r
34     @Target(ElementType.METHOD)\r
35     public static @interface SGInit {\r
36         SGDesignation designation() default SGDesignation.CANVAS;\r
37     }\r
38 \r
39     @Retention(RetentionPolicy.RUNTIME)\r
40     @Target(ElementType.METHOD)\r
41     public static @interface SGCleanup {\r
42     }\r
43 \r
44     /**\r
45      * Scans an object with reflection for all painter methods and returns\r
46      * an array of ICanvasPainters and priorities.\r
47      * <p>\r
48      * The corresponding class of obj must contain methods that meet the following\r
49      * criteria:\r
50      *  1) no return value\r
51      *  2) 1 argument, which is Graphics2D\r
52      *  3) has annotation Painter\r
53      *  4) may not throw any Exception\r
54      *  5) method must be accessible\r
55      * <p>\r
56      * Example:\r
57      *\r
58      *  @Painter(priority = Integer.MIN_VALUE)\r
59      *  public void prePaint(GraphicsContext gc) {\r
60      *  }\r
61      *\r
62      * @param obj object to scan\r
63      * @return an array of painters and their priorities\r
64      */\r
65     public static CanvasSGNodeDefinition[] getSGHandlers(final Object obj)\r
66     {\r
67         List<CanvasSGNodeDefinition> result = new ArrayList<CanvasSGNodeDefinition>();\r
68         Class<?> clazz = obj.getClass();\r
69 \r
70         for (final Method m : clazz.getMethods()) {\r
71             SGInit initAnno = m.getAnnotation(SGInit.class);\r
72             if (initAnno==null) continue;\r
73 \r
74             SGDesignation initDesignation = initAnno.designation();\r
75 \r
76             Class<?> returnType = m.getReturnType();\r
77             if (!returnType.equals(void.class))\r
78                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" return type is invalid");\r
79 \r
80             @SuppressWarnings("rawtypes")\r
81             Class[] argTypes = m.getParameterTypes();\r
82             if (argTypes.length!=1 || !argTypes[0].equals(G2DParentNode.class))\r
83                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid arguments");\r
84 \r
85             @SuppressWarnings("rawtypes")\r
86             Class[] exceptionTypes = m.getExceptionTypes();\r
87             if (exceptionTypes.length!=0)\r
88                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid exceptions");\r
89 \r
90             try {\r
91                 m.setAccessible(true);\r
92             } catch (Throwable t)\r
93             {\r
94                 t.printStackTrace();\r
95                 throw new Error(t);\r
96             }\r
97 \r
98             CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(m, initDesignation, null, obj);\r
99             result.add(def);\r
100         }\r
101 \r
102         for (final Method m : clazz.getMethods()) {\r
103             SGCleanup cleanupAnno = m.getAnnotation(SGCleanup.class);\r
104             if (cleanupAnno==null) continue;\r
105 \r
106             Class<?> returnType = m.getReturnType();\r
107             if (!returnType.equals(void.class))\r
108                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" return type is invalid");\r
109 \r
110             @SuppressWarnings("rawtypes")\r
111             Class[] argTypes = m.getParameterTypes();\r
112             if (argTypes.length!=0)\r
113                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid arguments");\r
114 \r
115             @SuppressWarnings("rawtypes")\r
116             Class[] exceptionTypes = m.getExceptionTypes();\r
117             if (exceptionTypes.length!=0)\r
118                 throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid exceptions");\r
119 \r
120             try {\r
121                 m.setAccessible(true);\r
122             } catch (Throwable t)\r
123             {\r
124                 t.printStackTrace();\r
125                 throw new Error(t);\r
126             }\r
127 \r
128             CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(null, null, m, obj);\r
129             result.add(def);\r
130         }\r
131 \r
132         return result.toArray(new CanvasSGNodeDefinition[0]);\r
133     }\r
134 \r
135     public static class CanvasSGNodeDefinition { // FIXME: own classes for init and cleanup\r
136         public final Method initMethod;\r
137         public final SGDesignation initDesignation;\r
138         public final Method cleanupMethod;\r
139         public final Object obj;\r
140 \r
141         public void init(G2DParentNode parent) {\r
142             if(initMethod == null) return;\r
143             try {\r
144                 initMethod.invoke(obj, parent);\r
145             } catch (IllegalArgumentException e) {\r
146                 throw new Error(e);\r
147             } catch (IllegalAccessException e) {\r
148                 throw new Error(e);\r
149             } catch (InvocationTargetException e) {\r
150                 throw new RuntimeException(e.getCause());\r
151             }\r
152         }\r
153         public void cleanup() {\r
154             if(cleanupMethod == null) return;\r
155             try {\r
156                 cleanupMethod.invoke(obj);\r
157             } catch (IllegalArgumentException e) {\r
158                 throw new Error(e);\r
159             } catch (IllegalAccessException e) {\r
160                 throw new Error(e);\r
161             } catch (InvocationTargetException e) {\r
162                 throw new RuntimeException(e.getCause());\r
163             }\r
164         }\r
165         public CanvasSGNodeDefinition(Method initMethod, SGDesignation initDesignation, Method cleanupMethod, Object obj) {\r
166             this.initMethod = initMethod;\r
167             this.initDesignation = initDesignation;\r
168             this.cleanupMethod = cleanupMethod;\r
169             this.obj = obj;\r
170         }\r
171         @Override\r
172         public String toString() {\r
173             return String.format("%s %s %s %s",\r
174                     obj.getClass().getSimpleName(),\r
175                     initMethod != null ? initMethod.getName() : "no init method",\r
176                     initDesignation != null ? initDesignation.toString() : "no init designation",\r
177                     cleanupMethod != null ? cleanupMethod.getName() : "no cleanup method");\r
178         }\r
179     }\r
180 }\r