001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.client;
018:
019: import javax.xml.ws.spi.Provider;
020: import javax.xml.ws.spi.ServiceDelegate;
021: import javax.xml.ws.Endpoint;
022: import javax.xml.ws.BindingProvider;
023: import javax.xml.ws.Dispatch;
024: import javax.xml.ws.Service;
025: import javax.xml.ws.WebServiceException;
026: import javax.xml.ws.EndpointReference;
027: import javax.xml.ws.WebServiceFeature;
028: import javax.xml.ws.wsaddressing.W3CEndpointReference;
029: import javax.xml.ws.soap.SOAPBinding;
030: import javax.xml.ws.handler.HandlerResolver;
031: import javax.xml.namespace.QName;
032: import javax.xml.bind.JAXBContext;
033: import javax.xml.transform.Source;
034: import javax.jws.WebService;
035: import java.net.URL;
036: import java.util.Iterator;
037: import java.util.Map;
038: import java.util.List;
039: import java.util.Properties;
040: import java.util.Collections;
041: import java.util.Enumeration;
042: import java.util.ArrayList;
043: import java.util.logging.Logger;
044: import java.util.logging.Level;
045: import java.util.concurrent.Executor;
046: import java.io.File;
047: import java.io.FileInputStream;
048: import java.io.InputStream;
049: import java.io.BufferedReader;
050: import java.io.InputStreamReader;
051: import java.io.IOException;
052: import java.io.OutputStream;
053: import java.io.FileOutputStream;
054: import java.lang.reflect.Method;
055: import java.lang.reflect.InvocationTargetException;
056:
057: import org.w3c.dom.Element;
058:
059: public class JaxWsProviderWrapper extends Provider {
060: private static final Logger logger = Logger
061: .getLogger("OpenEJB.client");
062:
063: //
064: // Magic to get our proider wrapper installed with the PortRefData
065: //
066:
067: private static ThreadLocal<ProviderWrapperData> threadPortRefs = new ThreadLocal<ProviderWrapperData>();
068:
069: public static void beforeCreate(
070: List<PortRefMetaData> portRefMetaDatas) {
071: // Axis JAXWS api is non compliant and checks system property before classloader
072: // so we replace system property so this wrapper is selected. The original value
073: // is saved into an openejb property so we can load the class in the find method
074: String oldProperty = System.getProperty(JAXWSPROVIDER_PROPERTY);
075: if (oldProperty != null
076: && !oldProperty.equals(JaxWsProviderWrapper.class
077: .getName())) {
078: System.setProperty("openejb." + JAXWSPROVIDER_PROPERTY,
079: oldProperty);
080: }
081:
082: System.setProperty(JAXWSPROVIDER_PROPERTY,
083: JaxWsProviderWrapper.class.getName());
084:
085: ClassLoader oldClassLoader = Thread.currentThread()
086: .getContextClassLoader();
087: if (oldClassLoader != null) {
088: Thread.currentThread().setContextClassLoader(
089: new ProviderClassLoader(oldClassLoader));
090: } else {
091: Thread.currentThread().setContextClassLoader(
092: new ProviderClassLoader());
093: }
094: threadPortRefs.set(new ProviderWrapperData(portRefMetaDatas,
095: oldClassLoader));
096: }
097:
098: public static void afterCreate() {
099: Thread.currentThread().setContextClassLoader(
100: threadPortRefs.get().callerClassLoader);
101: threadPortRefs.set(null);
102: }
103:
104: private static class ProviderWrapperData {
105: private final List<PortRefMetaData> portRefMetaData;
106: private final ClassLoader callerClassLoader;
107:
108: public ProviderWrapperData(
109: List<PortRefMetaData> portRefMetaDatas,
110: ClassLoader callerClassLoader) {
111: this .portRefMetaData = portRefMetaDatas;
112: this .callerClassLoader = callerClassLoader;
113: }
114: }
115:
116: //
117: // Provider wappre implementation
118: //
119:
120: private final Provider delegate;
121: private final List<PortRefMetaData> portRefs;
122:
123: public JaxWsProviderWrapper() {
124: delegate = findProvider();
125: portRefs = threadPortRefs.get().portRefMetaData;
126: }
127:
128: public Provider getDelegate() {
129: return delegate;
130: }
131:
132: public ServiceDelegate createServiceDelegate(
133: URL wsdlDocumentLocation, QName serviceName,
134: Class serviceClass) {
135: ServiceDelegate serviceDelegate = delegate
136: .createServiceDelegate(wsdlDocumentLocation,
137: serviceName, serviceClass);
138: serviceDelegate = new ServiceDelegateWrapper(serviceDelegate);
139: return serviceDelegate;
140: }
141:
142: public Endpoint createEndpoint(String bindingId, Object implementor) {
143: return delegate.createEndpoint(bindingId, implementor);
144: }
145:
146: public Endpoint createAndPublishEndpoint(String address,
147: Object implementor) {
148: return delegate.createAndPublishEndpoint(address, implementor);
149: }
150:
151: public W3CEndpointReference createW3CEndpointReference(
152: String address, QName serviceName, QName portName,
153: List<Element> metadata, String wsdlDocumentLocation,
154: List<Element> referenceParameters) {
155:
156: return (W3CEndpointReference) invoke21Delegate(delegate,
157: createW3CEndpointReference, address, serviceName,
158: portName, metadata, wsdlDocumentLocation,
159: referenceParameters);
160: }
161:
162: public EndpointReference readEndpointReference(Source source) {
163: return (EndpointReference) invoke21Delegate(delegate,
164: readEndpointReference, source);
165: }
166:
167: @SuppressWarnings({"unchecked"})
168: public <T> T getPort(EndpointReference endpointReference,
169: Class<T> serviceEndpointInterface,
170: WebServiceFeature... features) {
171: return (T) invoke21Delegate(delegate, providerGetPort,
172: endpointReference, serviceEndpointInterface, features);
173: }
174:
175: private class ServiceDelegateWrapper extends ServiceDelegate {
176: private final ServiceDelegate serviceDelegate;
177:
178: public ServiceDelegateWrapper(ServiceDelegate serviceDelegate) {
179: this .serviceDelegate = serviceDelegate;
180: }
181:
182: public <T> T getPort(QName portName,
183: Class<T> serviceEndpointInterface) {
184: T t = serviceDelegate.getPort(portName,
185: serviceEndpointInterface);
186: setProperties((BindingProvider) t, portName);
187: return t;
188: }
189:
190: public <T> T getPort(Class<T> serviceEndpointInterface) {
191: T t = serviceDelegate.getPort(serviceEndpointInterface);
192:
193: QName qname = null;
194: if (serviceEndpointInterface
195: .isAnnotationPresent(WebService.class)) {
196: WebService webService = serviceEndpointInterface
197: .getAnnotation(WebService.class);
198: String targetNamespace = webService.targetNamespace();
199: String name = webService.name();
200: if (targetNamespace != null
201: && targetNamespace.length() > 0 && name != null
202: && name.length() > 0) {
203: qname = new QName(targetNamespace, name);
204: }
205: }
206:
207: setProperties((BindingProvider) t, qname);
208: return t;
209: }
210:
211: public void addPort(QName portName, String bindingId,
212: String endpointAddress) {
213: serviceDelegate.addPort(portName, bindingId,
214: endpointAddress);
215: }
216:
217: public <T> Dispatch<T> createDispatch(QName portName,
218: Class<T> type, Service.Mode mode) {
219: Dispatch<T> dispatch = serviceDelegate.createDispatch(
220: portName, type, mode);
221: setProperties(dispatch, portName);
222: return dispatch;
223: }
224:
225: public Dispatch<Object> createDispatch(QName portName,
226: JAXBContext context, Service.Mode mode) {
227: Dispatch<Object> dispatch = serviceDelegate.createDispatch(
228: portName, context, mode);
229: setProperties(dispatch, portName);
230: return dispatch;
231: }
232:
233: @SuppressWarnings({"unchecked"})
234: public <T> Dispatch<T> createDispatch(QName portName,
235: Class<T> type, Service.Mode mode,
236: WebServiceFeature... features) {
237: return (Dispatch<T>) invoke21Delegate(serviceDelegate,
238: createDispatchInterface, portName, type, mode,
239: features);
240: }
241:
242: @SuppressWarnings({"unchecked"})
243: public Dispatch<java.lang.Object> createDispatch(
244: QName portName, JAXBContext context, Service.Mode mode,
245: WebServiceFeature... features) {
246: return (Dispatch<Object>) invoke21Delegate(serviceDelegate,
247: createDispatchJaxBContext, portName, context, mode,
248: features);
249: }
250:
251: @SuppressWarnings({"unchecked"})
252: public Dispatch<Object> createDispatch(
253: EndpointReference endpointReference,
254: JAXBContext context, Service.Mode mode,
255: WebServiceFeature... features) {
256: return (Dispatch<Object>) invoke21Delegate(serviceDelegate,
257: createDispatchReferenceJaxB, endpointReference,
258: context, mode, features);
259: }
260:
261: @SuppressWarnings({"unchecked"})
262: public <T> Dispatch<T> createDispatch(
263: EndpointReference endpointReference,
264: java.lang.Class<T> type, Service.Mode mode,
265: WebServiceFeature... features) {
266: return (Dispatch<T>) invoke21Delegate(serviceDelegate,
267: createDispatchReferenceClass, endpointReference,
268: type, mode, features);
269:
270: }
271:
272: @SuppressWarnings({"unchecked"})
273: public <T> T getPort(QName portName,
274: Class<T> serviceEndpointInterface,
275: WebServiceFeature... features) {
276: return (T) invoke21Delegate(serviceDelegate,
277: serviceGetPortByQName, portName,
278: serviceEndpointInterface, features);
279: }
280:
281: @SuppressWarnings({"unchecked"})
282: public <T> T getPort(EndpointReference endpointReference,
283: Class<T> serviceEndpointInterface,
284: WebServiceFeature... features) {
285: return (T) invoke21Delegate(serviceDelegate,
286: serviceGetPortByEndpointReference,
287: endpointReference, serviceEndpointInterface,
288: features);
289: }
290:
291: @SuppressWarnings({"unchecked"})
292: public <T> T getPort(Class<T> serviceEndpointInterface,
293: WebServiceFeature... features) {
294: return (T) invoke21Delegate(serviceDelegate,
295: serviceGetPortByInterface,
296: serviceEndpointInterface, features);
297: }
298:
299: public QName getServiceName() {
300: QName qName = serviceDelegate.getServiceName();
301: return qName;
302: }
303:
304: public Iterator<QName> getPorts() {
305: Iterator<QName> ports = serviceDelegate.getPorts();
306: return ports;
307: }
308:
309: public URL getWSDLDocumentLocation() {
310: URL documentLocation = serviceDelegate
311: .getWSDLDocumentLocation();
312: return documentLocation;
313: }
314:
315: public HandlerResolver getHandlerResolver() {
316: HandlerResolver handlerResolver = serviceDelegate
317: .getHandlerResolver();
318: return handlerResolver;
319: }
320:
321: public void setHandlerResolver(HandlerResolver handlerResolver) {
322: serviceDelegate.setHandlerResolver(handlerResolver);
323: }
324:
325: public Executor getExecutor() {
326: Executor executor = serviceDelegate.getExecutor();
327: return executor;
328: }
329:
330: public void setExecutor(Executor executor) {
331: serviceDelegate.setExecutor(executor);
332: }
333:
334: private void setProperties(BindingProvider proxy, QName qname) {
335: for (PortRefMetaData portRef : portRefs) {
336: Class<?> intf = null;
337: if (portRef.getServiceEndpointInterface() != null) {
338: try {
339: intf = proxy
340: .getClass()
341: .getClassLoader()
342: .loadClass(
343: portRef
344: .getServiceEndpointInterface());
345: } catch (ClassNotFoundException e) {
346: }
347: }
348: if ((qname != null && qname.equals(portRef.getQName()))
349: || (intf != null && intf.isInstance(proxy))) {
350: // set address
351: if (!portRef.getAddresses().isEmpty()) {
352: proxy
353: .getRequestContext()
354: .put(
355: BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
356: portRef.getAddresses().get(0));
357: }
358:
359: // set mtom
360: boolean enableMTOM = portRef.isEnableMtom();
361: if (enableMTOM
362: && proxy.getBinding() instanceof SOAPBinding) {
363: ((SOAPBinding) proxy.getBinding())
364: .setMTOMEnabled(enableMTOM);
365: }
366:
367: // set properties
368: for (Map.Entry<Object, Object> entry : portRef
369: .getProperties().entrySet()) {
370: String name = (String) entry.getKey();
371: String value = (String) entry.getValue();
372: proxy.getRequestContext().put(name, value);
373: }
374:
375: return;
376: }
377: }
378: }
379: }
380:
381: private static Provider findProvider() {
382: ClassLoader classLoader = Thread.currentThread()
383: .getContextClassLoader();
384: if (classLoader == null)
385: classLoader = ClassLoader.getSystemClassLoader();
386:
387: // 0. System.getProperty("openejb.javax.xml.ws.spi.Provider")
388: // This is so those using old axis rules still work as expected
389: String providerClass = System.getProperty("openejb."
390: + JAXWSPROVIDER_PROPERTY);
391: Provider provider = createProviderInstance(providerClass,
392: classLoader);
393: if (provider != null) {
394: return provider;
395: }
396:
397: // 1. META-INF/services/javax.xml.ws.spi.Provider
398: try {
399: for (URL url : Collections.list(classLoader
400: .getResources("META-INF/services/"
401: + JAXWSPROVIDER_PROPERTY))) {
402: BufferedReader in = null;
403: try {
404: in = new BufferedReader(new InputStreamReader(url
405: .openStream()));
406:
407: providerClass = in.readLine();
408: provider = createProviderInstance(providerClass,
409: classLoader);
410: if (provider != null) {
411: return provider;
412: }
413: } catch (Exception ignored) {
414: } finally {
415: if (in != null) {
416: try {
417: in.close();
418: } catch (IOException e) {
419: }
420: }
421: }
422: }
423: } catch (Exception ingored) {
424: }
425:
426: // 2. $java.home/lib/jaxws.properties
427: String javaHome = System.getProperty("java.home");
428: File jaxrpcPropertiesFile = new File(new File(javaHome, "lib"),
429: "jaxrpc.properties");
430: if (jaxrpcPropertiesFile.exists()) {
431: InputStream in = null;
432: try {
433: in = new FileInputStream(jaxrpcPropertiesFile);
434: Properties properties = new Properties();
435: properties.load(in);
436:
437: providerClass = properties
438: .getProperty(JAXWSPROVIDER_PROPERTY);
439: provider = createProviderInstance(providerClass,
440: classLoader);
441: if (provider != null) {
442: return provider;
443: }
444: } catch (Exception ignored) {
445: } finally {
446: if (in != null) {
447: try {
448: in.close();
449: } catch (IOException e) {
450: }
451: }
452: }
453: }
454:
455: // 3. System.getProperty("javax.xml.ws.spi.Provider")
456: providerClass = System.getProperty(JAXWSPROVIDER_PROPERTY);
457: provider = createProviderInstance(providerClass, classLoader);
458: if (provider != null) {
459: return provider;
460: }
461:
462: // 4. Use javax.xml.ws.spi.Provider default
463: try {
464: // disable the OpenEJB JaxWS provider
465: if (classLoader instanceof ProviderClassLoader) {
466: ((ProviderClassLoader) classLoader).enabled = false;
467: }
468: System.getProperties().remove(JAXWSPROVIDER_PROPERTY);
469:
470: provider = Provider.provider();
471: if (provider != null
472: && !provider.getClass().getName().equals(
473: JaxWsProviderWrapper.class.getName())) {
474: return provider;
475: }
476: } finally {
477: // reenable the OpenEJB JaxWS provider
478: System.setProperty(JAXWSPROVIDER_PROPERTY, providerClass);
479: if (classLoader instanceof ProviderClassLoader) {
480: ((ProviderClassLoader) classLoader).enabled = true;
481: }
482: }
483:
484: throw new WebServiceException("No " + JAXWSPROVIDER_PROPERTY
485: + " implementation found");
486: }
487:
488: private static Provider createProviderInstance(
489: String providerClass, ClassLoader classLoader) {
490: if (providerClass != null
491: && providerClass.length() > 0
492: && !providerClass.equals(JaxWsProviderWrapper.class
493: .getName())) {
494: try {
495: Class<? extends Provider> clazz = classLoader
496: .loadClass(providerClass).asSubclass(
497: Provider.class);
498: return clazz.newInstance();
499: } catch (Throwable e) {
500: logger.log(Level.WARNING,
501: "Unable to construct provider implementation "
502: + providerClass, e);
503: }
504: }
505: return null;
506: }
507:
508: private static class ProviderClassLoader extends ClassLoader {
509: private static final String PROVIDER_RESOURCE = "META-INF/services/"
510: + JAXWSPROVIDER_PROPERTY;
511: private static final URL PROVIDER_URL;
512: static {
513: try {
514: File tempFile = File.createTempFile(
515: "openejb-jaxws-provider", "tmp");
516: tempFile.deleteOnExit();
517: OutputStream out = new FileOutputStream(tempFile);
518: out.write(JaxWsProviderWrapper.class.getName()
519: .getBytes());
520: out.close();
521: PROVIDER_URL = tempFile.toURL();
522: } catch (IOException e) {
523: throw new RuntimeException(
524: "Cound not create openejb-jaxws-provider file");
525: }
526: }
527:
528: public boolean enabled = true;
529:
530: public ProviderClassLoader() {
531: }
532:
533: public ProviderClassLoader(ClassLoader parent) {
534: super (parent);
535: }
536:
537: public Enumeration<URL> getResources(String name)
538: throws IOException {
539: Enumeration<URL> resources = super .getResources(name);
540: if (enabled && PROVIDER_RESOURCE.equals(name)) {
541: ArrayList<URL> list = new ArrayList<URL>();
542: list.add(PROVIDER_URL);
543: list.addAll(Collections.list(resources));
544: resources = Collections.enumeration(list);
545: }
546: return resources;
547: }
548:
549: public URL getResource(String name) {
550: if (enabled && PROVIDER_RESOURCE.equals(name)) {
551: return PROVIDER_URL;
552: }
553: return super .getResource(name);
554: }
555: }
556:
557: //
558: // Delegate methods for JaxWS 2.1
559: //
560:
561: private static Object invoke21Delegate(Object delegate,
562: Method method, Object... args) {
563: if (method == null) {
564: throw new UnsupportedOperationException(
565: "JaxWS 2.1 APIs are not supported");
566: }
567: try {
568: return method.invoke(delegate, args);
569: } catch (IllegalAccessException e) {
570: throw new WebServiceException(e);
571: } catch (InvocationTargetException e) {
572: if (e.getCause() != null) {
573: throw new WebServiceException(e.getCause());
574: }
575: throw new WebServiceException(e);
576: }
577: }
578:
579: // Provider methods
580: private static final Method createW3CEndpointReference;
581: private static final Method providerGetPort;
582: private static final Method readEndpointReference;
583:
584: // ServiceDelegate methods
585: private static final Method createDispatchReferenceJaxB;
586: private static final Method createDispatchReferenceClass;
587: private static final Method createDispatchInterface;
588: private static final Method createDispatchJaxBContext;
589: private static final Method serviceGetPortByEndpointReference;
590: private static final Method serviceGetPortByQName;
591: private static final Method serviceGetPortByInterface;
592:
593: static {
594: Method method = null;
595: try {
596: method = Provider.class.getMethod(
597: "createW3CEndpointReference", String.class,
598: QName.class, QName.class, List.class, String.class,
599: List.class);
600: } catch (NoSuchMethodException e) {
601: }
602: createW3CEndpointReference = method;
603:
604: method = null;
605: try {
606: method = Provider.class.getMethod("getPort",
607: EndpointReference.class, Class.class,
608: WebServiceFeature[].class);
609: } catch (NoSuchMethodException e) {
610: }
611: providerGetPort = method;
612:
613: method = null;
614: try {
615: method = Provider.class.getMethod("readEndpointReference",
616: Source.class);
617: } catch (NoSuchMethodException e) {
618: }
619: readEndpointReference = method;
620:
621: method = null;
622: try {
623: method = ServiceDelegate.class.getMethod("createDispatch",
624: EndpointReference.class, JAXBContext.class,
625: Service.Mode.class, WebServiceFeature[].class);
626: } catch (NoSuchMethodException e) {
627: }
628: createDispatchReferenceJaxB = method;
629:
630: method = null;
631: try {
632: method = ServiceDelegate.class.getMethod("createDispatch",
633: EndpointReference.class, Class.class,
634: Service.Mode.class, WebServiceFeature[].class);
635: } catch (NoSuchMethodException e) {
636: }
637: createDispatchReferenceClass = method;
638:
639: method = null;
640: try {
641: method = ServiceDelegate.class.getMethod("createDispatch",
642: QName.class, JAXBContext.class, Service.Mode.class,
643: WebServiceFeature[].class);
644: } catch (NoSuchMethodException e) {
645: }
646: createDispatchJaxBContext = method;
647:
648: method = null;
649: try {
650: method = ServiceDelegate.class.getMethod("createDispatch",
651: QName.class, Class.class, Service.Mode.class,
652: WebServiceFeature[].class);
653: } catch (NoSuchMethodException e) {
654: }
655: createDispatchInterface = method;
656:
657: method = null;
658: try {
659: method = ServiceDelegate.class.getMethod("getPort",
660: EndpointReference.class, Class.class,
661: WebServiceFeature[].class);
662: } catch (NoSuchMethodException e) {
663: }
664: serviceGetPortByEndpointReference = method;
665:
666: method = null;
667: try {
668: method = ServiceDelegate.class
669: .getMethod("getPort", QName.class, Class.class,
670: WebServiceFeature[].class);
671: } catch (NoSuchMethodException e) {
672: }
673: serviceGetPortByQName = method;
674:
675: method = null;
676: try {
677: method = ServiceDelegate.class.getMethod("getPort",
678: Class.class, WebServiceFeature[].class);
679: } catch (NoSuchMethodException e) {
680: }
681: serviceGetPortByInterface = method;
682: }
683: }
|