Lucio Lelii 2017-10-06 13:21:32 +00:00
parent b95572fe28
commit 543f765d09
4 changed files with 225 additions and 223 deletions

View File

@ -11,7 +11,7 @@
<groupId>org.gcube.dataanalysis</groupId>
<artifactId>52n-wps-algorithm-gcube</artifactId>
<name>52North WPS Algorithm API modified for gcube</name>
<version>3.6.1-SNAPSHOT</version>
<version>3.6.2-SNAPSHOT</version>
<description>API for implementation of algorithms to be exposed as web processes</description>
<licenses>
@ -76,11 +76,6 @@
</plugins>
</build>
<dependencies>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>
<dependency>
<groupId>org.n52.wps</groupId>
<artifactId>52n-wps-commons</artifactId>

View File

@ -29,11 +29,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.n52.wps.algorithm.annotation.AnnotationBinding.ExecuteMethodBinding;
import org.n52.wps.algorithm.annotation.AnnotationBinding.InputBinding;
import org.n52.wps.algorithm.annotation.AnnotationBinding.OutputBinding;
@ -57,224 +52,223 @@ import org.slf4j.LoggerFactory;
* @author tkunicki
*/
public class AnnotatedAlgorithmIntrospector {
private final static Logger LOGGER = LoggerFactory.getLogger(AnnotatedAlgorithmIntrospector.class);
private final static List<InputAnnotationParser<?,Field,?>> INPUT_FIELD_PARSERS;
private final static List<InputAnnotationParser<?,Method,?>> INPUT_METHOD_PARSERS;
private final static List<OutputAnnotationParser<?,Field,?>> OUTPUT_FIELD_PARSERS;
private final static List<OutputAnnotationParser<?,Method,?>> OUTPUT_METHOD_PARSERS;
private final static ExecuteAnnotationParser PROCESS_PARSER;
static {
List<InputAnnotationParser<?,Field,?>> inputFieldParsers =
new ArrayList<InputAnnotationParser<?,Field,?>>();
inputFieldParsers.add(new LiteralDataInputFieldAnnotationParser());
inputFieldParsers.add(new ComplexDataInputFieldAnnotationParser());
INPUT_FIELD_PARSERS = Collections.unmodifiableList(inputFieldParsers);
List<InputAnnotationParser<?,Method,?>> inputMethodParsers =
new ArrayList<InputAnnotationParser<?,Method,?>>();
inputMethodParsers.add(new LiteralDataInputMethodAnnotationParser());
inputMethodParsers.add(new ComplexDataInputMethodAnnotationParser());
INPUT_METHOD_PARSERS = Collections.unmodifiableList(inputMethodParsers);
List<OutputAnnotationParser<?,Field,?>> outputFieldParsers =
new ArrayList<OutputAnnotationParser<?,Field,?>>();
outputFieldParsers.add(new LiteralDataOutputFieldAnnotationParser());
outputFieldParsers.add(new ComplexDataOutputFieldAnnotationParser());
OUTPUT_FIELD_PARSERS = Collections.unmodifiableList(outputFieldParsers);
List<OutputAnnotationParser<?,Method,?>> outputMethodParsers =
new ArrayList<OutputAnnotationParser<?,Method,?>>();
outputMethodParsers.add(new LiteralDataOutputMethodAnnotationParser());
outputMethodParsers.add(new ComplexDataOutputMethodAnnotationParser());
OUTPUT_METHOD_PARSERS = Collections.unmodifiableList(outputMethodParsers);
PROCESS_PARSER = new ExecuteAnnotationParser();
}
private final static Map<Class<?>, AnnotatedAlgorithmIntrospector> INTROSPECTOR_MAP =
new HashMap<Class<?>, AnnotatedAlgorithmIntrospector>();
public static synchronized AnnotatedAlgorithmIntrospector getInstrospector(Class<?> algorithmClass) {
AnnotatedAlgorithmIntrospector introspector = INTROSPECTOR_MAP.get(algorithmClass);
if (introspector == null) {
introspector = new AnnotatedAlgorithmIntrospector(algorithmClass);
INTROSPECTOR_MAP.put(algorithmClass, introspector);
}
return introspector;
}
private Class<?> algorithmClass;
private AlgorithmDescriptor algorithmDescriptor;
private ExecuteMethodBinding executeMethodBinding;
private Map<String, AnnotationBinding.InputBinding<?, ?>> inputBindingMap;
private Map<String, AnnotationBinding.OutputBinding<?, ?>> outputBindingMap;
public AnnotatedAlgorithmIntrospector(Class<?> algorithmClass) {
this.algorithmClass = algorithmClass;
inputBindingMap = new LinkedHashMap<String, InputBinding<?, ?>>();
outputBindingMap = new LinkedHashMap<String, OutputBinding<?, ?>>();
parseClass();
inputBindingMap = Collections.unmodifiableMap(inputBindingMap);
outputBindingMap = Collections.unmodifiableMap(outputBindingMap);
}
private final static Logger LOGGER = LoggerFactory.getLogger(AnnotatedAlgorithmIntrospector.class);
//Modified by Gianpaolo Coro
private void parseClass() {
if (!algorithmClass.isAnnotationPresent(Algorithm.class)) {
throw new RuntimeException("Class isn't annotated with an Algorithm annotation");
}
boolean validContructor = false;
try {
Constructor defaultConstructor = algorithmClass.getConstructor(new Class[0]);
validContructor = (defaultConstructor.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC;
} catch (NoSuchMethodException ex) {
// inherit error message on fall through...
} catch (SecurityException ex) {
throw new RuntimeException("Current security policy limits use of reflection, error introspecting " + algorithmClass.getName());
}
if (!validContructor) {
throw new RuntimeException("Classes with Algorithm annotation require public no-arg constructor, error introspecting " + algorithmClass.getName());
}
AlgorithmDescriptor.Builder<?> algorithmBuilder = null;
Algorithm algorithm = algorithmClass.getAnnotation(Algorithm.class);
//MODIFICATIONS BY G CORO TO ACCOUNT FOR METHODS ORDER
List<Method> sortedMethods = new ArrayList<Method>();
List<Integer> methodsIdxs = new ArrayList<Integer>();
try{
for (Method m:algorithmClass.getDeclaredMethods()){
//System.out.println("Javaassist Analysing method "+m.getName());
ClassPool pool = ClassPool.getDefault();
ClassClassPath ccpath = new ClassClassPath(m.getDeclaringClass());
pool.insertClassPath(ccpath);
//System.out.println("Javaassist searching for canonical name "+m.getDeclaringClass().getCanonicalName());
CtClass cc = pool.get(m.getDeclaringClass().getCanonicalName());
//System.out.println("Javaassist cc "+cc.getName());
CtMethod javassistMethod = cc.getDeclaredMethod(m.getName());
//System.out.println("Javaassist method "+javassistMethod.getName());
int linenumber = javassistMethod.getMethodInfo().getLineNumber(0);
//System.out.println("Javaassist line number "+linenumber);
int i=0;
for (Integer methodsIdx :methodsIdxs){
if (methodsIdx>linenumber){
break;
}
i++;
}
sortedMethods.add(i,m);
methodsIdxs.add(i,linenumber);
}
}catch(Exception e){
LOGGER.warn("error getting method order",e);
}
Method[] sMethods = sortedMethods.toArray(new Method[sortedMethods.size()]);
algorithmBuilder = AlgorithmDescriptor.builder(
algorithm.identifier().length() > 0 ?
algorithm.identifier() :
algorithmClass.getCanonicalName());
algorithmBuilder.
title(algorithm.title()).
abstrakt(algorithm.abstrakt()).
version(algorithm.version()).
storeSupported(algorithm.storeSupported()).
statusSupported(algorithm.statusSupported());
parseElements(sMethods,
INPUT_METHOD_PARSERS,
OUTPUT_METHOD_PARSERS);
parseElements(algorithmClass.getDeclaredFields(),
INPUT_FIELD_PARSERS,
OUTPUT_FIELD_PARSERS);
private final static List<InputAnnotationParser<?,Field,?>> INPUT_FIELD_PARSERS;
private final static List<InputAnnotationParser<?,Method,?>> INPUT_METHOD_PARSERS;
private final static List<OutputAnnotationParser<?,Field,?>> OUTPUT_FIELD_PARSERS;
private final static List<OutputAnnotationParser<?,Method,?>> OUTPUT_METHOD_PARSERS;
private final static ExecuteAnnotationParser PROCESS_PARSER;
for (Method method : sMethods) {
if (method.isAnnotationPresent(PROCESS_PARSER.getSupportedAnnotation())) {
ExecuteMethodBinding executeMethodBinding = PROCESS_PARSER.parse(method);
if (executeMethodBinding != null) {
if (this.executeMethodBinding != null) {
// we need to error out here because ordering of getDeclaredMethods() or
// getMethods() is not guarenteed to be consistent, if it were consistent
// maybe we could ignore this state, but having an algorithm behave
// differently betweeen runtimes would be bad...
throw new RuntimeException("Multiple execute method bindings encountered for class " + getClass().getCanonicalName());
}
this.executeMethodBinding = executeMethodBinding;
}
}
}
static {
List<InputAnnotationParser<?,Field,?>> inputFieldParsers =
new ArrayList<InputAnnotationParser<?,Field,?>>();
inputFieldParsers.add(new LiteralDataInputFieldAnnotationParser());
inputFieldParsers.add(new ComplexDataInputFieldAnnotationParser());
INPUT_FIELD_PARSERS = Collections.unmodifiableList(inputFieldParsers);
if(this.executeMethodBinding == null) {
throw new RuntimeException("No execute method binding for class " + this.algorithmClass.getCanonicalName());
}
List<InputAnnotationParser<?,Method,?>> inputMethodParsers =
new ArrayList<InputAnnotationParser<?,Method,?>>();
inputMethodParsers.add(new LiteralDataInputMethodAnnotationParser());
inputMethodParsers.add(new ComplexDataInputMethodAnnotationParser());
INPUT_METHOD_PARSERS = Collections.unmodifiableList(inputMethodParsers);
for (InputBinding<?,?> inputBinding : inputBindingMap.values()) {
algorithmBuilder.addInputDescriptor(inputBinding.getDescriptor());
}
for (OutputBinding<?,?> outputBinding : outputBindingMap.values()) {
algorithmBuilder.addOutputDescriptor(outputBinding.getDescriptor());
}
algorithmDescriptor = algorithmBuilder.build();
}
List<OutputAnnotationParser<?,Field,?>> outputFieldParsers =
new ArrayList<OutputAnnotationParser<?,Field,?>>();
outputFieldParsers.add(new LiteralDataOutputFieldAnnotationParser());
outputFieldParsers.add(new ComplexDataOutputFieldAnnotationParser());
OUTPUT_FIELD_PARSERS = Collections.unmodifiableList(outputFieldParsers);
public AlgorithmDescriptor getAlgorithmDescriptor() {
return algorithmDescriptor;
}
List<OutputAnnotationParser<?,Method,?>> outputMethodParsers =
new ArrayList<OutputAnnotationParser<?,Method,?>>();
outputMethodParsers.add(new LiteralDataOutputMethodAnnotationParser());
outputMethodParsers.add(new ComplexDataOutputMethodAnnotationParser());
OUTPUT_METHOD_PARSERS = Collections.unmodifiableList(outputMethodParsers);
public ExecuteMethodBinding getExecuteMethodBinding() {
return executeMethodBinding;
}
PROCESS_PARSER = new ExecuteAnnotationParser();
}
public Map<String, AnnotationBinding.InputBinding<?, ?>> getInputBindingMap() {
return inputBindingMap;
}
private final static Map<Class<?>, AnnotatedAlgorithmIntrospector> INTROSPECTOR_MAP =
new HashMap<Class<?>, AnnotatedAlgorithmIntrospector>();
public static synchronized AnnotatedAlgorithmIntrospector getInstrospector(Class<?> algorithmClass) {
AnnotatedAlgorithmIntrospector introspector = INTROSPECTOR_MAP.get(algorithmClass);
if (introspector == null) {
introspector = new AnnotatedAlgorithmIntrospector(algorithmClass);
INTROSPECTOR_MAP.put(algorithmClass, introspector);
}
return introspector;
}
private Class<?> algorithmClass;
private AlgorithmDescriptor algorithmDescriptor;
private ExecuteMethodBinding executeMethodBinding;
private Map<String, AnnotationBinding.InputBinding<?, ?>> inputBindingMap;
private Map<String, AnnotationBinding.OutputBinding<?, ?>> outputBindingMap;
public AnnotatedAlgorithmIntrospector(Class<?> algorithmClass) {
this.algorithmClass = algorithmClass;
inputBindingMap = new LinkedHashMap<String, InputBinding<?, ?>>();
outputBindingMap = new LinkedHashMap<String, OutputBinding<?, ?>>();
parseClass();
inputBindingMap = Collections.unmodifiableMap(inputBindingMap);
outputBindingMap = Collections.unmodifiableMap(outputBindingMap);
}
//Modified by Gianpaolo Coro
private void parseClass() {
if (!algorithmClass.isAnnotationPresent(Algorithm.class)) {
throw new RuntimeException("Class isn't annotated with an Algorithm annotation");
}
boolean validContructor = false;
try {
Constructor defaultConstructor = algorithmClass.getConstructor(new Class[0]);
validContructor = (defaultConstructor.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC;
} catch (NoSuchMethodException ex) {
// inherit error message on fall through...
} catch (SecurityException ex) {
throw new RuntimeException("Current security policy limits use of reflection, error introspecting " + algorithmClass.getName());
}
if (!validContructor) {
throw new RuntimeException("Classes with Algorithm annotation require public no-arg constructor, error introspecting " + algorithmClass.getName());
}
AlgorithmDescriptor.Builder<?> algorithmBuilder = null;
Algorithm algorithm = algorithmClass.getAnnotation(Algorithm.class);
//MODIFICATIONS BY G CORO TO ACCOUNT FOR METHODS ORDER
List<Method> sortedMethods = new ArrayList<Method>();
List<Integer> methodsIdxs = new ArrayList<Integer>();
List<Method> notOrderedMethod = new ArrayList<Method>();
try{
for (Method m:algorithmClass.getDeclaredMethods()){
if (!m.isAnnotationPresent(MethodOrder.class)){
LOGGER.warn("METHOD {} in not annotated with MethodOrder in class {}", m.getName(), algorithmClass.getSimpleName());
notOrderedMethod.add(m);
continue;
}
int linenumber = m.getAnnotation(MethodOrder.class).value();
//System.out.println("Javaassist line number "+linenumber);
int i=0;
for (Integer methodsIdx :methodsIdxs){
if (methodsIdx>linenumber){
break;
}
i++;
}
sortedMethods.add(i,m);
methodsIdxs.add(i,linenumber);
}
}catch(Exception e){
LOGGER.warn("error getting method order",e);
}
sortedMethods.addAll(notOrderedMethod);
Method[] sMethods = sortedMethods.toArray(new Method[sortedMethods.size()]);
algorithmBuilder = AlgorithmDescriptor.builder(
algorithm.identifier().length() > 0 ?
algorithm.identifier() :
algorithmClass.getCanonicalName());
algorithmBuilder.
title(algorithm.title()).
abstrakt(algorithm.abstrakt()).
version(algorithm.version()).
storeSupported(algorithm.storeSupported()).
statusSupported(algorithm.statusSupported());
parseElements(sMethods,
INPUT_METHOD_PARSERS,
OUTPUT_METHOD_PARSERS);
parseElements(algorithmClass.getDeclaredFields(),
INPUT_FIELD_PARSERS,
OUTPUT_FIELD_PARSERS);
for (Method method : sMethods) {
if (method.isAnnotationPresent(PROCESS_PARSER.getSupportedAnnotation())) {
ExecuteMethodBinding executeMethodBinding = PROCESS_PARSER.parse(method);
if (executeMethodBinding != null) {
if (this.executeMethodBinding != null) {
// we need to error out here because ordering of getDeclaredMethods() or
// getMethods() is not guarenteed to be consistent, if it were consistent
// maybe we could ignore this state, but having an algorithm behave
// differently betweeen runtimes would be bad...
throw new RuntimeException("Multiple execute method bindings encountered for class " + getClass().getCanonicalName());
}
this.executeMethodBinding = executeMethodBinding;
}
}
}
if(this.executeMethodBinding == null) {
throw new RuntimeException("No execute method binding for class " + this.algorithmClass.getCanonicalName());
}
for (InputBinding<?,?> inputBinding : inputBindingMap.values()) {
algorithmBuilder.addInputDescriptor(inputBinding.getDescriptor());
}
for (OutputBinding<?,?> outputBinding : outputBindingMap.values()) {
algorithmBuilder.addOutputDescriptor(outputBinding.getDescriptor());
}
algorithmDescriptor = algorithmBuilder.build();
}
public AlgorithmDescriptor getAlgorithmDescriptor() {
return algorithmDescriptor;
}
public ExecuteMethodBinding getExecuteMethodBinding() {
return executeMethodBinding;
}
public Map<String, AnnotationBinding.InputBinding<?, ?>> getInputBindingMap() {
return inputBindingMap;
}
public Map<String, AnnotationBinding.OutputBinding<?, ?>> getOutputBindingMap() {
return outputBindingMap;
}
public <M extends AccessibleObject & Member> void parseElements(
M members[],
List<InputAnnotationParser<?,M,?>> inputParser,
List<OutputAnnotationParser<?,M,?>> outputParser) {
for (M member : members) {
for (OutputAnnotationParser<?,M,?> parser : outputParser) {
if (member.isAnnotationPresent(parser.getSupportedAnnotation())) {
OutputBinding<?,?> binding = parser.parse(member);
if (binding != null) {
outputBindingMap.put(binding.getDescriptor().getIdentifier(), binding);
}
}
}
for (InputAnnotationParser<?,M,?> parser : inputParser) {
if (member.isAnnotationPresent(parser.getSupportedAnnotation())) {
InputBinding<?,?> binding = parser.parse(member);
if (binding != null) {
inputBindingMap.put(binding.getDescriptor().getIdentifier(), binding);
}
}
}
}
}
public Map<String, AnnotationBinding.OutputBinding<?, ?>> getOutputBindingMap() {
return outputBindingMap;
}
public <M extends AccessibleObject & Member> void parseElements(
M members[],
List<InputAnnotationParser<?,M,?>> inputParser,
List<OutputAnnotationParser<?,M,?>> outputParser) {
for (M member : members) {
for (OutputAnnotationParser<?,M,?> parser : outputParser) {
if (member.isAnnotationPresent(parser.getSupportedAnnotation())) {
OutputBinding<?,?> binding = parser.parse(member);
if (binding != null) {
outputBindingMap.put(binding.getDescriptor().getIdentifier(), binding);
}
}
}
for (InputAnnotationParser<?,M,?> parser : inputParser) {
if (member.isAnnotationPresent(parser.getSupportedAnnotation())) {
InputBinding<?,?> binding = parser.parse(member);
if (binding != null) {
inputBindingMap.put(binding.getDescriptor().getIdentifier(), binding);
}
}
}
}
}
}

View File

@ -0,0 +1,13 @@
package org.n52.wps.algorithm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodOrder {
int value() default Integer.MAX_VALUE;
}

View File

@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
* @author tkunicki
*/
public abstract class AbstractAnnotatedAlgorithm extends AbstractDescriptorAlgorithm {
private final static Logger LOGGER = LoggerFactory.getLogger(AbstractAnnotatedAlgorithm.class);
@Override