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
12 package org.simantics.g2d.canvas.impl;
\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
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
29 * @author Toni Kalajainen
\r
31 public class HintReflection {
\r
33 private final static HintListenerDefinition[] EMPTY = new HintListenerDefinition[0];
\r
35 @Retention(RetentionPolicy.RUNTIME)
\r
36 @Target(ElementType.METHOD)
\r
37 public static @interface HintListener {
\r
43 * Scans an object for reflections of hint listeners
\r
47 * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")
\r
48 * public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
\r
51 * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")
\r
52 * public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {
\r
56 * @param obj object to scan
\r
57 * @return an array of painters and their priorities
\r
59 public static HintListenerDefinition[] getDependencies(final Object obj)
\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
68 private static void _add(final Object obj, Class<?> clazz, Map<Key, HintListenerDefinition> result)
\r
71 for (final Method m : clazz.getDeclaredMethods()) {
\r
72 HintListener anno = (HintListener) m
\r
73 .getAnnotation(HintListener.class);
\r
77 Class<?> keyContainerClass = anno.Class();
\r
78 assert (keyContainerClass != null);
\r
79 String fieldName = anno.Field();
\r
80 assert (fieldName != null);
\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
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
98 if (params.length == 4)
\r
99 assert (params[3].equals(Object.class));
\r
101 HintListenerDefinition def = result.get(key);
\r
103 def = new HintListenerDefinition(key, obj);
\r
104 result.put(key, def);
\r
107 m.setAccessible(true);
\r
108 if (params.length == 4)
\r
109 def.changedHandlerMethod = m;
\r
111 def.removedHandlerMethod = m;
\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
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
131 rd.requirement = c;
\r
132 f.setAccessible(true);
\r
137 Class<?> superClass = clazz.getSuperclass();
\r
138 if (superClass!=null)
\r
139 _add(obj, superClass, result);
\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
149 public HintListenerDefinition(Key key, Object object) {
\r
151 this.object = object;
\r
155 public void hintChanged(IHintObservable sender, Key key,
\r
156 Object oldValue, Object newValue) {
\r
157 if (changedHandlerMethod==null) return;
\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
169 public void hintRemoved(IHintObservable sender, Key key, Object oldValue) {
\r
170 if (removedHandlerMethod==null) return;
\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