1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.gridsystems.innergrid.api;
18
19 import java.io.File;
20 import java.io.InputStream;
21 import java.lang.reflect.Proxy;
22 import java.net.URL;
23 import java.rmi.Remote;
24 import java.util.Hashtable;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27 import java.util.concurrent.ConcurrentMap;
28
29 import javax.xml.namespace.QName;
30 import javax.xml.rpc.ServiceException;
31 import javax.xml.rpc.Stub;
32 import javax.xml.rpc.encoding.DeserializerFactory;
33 import javax.xml.rpc.encoding.SerializerFactory;
34 import javax.xml.rpc.encoding.TypeMapping;
35
36 import com.gridsystems.utils.FileUtils;
37
38 import org.apache.axis.MessageContext;
39 import org.apache.axis.WSDDEngineConfiguration;
40 import org.apache.axis.client.AxisClient;
41 import org.apache.axis.client.Call;
42 import org.apache.axis.client.Service;
43 import org.apache.axis.configuration.FileProvider;
44 import org.apache.axis.deployment.wsdd.WSDDDeployment;
45 import org.apache.axis.deployment.wsdd.WSDDDocument;
46 import org.apache.axis.encoding.TypeMappingRegistry;
47 import org.apache.axis.encoding.ser.BeanDeserializerFactory;
48 import org.apache.axis.encoding.ser.BeanSerializerFactory;
49 import org.apache.axis.handlers.soap.SOAPService;
50 import org.apache.axis.transport.http.HTTPConstants;
51 import org.apache.axis.utils.XMLUtils;
52 import org.apache.commons.discovery.ResourceNameIterator;
53 import org.apache.commons.discovery.resource.ClassLoaders;
54 import org.apache.commons.discovery.resource.names.DiscoverServiceNames;
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57
58
59
60
61
62
63 public abstract class ClientApiFactory extends HTTPConstants {
64
65
66
67
68 public static class ApiEntry {
69
70 public ClientApiFactory factory;
71
72
73 public Class< ? > iface;
74
75
76 public URL wsdl;
77
78
79 public URL wsdd;
80
81
82 public QName serviceName;
83
84
85 public QName portName;
86 }
87
88
89
90
91
92 private static class FuraService extends Service {
93
94
95
96 private static final long serialVersionUID = 1L;
97
98
99
100
101 private static final WSDDEngineConfiguration CONFIG;
102
103
104
105
106 private static final AxisClient ENGINE;
107
108 static {
109
110 CONFIG = new FileProvider("fura-client-config.wsdd");
111 ENGINE = new AxisClient(CONFIG);
112 }
113
114
115
116
117
118
119
120
121 public FuraService(URL wsdl, QName serviceName) throws ServiceException {
122 super(wsdl, serviceName);
123 }
124
125
126
127
128 @Override protected AxisClient getAxisClient() {
129 return ENGINE;
130 }
131 }
132
133
134
135
136 private static final Log LOG = LogFactory.getLog(ClientApiFactory.class);
137
138
139
140
141 private static final int INITIAL_CAPACITY = 15;
142
143
144
145
146 private static final float LOAD_FACTOR = 0.75f;
147
148
149
150
151 private static final int CONCURRENCY_LEVEL = 5;
152
153
154
155
156
157 private static final long WSDL_CACHE_STARTUP = System.currentTimeMillis();
158
159
160
161
162 private static final ConcurrentMap<Class<?>, QName> API_NAMES;
163
164
165
166
167 private static final ConcurrentMap<QName, ApiEntry> API_ENTRIES;
168
169 static {
170 API_NAMES = new ConcurrentHashMap<Class<?>, QName>(
171 INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL);
172
173 API_ENTRIES = new ConcurrentHashMap<QName, ApiEntry>(
174 INITIAL_CAPACITY, LOAD_FACTOR, CONCURRENCY_LEVEL);
175
176
177
178 final String spi = ClientApiFactory.class.getName();
179 LOG.info("Discovering API factories for '" + spi + "'");
180 final ClassLoaders loaders = new ClassLoaders();
181 loaders.put(Thread.currentThread().getContextClassLoader());
182 final DiscoverServiceNames discover = new DiscoverServiceNames(loaders);
183 ResourceNameIterator it = discover.findResourceNames(spi);
184 while (it.hasNext()) {
185 String factoryName = it.nextResourceName();
186 try {
187 Class<?> factoryClass = Class.forName(factoryName);
188 if (ClientApiFactory.class.isAssignableFrom(factoryClass)) {
189
190 LOG.info("Registering " + factoryName);
191 ((ClientApiFactory)factoryClass.newInstance()).registerApis();
192 }
193 } catch (Exception e) {
194 LOG.warn("Could not register factory '" + factoryName + "'", e);
195 }
196 }
197 }
198
199
200
201
202
203
204 public static void register(ApiEntry api) {
205 API_NAMES.putIfAbsent(api.iface, api.serviceName);
206 API_ENTRIES.putIfAbsent(api.serviceName, api);
207
208 if (api.wsdd != null && FuraService.CONFIG != null) {
209 LOG.debug("Registering WSDD '" + api.wsdd + "'");
210 InputStream is = null;
211 try {
212 is = api.wsdd.openStream();
213 WSDDDeployment deployment = FuraService.CONFIG.getDeployment();
214 WSDDDocument doc = new WSDDDocument(XMLUtils.newDocument(is));
215 doc.deploy(deployment);
216
217 FuraService.ENGINE.refreshGlobalOptions();
218 } catch (Exception e) {
219 LOG.warn("Could not register API '" + api.iface.getName() + "'", e);
220 } finally {
221 if (is != null) {
222 try {
223 is.close();
224 } catch (Exception e) { }
225 }
226 }
227 }
228 }
229
230
231
232
233 protected ClientApiFactory() {
234
235 }
236
237
238
239
240 protected abstract void registerApis();
241
242
243
244
245
246
247
248
249
250 protected Remote newInstance(ApiEntry entry, Connection con) throws ServiceException {
251 ClassLoader loader = Thread.currentThread().getContextClassLoader();
252 Class< ? >[] ifaces = { entry.iface, javax.xml.rpc.Stub.class };
253
254 Stub port = (Stub)getPort(entry, con);
255
256 return (Remote)Proxy.newProxyInstance(loader, ifaces,
257 new ClientApiProxy(entry.iface, port, con));
258 }
259
260
261
262
263
264
265
266
267
268 @SuppressWarnings("unchecked")
269 public final Remote getPort(ApiEntry entry, Connection con) throws ServiceException {
270 fixWsdl(entry, con);
271
272 Service service = new FuraService(entry.wsdl, entry.serviceName);
273 Remote remote = service.getPort(entry.iface);
274
275
276 Stub stub = (Stub)remote;
277 Map headers = (Map)stub._getProperty(REQUEST_HEADERS);
278 if (headers == null) {
279 headers = new Hashtable();
280 stub._setProperty(REQUEST_HEADERS, headers);
281 }
282
283 return (Remote)stub;
284 }
285
286
287
288
289
290
291
292
293 private void fixWsdl(ApiEntry entry, Connection con) {
294 if (entry.wsdl == null && con != null && entry.serviceName != null) {
295 String tempDir = System.getProperty("java.io.tmpdir");
296 File temp = new File(tempDir, "ClientApiFactory");
297 temp.mkdirs();
298
299 String ns = entry.serviceName.getNamespaceURI();
300 String name = entry.serviceName.getLocalPart();
301 ns = ns.replaceAll("[:/]+", "_");
302 String wsdlName = ns + "_" + name + ".wsdl";
303 File f = new File(temp, wsdlName);
304
305 if (f.isFile() && WSDL_CACHE_STARTUP < f.lastModified()) {
306 try {
307 entry.wsdl = f.toURI().toURL();
308 } catch (Exception e) {
309 throw new RuntimeException("Could not build URL to service WSDL", e);
310 }
311 } else {
312 try {
313 StringBuffer sbUrl = new StringBuffer();
314 sbUrl.append((con.isSecured()) ? "https://" : "http://");
315 sbUrl.append(con.getHost());
316 sbUrl.append(':');
317 sbUrl.append(con.getPort());
318 sbUrl.append("/kernel/api/");
319 sbUrl.append(entry.portName.getLocalPart());
320 sbUrl.append("?wsdl");
321 URL url = new URL(sbUrl.toString());
322 FileUtils.createFile(url.openStream(), f);
323
324 entry.wsdl = f.toURI().toURL();
325 } catch (Exception e) {
326 f.delete();
327 e.printStackTrace();
328 throw new RuntimeException(entry.serviceName + " WSDL download failed", e);
329 }
330 }
331 }
332 }
333
334
335
336
337
338
339
340
341
342
343 public static <T extends Remote> T newApi(Class<T> iface, Connection con)
344 throws Exception {
345 if (iface == null) {
346 return null;
347 } else {
348 QName name = API_NAMES.get(iface);
349 if (name == null) {
350 throw new CKernelException("CLT015", iface.getName());
351 } else {
352 return newApi(iface, API_NAMES.get(iface), con);
353 }
354 }
355 }
356
357
358
359
360
361
362
363
364
365
366
367 public static <T extends Remote> T newApi(Class<T> iface, QName serviceName,
368 Connection con) throws Exception {
369 ApiEntry entry = API_ENTRIES.get(serviceName);
370
371 if (entry == null) {
372 throw new CKernelException("CLT015", iface.getName());
373 } else {
374 return (T)entry.factory.newInstance(entry, con);
375 }
376 }
377
378
379
380
381
382
383
384 public static WSDDEngineConfiguration getConfig() {
385 return FuraService.CONFIG;
386 }
387
388
389
390
391
392
393 public static AxisClient getEngine() {
394 return FuraService.ENGINE;
395 }
396
397
398
399
400
401
402
403
404 public static void fixTypeMapping(String svcName, Class<?> javaType, QName xmlType) {
405 try {
406 SOAPService svc = ClientApiFactory.getEngine().getService(svcName);
407 TypeMappingRegistry tmr = svc.getTypeMappingRegistry();
408
409 SerializerFactory sf = null;
410 DeserializerFactory df = null;
411
412 String[] styleURIs = tmr.getRegisteredEncodingStyleURIs();
413 for (String uri : styleURIs) {
414 TypeMapping tm = tmr.getTypeMapping(uri);
415 sf = tm.getSerializer(javaType, xmlType);
416 df = tm.getDeserializer(javaType, xmlType);
417 if (sf != null && df != null) {
418 break;
419 }
420 }
421
422 if (sf == null || df == null) {
423
424 sf = new BeanSerializerFactory(javaType, xmlType);
425 df = new BeanDeserializerFactory(javaType, xmlType);
426 }
427
428
429 tmr.getDefaultTypeMapping().register(javaType, xmlType, sf, df);
430 for (String uri : styleURIs) {
431 TypeMapping tm = tmr.getTypeMapping(uri);
432 tm.register(javaType, xmlType, sf, df);
433 }
434 } catch (Exception e) {
435 throw new RuntimeException(e);
436 }
437 }
438 }