1 package cz.cuni.amis.pogamut.sposh.executor;
2
3 import cz.cuni.amis.pogamut.sposh.engine.VariableContext;
4 import cz.cuni.amis.pogamut.sposh.exceptions.FubarException;
5 import cz.cuni.amis.pogamut.sposh.exceptions.MethodException;
6 import java.lang.annotation.Annotation;
7 import java.lang.reflect.InvocationTargetException;
8 import java.lang.reflect.Method;
9 import java.lang.reflect.Modifier;
10 import java.util.LinkedList;
11 import java.util.List;
12 import java.util.logging.Level;
13 import java.util.logging.Logger;
14
15
16
17
18
19 class ParamsMethod<RETURN> {
20
21 private final String methodName;
22 private final Class<RETURN> returnCls;
23 private final Class<?> methodClass;
24 private final Method method;
25
26 ParamsMethod(Class methodClass, String methodName, Class<RETURN> returnCls) {
27 this.methodClass = methodClass;
28 this.methodName = methodName;
29 this.returnCls = returnCls;
30
31 this.method = findMethod();
32 }
33
34
35
36
37
38
39
40
41 private boolean areParamsAcceptable(Method method, Class<?>... acceptedTypes) {
42 for (Class<?> paramType : method.getParameterTypes()) {
43 boolean found = false;
44 for (Class<?> acceptedType : acceptedTypes) {
45 if (paramType.equals(acceptedType)) {
46 found = true;
47 }
48 }
49 if (!found) {
50 return false;
51 }
52 }
53 return true;
54 }
55
56
57
58
59
60
61
62
63
64 private <T extends Annotation> T getAnnotation(Annotation[] annotations, Class<T> seekedAnnotation) {
65 for (Annotation annotation : annotations) {
66 if (annotation.annotationType().equals(seekedAnnotation)) {
67 return (T) annotation;
68 }
69 }
70 return null;
71 }
72
73
74
75
76
77
78
79 private boolean areParamsAnnotated(Method method) {
80 for (Annotation[] paramAnnotations : method.getParameterAnnotations()) {
81 if (getAnnotation(paramAnnotations, Param.class) == null) {
82 return false;
83 }
84 }
85 return true;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 private Method[] filterMethods(Method[] methods, String seekedName, Class<?> returnType) {
111 List<Method> filteredMethods = new LinkedList<Method>();
112
113 for (Method testedMethod : methods) {
114 String testedMethodName = testedMethod.getName();
115 boolean methodIsPublic = (testedMethod.getModifiers() & Modifier.PUBLIC) == Modifier.PUBLIC;
116 boolean methodIsAbstract = (testedMethod.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
117 boolean correctReturnType = testedMethod.getReturnType().equals(returnType);
118 boolean acceptedParams = areParamsAcceptable(testedMethod, String.class, Integer.class, int.class, Double.class, double.class);
119 boolean annotatedParams = areParamsAnnotated(testedMethod);
120
121 if (testedMethodName.equals(seekedName)
122 && methodIsPublic
123 && !methodIsAbstract
124 && !testedMethod.isVarArgs()
125 && correctReturnType
126 && acceptedParams
127 && annotatedParams) {
128 filteredMethods.add(testedMethod);
129 }
130 }
131 return filteredMethods.toArray(new Method[filteredMethods.size()]);
132 }
133
134
135
136
137
138
139
140
141
142
143
144 final Method findMethod() {
145 Method[] methods = filterMethods(methodClass.getMethods(), methodName, returnCls);
146 if (methods.length == 0) {
147 throw new NoSuchMethodError("Unable to find method " + methodName);
148 }
149 if (methods.length > 1) {
150 throw new UnsupportedOperationException("Multiple (" + methods.length + ") possible " + methodName + " methods, overloading is not supported.");
151 }
152 return methods[0];
153 }
154
155
156
157
158
159
160
161
162 public final RETURN invoke(Object thisObject, VariableContext params) throws InvocationTargetException {
163 Class<?>[] paramTypes = method.getParameterTypes();
164 Annotation[][] paramsAnnotations = method.getParameterAnnotations();
165
166 assert paramsAnnotations.length == paramTypes.length;
167
168 int paramCount = paramTypes.length;
169
170 List methodArguments = new LinkedList();
171 for (int paramIndex = 0; paramIndex < paramCount; ++paramIndex) {
172 Annotation[] paramAnnotations = paramsAnnotations[paramIndex];
173 Param param = getAnnotation(paramAnnotations, Param.class);
174
175 String variableName = param.value();
176 try {
177 Object variableValue = params.getValue(variableName);
178 methodArguments.add(variableValue);
179 } catch (IllegalArgumentException ex) {
180 String thisObjectName = thisObject.getClass().getName();
181 throw new MethodException("No variable " + variableName + " for " + thisObjectName + "." + methodName, ex);
182 }
183 }
184
185 try {
186 Object ret = method.invoke(thisObject, methodArguments.toArray());
187 return (RETURN) ret;
188 } catch (IllegalAccessException ex) {
189 throw new FubarException("findMethod filters for public methods", ex);
190 } catch (IllegalArgumentException ex) {
191 throw new FubarException("Error with parameter maching code", ex);
192 } catch (InvocationTargetException ex) {
193 throw ex;
194 }
195 }
196 }