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.g2d.canvas.impl;
\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
27 import org.simantics.g2d.canvas.SGDesignation;
\r
28 import org.simantics.scenegraph.g2d.G2DParentNode;
\r
31 public class SGNodeReflection {
\r
33 @Retention(RetentionPolicy.RUNTIME)
\r
34 @Target(ElementType.METHOD)
\r
35 public static @interface SGInit {
\r
36 SGDesignation designation() default SGDesignation.CANVAS;
\r
39 @Retention(RetentionPolicy.RUNTIME)
\r
40 @Target(ElementType.METHOD)
\r
41 public static @interface SGCleanup {
\r
45 * Scans an object with reflection for all painter methods and returns
\r
46 * an array of ICanvasPainters and priorities.
\r
48 * The corresponding class of obj must contain methods that meet the following
\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
58 * @Painter(priority = Integer.MIN_VALUE)
\r
59 * public void prePaint(GraphicsContext gc) {
\r
62 * @param obj object to scan
\r
63 * @return an array of painters and their priorities
\r
65 public static CanvasSGNodeDefinition[] getSGHandlers(final Object obj)
\r
67 List<CanvasSGNodeDefinition> result = new ArrayList<CanvasSGNodeDefinition>();
\r
68 Class<?> clazz = obj.getClass();
\r
70 for (final Method m : clazz.getMethods()) {
\r
71 SGInit initAnno = m.getAnnotation(SGInit.class);
\r
72 if (initAnno==null) continue;
\r
74 SGDesignation initDesignation = initAnno.designation();
\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
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
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
91 m.setAccessible(true);
\r
92 } catch (Throwable t)
\r
94 t.printStackTrace();
\r
98 CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(m, initDesignation, null, obj);
\r
102 for (final Method m : clazz.getMethods()) {
\r
103 SGCleanup cleanupAnno = m.getAnnotation(SGCleanup.class);
\r
104 if (cleanupAnno==null) continue;
\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
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
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
121 m.setAccessible(true);
\r
122 } catch (Throwable t)
\r
124 t.printStackTrace();
\r
125 throw new Error(t);
\r
128 CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(null, null, m, obj);
\r
132 return result.toArray(new CanvasSGNodeDefinition[0]);
\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
141 public void init(G2DParentNode parent) {
\r
142 if(initMethod == null) return;
\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
153 public void cleanup() {
\r
154 if(cleanupMethod == null) return;
\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
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
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