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