/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.canvas.impl; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import org.simantics.utils.datastructures.hints.IHintListener; import org.simantics.utils.datastructures.hints.IHintObservable; import org.simantics.utils.datastructures.hints.IHintContext.Key; /** * @author Toni Kalajainen */ public class HintReflection { private final static HintListenerDefinition[] EMPTY = new HintListenerDefinition[0]; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface HintListener { Class Class(); String Field(); } /** * Scans an object for reflections of hint listeners *

* Example: * * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM") * public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { * ... * } * @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM") * public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { * ... * } * * @param obj object to scan * @return an array of painters and their priorities */ public static HintListenerDefinition[] getDependencies(final Object obj) { Map result = new HashMap(); Class clazz = obj.getClass(); _add(obj, clazz, result); //if (result==null) return EMPTY; return result.values().toArray(EMPTY); } private static void _add(final Object obj, Class clazz, Map result) { try { for (final Method m : clazz.getDeclaredMethods()) { HintListener anno = (HintListener) m .getAnnotation(HintListener.class); if (anno == null) continue; Class keyContainerClass = anno.Class(); assert (keyContainerClass != null); String fieldName = anno.Field(); assert (fieldName != null); Field field; field = keyContainerClass.getField(fieldName); assert (field != null); field.setAccessible(true); Object value = field.get(field != null); assert (value != null); assert (value instanceof Key); Key key = (Key) value; Class returnType = m.getReturnType(); assert (returnType == void.class); Class[] params = m.getParameterTypes(); assert (params.length == 4 || params.length == 3); assert (params[0].equals(IHintObservable.class)); assert (params[1].equals(Key.class)); assert (params[2].equals(Object.class)); if (params.length == 4) assert (params[3].equals(Object.class)); HintListenerDefinition def = result.get(key); if (def==null) { def = new HintListenerDefinition(key, obj); result.put(key, def); } m.setAccessible(true); if (params.length == 4) def.changedHandlerMethod = m; else def.removedHandlerMethod = m; } } catch (SecurityException e) { throw new Error(e); } catch (NoSuchFieldException e) { throw new Error(e); } catch (IllegalAccessException e) { throw new Error(e); } /* for (final Field f : clazz.getDeclaredFields()) { Class c = f.getType(); Dependency dep = (Dependency) f.getAnnotation(Dependency.class); Reference ref = (Reference) f.getAnnotation(Reference.class); if (dep==null && ref==null) continue; assert(ICanvasParticipant.class.isAssignableFrom( c )); assert(!(dep!=null && ref!=null)); ReferenceDefinition rd = new ReferenceDefinition(); rd.dependency = dep!=null; rd.field = f; rd.requirement = c; f.setAccessible(true); result.add(rd); } */ Class superClass = clazz.getSuperclass(); if (superClass!=null) _add(obj, superClass, result); } public final static class HintListenerDefinition implements IHintListener { public final Key key; public final Object object; public Method changedHandlerMethod; public Method removedHandlerMethod; public HintListenerDefinition(Key key, Object object) { this.key = key; this.object = object; } @Override public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) { if (changedHandlerMethod==null) return; try { changedHandlerMethod.invoke(object, sender, key, oldValue, newValue); } catch (IllegalArgumentException e) { throw new Error(e); } catch (IllegalAccessException e) { throw new Error(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } @Override public void hintRemoved(IHintObservable sender, Key key, Object oldValue) { if (removedHandlerMethod==null) return; try { removedHandlerMethod.invoke(object, sender, key, oldValue); } catch (IllegalArgumentException e) { throw new Error(e); } catch (IllegalAccessException e) { throw new Error(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } } }