/******************************************************************************* * 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 *******************************************************************************/ /* * * @author Toni Kalajainen */ 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.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.simantics.g2d.canvas.SGDesignation; import org.simantics.scenegraph.g2d.G2DParentNode; public class SGNodeReflection { @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface SGInit { SGDesignation designation() default SGDesignation.CANVAS; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface SGCleanup { } /** * Scans an object with reflection for all painter methods and returns * an array of ICanvasPainters and priorities. *

* The corresponding class of obj must contain methods that meet the following * criteria: * 1) no return value * 2) 1 argument, which is Graphics2D * 3) has annotation Painter * 4) may not throw any Exception * 5) method must be accessible *

* Example: * * @Painter(priority = Integer.MIN_VALUE) * public void prePaint(GraphicsContext gc) { * } * * @param obj object to scan * @return an array of painters and their priorities */ public static CanvasSGNodeDefinition[] getSGHandlers(final Object obj) { List result = new ArrayList(); Class clazz = obj.getClass(); for (final Method m : clazz.getMethods()) { SGInit initAnno = m.getAnnotation(SGInit.class); if (initAnno==null) continue; SGDesignation initDesignation = initAnno.designation(); Class returnType = m.getReturnType(); if (!returnType.equals(void.class)) throw new RuntimeException(clazz.getName()+"."+m.getName()+" return type is invalid"); @SuppressWarnings("rawtypes") Class[] argTypes = m.getParameterTypes(); if (argTypes.length!=1 || !argTypes[0].equals(G2DParentNode.class)) throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid arguments"); @SuppressWarnings("rawtypes") Class[] exceptionTypes = m.getExceptionTypes(); if (exceptionTypes.length!=0) throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid exceptions"); try { m.setAccessible(true); } catch (Throwable t) { t.printStackTrace(); throw new Error(t); } CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(m, initDesignation, null, obj); result.add(def); } for (final Method m : clazz.getMethods()) { SGCleanup cleanupAnno = m.getAnnotation(SGCleanup.class); if (cleanupAnno==null) continue; Class returnType = m.getReturnType(); if (!returnType.equals(void.class)) throw new RuntimeException(clazz.getName()+"."+m.getName()+" return type is invalid"); @SuppressWarnings("rawtypes") Class[] argTypes = m.getParameterTypes(); if (argTypes.length!=0) throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid arguments"); @SuppressWarnings("rawtypes") Class[] exceptionTypes = m.getExceptionTypes(); if (exceptionTypes.length!=0) throw new RuntimeException(clazz.getName()+"."+m.getName()+" invalid exceptions"); try { m.setAccessible(true); } catch (Throwable t) { t.printStackTrace(); throw new Error(t); } CanvasSGNodeDefinition def = new CanvasSGNodeDefinition(null, null, m, obj); result.add(def); } return result.toArray(new CanvasSGNodeDefinition[0]); } public static class CanvasSGNodeDefinition { // FIXME: own classes for init and cleanup public final Method initMethod; public final SGDesignation initDesignation; public final Method cleanupMethod; public final Object obj; public void init(G2DParentNode parent) { if(initMethod == null) return; try { initMethod.invoke(obj, parent); } catch (IllegalArgumentException e) { throw new Error(e); } catch (IllegalAccessException e) { throw new Error(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } public void cleanup() { if(cleanupMethod == null) return; try { cleanupMethod.invoke(obj); } catch (IllegalArgumentException e) { throw new Error(e); } catch (IllegalAccessException e) { throw new Error(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } } public CanvasSGNodeDefinition(Method initMethod, SGDesignation initDesignation, Method cleanupMethod, Object obj) { this.initMethod = initMethod; this.initDesignation = initDesignation; this.cleanupMethod = cleanupMethod; this.obj = obj; } @Override public String toString() { return String.format("%s %s %s %s", obj.getClass().getSimpleName(), initMethod != null ? initMethod.getName() : "no init method", initDesignation != null ? initDesignation.toString() : "no init designation", cleanupMethod != null ? cleanupMethod.getName() : "no cleanup method"); } } }