/*******************************************************************************
* 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");
}
}
}