1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package uk.ac.soton.itinnovation.nextgrid.api.pom;
19
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Modifier;
23 import java.net.URI;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28 import java.util.WeakHashMap;
29
30 import javax.xml.namespace.QName;
31
32 import nextgrid.api.env.ProcessEnvironment;
33 import nextgrid.api.pom.ProcessException;
34 import nextgrid.api.pom.Reference;
35 import nextgrid.api.pom.Service;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 import uk.ac.soton.itinnovation.nextgrid.api.pom.exceptions.ExecutionException;
41
42 import com.gridsystems.nextgrid.api.pom.AbstractGroundingImpl;
43
44
45
46
47
48
49
50 public class JavaGroundingImpl extends AbstractGroundingImpl {
51
52
53
54
55 private static final long serialVersionUID = -7991464254187036277L;
56
57
58
59
60 private static final Log LOG = LogFactory.getLog(JavaGroundingImpl.class);
61
62
63
64
65 public static final QName ATTR_JAVA_CLASS = attr("java-class");
66
67
68
69
70 public static final QName ATTR_JAVA_FACTORY = attr("java-factory");
71
72
73
74
75
76 public static final QName ATTR_JAVA_NAME = attr("java-factory-name");
77
78
79
80
81 public static final QName ATTR_JAVA_METHOD = attr("java-method");
82
83
84
85
86 public static final QName ATTR_PARAM_ORDER = attr("parameter-order");
87
88
89
90
91 private static final Map<QName, String> ATTRIBS;
92
93
94
95
96 public static final URI TYPE = URI.create("urn:java");
97
98
99
100
101 private static final WeakHashMap<Service, Object> CACHE
102 = new WeakHashMap<Service, Object>();
103
104 static {
105 Map<QName, String> attrs = new HashMap<QName, String>();
106 attrs.put(ATTR_JAVA_CLASS, "Qualified name of the Java class to invoke");
107 attrs.put(ATTR_JAVA_FACTORY, "Qualified name of Java class to use as factory");
108 attrs.put(ATTR_JAVA_NAME, "Identifier passed to the factory");
109 attrs.put(ATTR_JAVA_METHOD, "Method name to invoke");
110 attrs.put(ATTR_PARAM_ORDER, "Comma-separated list of input parameters");
111 ATTRIBS = Collections.unmodifiableMap(attrs);
112 }
113
114
115
116
117 public JavaGroundingImpl() {
118 super(TYPE, ATTRIBS);
119 }
120
121
122
123
124 public void invoke(ProcessEnvironment env, Service svc) throws ProcessException {
125 if (svc == null) {
126 throw new ProcessException("No service associated to this grounding");
127 }
128 try {
129 LOG.trace("Grounding '" + svc.getName() + "' execution start");
130 String fClass = svc.getAttribute(ATTR_JAVA_CLASS);
131 String fMethod = svc.getAttribute(ATTR_JAVA_METHOD);
132 String fOrder = svc.getAttribute(ATTR_PARAM_ORDER);
133
134 checkNull(fClass, ATTR_JAVA_CLASS.toString());
135 checkNull(fMethod, ATTR_JAVA_METHOD.toString());
136
137 Class<?> claz = null;
138 Method method = null;
139
140 String[] paramNames = (fOrder == null) ? new String[0] : fOrder.split(",");
141 Class<?>[] paramTypes = new Class[paramNames.length];
142 Object[] paramValues = new Object[paramTypes.length];
143
144 for (int i = 0; i < paramNames.length; i++) {
145 Reference<?> ref = svc.getInput(paramNames[i]);
146 checkNull(ref, "Reference '" + paramNames[i] + "'");
147 paramTypes[i] = ref.getValueType();
148 paramValues[i] = ref.getValue();
149 }
150
151 try {
152 claz = Class.forName(fClass);
153 method = claz.getDeclaredMethod(fMethod, paramTypes);
154 } catch (ClassNotFoundException e) {
155 throw new ExecutionException("Class '" + fClass + "' not found.", e);
156 } catch (NoSuchMethodException e) {
157 throw new ExecutionException("Method '" + fMethod + "' not found.", e);
158 } catch (Exception e) {
159 throw new ExecutionException(e);
160 }
161
162
163
164 try {
165 Object obj = null;
166 if (!Modifier.isStatic(method.getModifiers())) {
167 obj = getInstance(svc, claz);
168 }
169 if (method.getReturnType().toString().equalsIgnoreCase("void")) {
170 method.invoke(obj, paramValues);
171 } else {
172 Object result = method.invoke(obj, paramValues);
173 writeResult(svc, result);
174 }
175 } catch (InvocationTargetException e) {
176 throw new ExecutionException("Error in executed method", e.getTargetException());
177 } catch (Exception e) {
178 throw new ExecutionException("Error in executed method", e);
179 }
180 } finally {
181 LOG.trace("Grounding '" + svc.getName() + "' execution end");
182 }
183 }
184
185
186
187
188
189
190
191
192 private void checkNull(Object obj, String name) throws ProcessException {
193 if (obj == null) {
194 throw new ProcessException(name + " not defined",
195 new NullPointerException(name));
196 }
197 }
198
199
200
201
202 public void dispose() {
203 }
204
205
206
207
208 public void validate() {
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228 @SuppressWarnings("unchecked")
229 private Object getInstance(Service service, Class c) {
230 assert service != null;
231
232 Object instance = CACHE.get(service);
233 if (instance != null) {
234 return instance;
235 } else {
236 final Object obj;
237
238 try {
239 String factName = service.getAttribute(ATTR_JAVA_FACTORY);
240 if (factName == null) {
241 obj = c.newInstance();
242 } else {
243 Class factory = Class.forName(factName);
244 Method mFactory = factory.getDeclaredMethod("getInstance", URI.class);
245 obj = mFactory.invoke(null, service.getId());
246 }
247 } catch (Exception e) {
248 throw new ExecutionException("Error getting java instance", e);
249 }
250
251 CACHE.put(service, obj);
252 return obj;
253 }
254 }
255
256
257
258
259
260
261
262 @SuppressWarnings("unchecked")
263 private void writeResult(Service service, Object value) {
264 Iterator<Reference<?>> it = service.getOutputs().values().iterator();
265 if (it.hasNext()) {
266 Reference r = it.next();
267 r.setValue(value);
268 } else {
269 LOG.info("No output parameters found. Return value ignored");
270 }
271 }
272 }