/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.jaxws.spi; import java.lang.reflect.Field; import java.lang.reflect.Proxy; import java.net.MalformedURLException; import java.net.URL; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Iterator; import java.util.concurrent.Executor; import javax.activation.DataSource; import javax.xml.bind.JAXBContext; import javax.xml.namespace.QName; import javax.xml.soap.SOAPMessage; import javax.xml.transform.Source; import javax.xml.ws.Dispatch; import javax.xml.ws.EndpointReference; import javax.xml.ws.Service; import javax.xml.ws.WebServiceException; import javax.xml.ws.WebServiceFeature; import javax.xml.ws.Service.Mode; import javax.xml.ws.handler.HandlerResolver; import org.apache.axiom.om.OMElement; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.java.security.AccessController; import org.apache.axis2.jaxws.ExceptionFactory; import org.apache.axis2.jaxws.addressing.util.EndpointReferenceUtils; import org.apache.axis2.jaxws.client.PropertyMigrator; import org.apache.axis2.jaxws.client.dispatch.JAXBDispatch; import org.apache.axis2.jaxws.client.dispatch.XMLDispatch; import org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler; import org.apache.axis2.jaxws.description.DescriptionFactory; import org.apache.axis2.jaxws.description.EndpointDescription; import org.apache.axis2.jaxws.description.ServiceDescription; import org.apache.axis2.jaxws.description.ServiceDescriptionWSDL; import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite; import org.apache.axis2.jaxws.handler.HandlerResolverImpl; import org.apache.axis2.jaxws.i18n.Messages; import org.apache.axis2.jaxws.registry.FactoryRegistry; import org.apache.axis2.jaxws.spi.migrator.ApplicationContextMigratorUtil; import org.apache.axis2.jaxws.util.WSDLWrapper; import org.apache.axis2.jaxws.utility.ExecutorFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * The ServiceDelegate serves as the backing implementation for all of the methods in the {@link * javax.xml.ws.Service} API. This is the plug point for the client implementation. */ public class ServiceDelegate extends javax.xml.ws.spi.ServiceDelegate { private static final Log log = LogFactory.getLog(ServiceDelegate.class); private static ThreadLocal<DescriptionBuilderComposite> sparseServiceCompositeThreadLocal = new ThreadLocal<DescriptionBuilderComposite>(); private static ThreadLocal<DescriptionBuilderComposite> sparsePortCompositeThreadLocal = new ThreadLocal<DescriptionBuilderComposite>(); private Executor executor; private ServiceDescription serviceDescription; private QName serviceQname; private ServiceClient serviceClient = null; private HandlerResolver handlerResolver = null; /** * NON-STANDARD SPI! Set any metadata to be used on the creation of the NEXT Service by this thread. * NOTE that this uses ThreadLocal to store the metadata, and that ThreadLocal is cleared after it is * used to create a Service. That means: * 1) The thread that sets the metadata to use MUST be the thread that creates the Service * 2) Creation of the Service should be the very next thing the thread does * 3) The metadata will be set to null when the Service is created, so to create another * service with the same metadata, it will need to be set again prior to creating the * service * 4) The metadata can be set prior to creating both generic Service and generated Service * instances. * * This allows creating a generic Service (javax.xml.ws.Service) or a generated Service * (subclass of javax.xml.ws.Service) specifying additional metadata via a * sparse composite. This can be used by a runtime to create a Service for a requester using * additional metadata such as might come from a deployment descriptor or from resource * injection processing of @Resource or @WebServiceRef(s) annotations. Additional metadata * may include things like @WebServiceClient.wsdlLocation or a @HandlerChain specification. * * @see javax.xml.ws.Service#create(QName) * @see javax.xml.ws.Service#create(URL, QName) * * @param composite Additional metadata (if any) to be used in creation of the service */ static public void setServiceMetadata(DescriptionBuilderComposite composite) { sparseServiceCompositeThreadLocal.set(composite); } /** * NON-STANDARD SPI! Returns the composite that will be used on the creation of the next * Service by this thread. * * @see #setServiceMetadata(DescriptionBuilderComposite) * * @return composite that will be used on the creation of the next Service by this thread, or null * if no composite is to be used. */ static DescriptionBuilderComposite getServiceMetadata() { return sparseServiceCompositeThreadLocal.get(); } /** * Remove any composite so that creation of the next Service by this thread will NOT be * affected by any additional metadata. * * @see #setServiceMetadata(DescriptionBuilderComposite) * */ static void resetServiceMetadata() { sparseServiceCompositeThreadLocal.set(null); } /** * NON-STANDARD SPI! Set any metadata to be used on the creation of the NEXT Port by this thread. * NOTE that this uses ThreadLocal to store the metadata, and that ThreadLocal is cleared after it is * used to create a Port. That means: * 1) The thread that sets the metadata to use MUST be the thread that creates the Port * 2) Creation of the Port should be the very next thing the thread does * 3) The metadata will be set to null when the Port is created, so to create another * Port with the same metadata, it will need to be set again prior to creating the * Port * 4) The metadata can be set prior to creating Port which specifies a QName via * Service.getPort(QName, Class) or one that only specifies the SEI class via * Service.getPort(Class) * 5) Metadata can not be specified for dynamic ports, i.e. those added via * Service.addPort(...). * 6) Metadata can not be specfied when creating a dispatch client, i.e. via * Service.createDispatch(...) * 7) The Service used to create the port can be the generic service or a generated * service. * * This allows creating Port specifying additional metadata via a sparse composite. * This can be used by a runtime to create a Port for a requester using * additional metadata such as might come from a deployment descriptor or from resource * injection processing. Additional metadata might include things like * a @HandlerChain specification. * * @see javax.xml.ws.Service#getPort(Class) * @see javax.xml.ws.Service#getPort(QName, Class) * * @param composite Additional metadata (if any) to be used in creation of the port */ static public void setPortMetadata(DescriptionBuilderComposite composite) { sparsePortCompositeThreadLocal.set(composite); } /** * NON-STANDARD SPI! Returns the composite that will be used on the creation of the next * Port by this thread. * * @see #setPortMetadata(DescriptionBuilderComposite) * * @return composite that will be used on the creation of the next Port by this thread, or null * if no composite is to be used. */ static DescriptionBuilderComposite getPortMetadata() { return sparsePortCompositeThreadLocal.get(); } /** * Remove any composite so that creation of the next Port by this thread will NOT be * affected by any additional metadata. * * @see #setPortMetadata(DescriptionBuilderComposite) * */ static void resetPortMetadata() { sparsePortCompositeThreadLocal.set(null); } public ServiceDelegate(URL url, QName qname, Class clazz, WebServiceFeature... features) throws WebServiceException { super(); this.serviceQname = qname; if (!isValidServiceName()) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("serviceDelegateConstruct0", "")); } if ((features != null) && (features.length != 0)) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("serviceDelegateConstruct2", serviceQname.toString())); } // Get any metadata that is to be used to build up this service, then reset it so it isn't used // to create any other services. DescriptionBuilderComposite sparseComposite = getServiceMetadata(); resetServiceMetadata(); if (sparseComposite != null) { serviceDescription = DescriptionFactory.createServiceDescription(url, serviceQname, clazz, sparseComposite, this); } else { serviceDescription = DescriptionFactory.createServiceDescription(url, serviceQname, clazz); } // TODO: This check should be done when the Service Description is created above; that should throw this exception. // That is because we (following the behavior of the RI) require the WSDL be fully specified (not partial) on the client if (isValidWSDLLocation()) { if (!isServiceDefined(serviceQname)) { throw ExceptionFactory.makeWebServiceException(Messages.getMessage( "serviceDelegateConstruct0", serviceQname.toString(), url.toString())); } } //TODO: Is this the best place for this code? ConfigurationContext context = serviceDescription.getAxisConfigContext(); // Register the necessary ApplicationContextMigrators ApplicationContextMigratorUtil.addApplicationContextMigrator(context, Constants.APPLICATION_CONTEXT_MIGRATOR_LIST_ID, new PropertyMigrator()); } //================================================ // JAX-WS API methods //================================================ /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#addPort(javax.xml.namespace.QName, java.lang.String, java.lang.String) */ // Creates a DISPATCH ONLY port. Per JAXWS Sec 4.1 javax.xm..ws.Service, p. 49, ports added via addPort method // are only suitibale for creating Distpach instances. public void addPort(QName portName, String bindingId, String endpointAddress) throws WebServiceException { verifyServiceDescriptionActive(); if (log.isDebugEnabled()) { log.debug("Calling addPort : (" + portName + "," + bindingId + "," + endpointAddress + ")"); } if(endpointAddress!=null && endpointAddress.trim().length()==0){ ExceptionFactory.makeWebServiceException(Messages.getMessage("addPortErr1", (portName!=null)?portName.getLocalPart():"", endpointAddress)); } EndpointDescription endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, null, portName, DescriptionFactory.UpdateType.ADD_PORT, this, bindingId, endpointAddress); // TODO: Need to set endpointAddress and set or check bindingId on the EndpointDesc endpointDesc.setEndpointAddress(endpointAddress); endpointDesc.setClientBindingID(bindingId); } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#createDispatch(javax.xml.namespace.QName, java.lang.Class, javax.xml.ws.Service.Mode) */ public <T> Dispatch<T> createDispatch(QName portName, Class<T> type, Mode mode) throws WebServiceException { return createDispatch(portName, type, mode, (WebServiceFeature[]) null); } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#createDispatch(javax.xml.namespace.QName, javax.xml.bind.JAXBContext, javax.xml.ws.Service.Mode) */ public Dispatch<java.lang.Object> createDispatch(QName portName, JAXBContext context, Mode mode) { return createDispatch(portName, context, mode, (WebServiceFeature[]) null); } @Override public <T> Dispatch<T> createDispatch(EndpointReference jaxwsEPR, Class<T> type, Mode mode, WebServiceFeature... features) { if (log.isDebugEnabled()) { log.debug("Create Dispatch with epr: " + jaxwsEPR); } verifyServiceDescriptionActive(); if (jaxwsEPR == null) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchNoEndpointReference")); } if (!isValidDispatchType(type)) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchInvalidType")); } if (!isValidDispatchTypeWithMode(type, mode)) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchInvalidTypeWithMode")); } org.apache.axis2.addressing.EndpointReference axis2EPR = EndpointReferenceUtils.createAxis2EndpointReference(""); String addressingNamespace = null; try { addressingNamespace = EndpointReferenceUtils.convertToAxis2(axis2EPR, jaxwsEPR); } catch (Exception e) { throw ExceptionFactory. makeWebServiceException(Messages.getMessage("invalidEndpointReference", e.toString())); } EndpointDescription endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, null, axis2EPR, addressingNamespace, DescriptionFactory.UpdateType.CREATE_DISPATCH, this); if (endpointDesc == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("endpointDescriptionConstructionFailure", jaxwsEPR.toString())); } XMLDispatch<T> dispatch = new XMLDispatch<T>(this, endpointDesc, axis2EPR, addressingNamespace, features); if (mode != null) { dispatch.setMode(mode); } else { dispatch.setMode(Service.Mode.PAYLOAD); } if (serviceClient == null) serviceClient = getServiceClient(endpointDesc.getPortQName()); dispatch.setServiceClient(serviceClient); dispatch.setType(type); return dispatch; } @Override public Dispatch<Object> createDispatch(EndpointReference jaxwsEPR, JAXBContext context, Mode mode, WebServiceFeature... features) { if (log.isDebugEnabled()) { log.debug("Create Dispatch with epr 2: " + jaxwsEPR); } verifyServiceDescriptionActive(); if (jaxwsEPR == null) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchNoEndpointReference")); } org.apache.axis2.addressing.EndpointReference axis2EPR = EndpointReferenceUtils.createAxis2EndpointReference(""); String addressingNamespace = null; try { addressingNamespace = EndpointReferenceUtils.convertToAxis2(axis2EPR, jaxwsEPR); } catch (Exception e) { throw ExceptionFactory. makeWebServiceException(Messages.getMessage("invalidEndpointReference", e.toString())); } EndpointDescription endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, null, axis2EPR, addressingNamespace, DescriptionFactory.UpdateType.CREATE_DISPATCH, this); if (endpointDesc == null) { throw ExceptionFactory. makeWebServiceException(Messages.getMessage("endpointDescriptionConstructionFailure", jaxwsEPR.toString())); } JAXBDispatch<Object> dispatch = new JAXBDispatch(this, endpointDesc, axis2EPR, addressingNamespace, features); if (mode != null) { dispatch.setMode(mode); } else { dispatch.setMode(Service.Mode.PAYLOAD); } if (serviceClient == null) serviceClient = getServiceClient(endpointDesc.getPortQName()); dispatch.setJAXBContext(context); dispatch.setServiceClient(serviceClient); return dispatch; } @Override public <T> Dispatch<T> createDispatch(QName portName, Class<T> type, Mode mode, WebServiceFeature... features) { if (log.isDebugEnabled()) { log.debug("Create Dispatch with portName: " + portName); } verifyServiceDescriptionActive(); if (portName == null) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("createDispatchFail0")); } if (!isValidDispatchType(type)) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchInvalidType")); } if (!isValidDispatchTypeWithMode(type, mode)) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("dispatchInvalidTypeWithMode")); } EndpointDescription endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, null, portName, DescriptionFactory.UpdateType.CREATE_DISPATCH, this); if (endpointDesc == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("createDispatchFail2", portName.toString())); } XMLDispatch<T> dispatch = new XMLDispatch<T>(this, endpointDesc, features); if (mode != null) { dispatch.setMode(mode); } else { dispatch.setMode(Service.Mode.PAYLOAD); } if (serviceClient == null) serviceClient = getServiceClient(portName); dispatch.setServiceClient(serviceClient); dispatch.setType(type); return dispatch; } @Override public Dispatch<Object> createDispatch(QName portName, JAXBContext context, Mode mode, WebServiceFeature... features) { if (log.isDebugEnabled()) { log.debug("Create Dispatch with jaxbcontext and portName: " + portName); } verifyServiceDescriptionActive(); if (portName == null) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("createDispatchFail0")); } EndpointDescription endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, null, portName, DescriptionFactory.UpdateType.CREATE_DISPATCH, this); if (endpointDesc == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("createDispatchFail2", portName.toString())); } JAXBDispatch<Object> dispatch = new JAXBDispatch(this, endpointDesc, features); if (mode != null) { dispatch.setMode(mode); } else { dispatch.setMode(Service.Mode.PAYLOAD); } if (serviceClient == null) serviceClient = getServiceClient(portName); dispatch.setJAXBContext(context); dispatch.setServiceClient(serviceClient); return dispatch; } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getPort(java.lang.Class) */ public <T> T getPort(Class<T> sei) throws WebServiceException { return getPort((QName) null, sei, (WebServiceFeature[]) null); } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getPort(javax.xml.namespace.QName, java.lang.Class) */ public <T> T getPort(QName portName, Class<T> sei) throws WebServiceException { return getPort(portName, sei, (WebServiceFeature[]) null); } @Override public <T> T getPort(Class<T> sei, WebServiceFeature... features) { return getPort((QName) null, sei, features); } @Override public <T> T getPort(EndpointReference jaxwsEPR, Class<T> sei, WebServiceFeature... features) { /* TODO Check to see if WSDL Location is provided. * if not check WebService annotation's WSDLLocation * if both are not provided then throw exception. * (JLB): I'm not sure lack of WSDL should cause an exception */ if (log.isTraceEnabled()) { log.trace("getPort: jaxwsEPR = " + jaxwsEPR); } if (!isValidWSDLLocation()) { //TODO: Should I throw Exception if no WSDL //throw ExceptionFactory.makeWebServiceException("WSLD Not found"); } if (jaxwsEPR == null) { throw ExceptionFactory. makeWebServiceException(Messages.getMessage("dispatchNoEndpointReference2")); } if (sei == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("getPortInvalidSEI", jaxwsEPR.toString(), "null")); } org.apache.axis2.addressing.EndpointReference axis2EPR = EndpointReferenceUtils.createAxis2EndpointReference(""); String addressingNamespace = null; try { addressingNamespace = EndpointReferenceUtils.convertToAxis2(axis2EPR, jaxwsEPR); } catch (Exception e) { throw ExceptionFactory. makeWebServiceException(Messages.getMessage("invalidEndpointReference", e.toString())); } if (log.isTraceEnabled()) { log.trace("getPort: Converted jaxwsEPR to axis2EPR = " + axis2EPR); } return getPort(axis2EPR, addressingNamespace, sei, features); } @Override public <T> T getPort(QName portName, Class<T> sei, WebServiceFeature... features) { verifyServiceDescriptionActive(); /* TODO Check to see if WSDL Location is provided. * if not check WebService annotation's WSDLLocation * if both are not provided then throw exception. * (JLB): I'm not sure lack of WSDL should cause an exception */ if (!isValidWSDLLocation()) { //TODO: Should I throw Exception if no WSDL //throw ExceptionFactory.makeWebServiceException("WSLD Not found"); } if (sei == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("getPortInvalidSEI", portName.toString(), "null")); } DescriptionBuilderComposite sparseComposite = getPortMetadata(); resetPortMetadata(); EndpointDescription endpointDesc = null; if (sparseComposite != null) { endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, sei, portName, DescriptionFactory.UpdateType.GET_PORT, sparseComposite, this); } else { endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, sei, portName, DescriptionFactory.UpdateType.GET_PORT, null, this); } if (endpointDesc == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("portErr",portName.toString())); } String[] interfacesNames = new String [] {sei.getName(), org.apache.axis2.jaxws.spi.BindingProvider.class.getName()}; // As required by java.lang.reflect.Proxy, ensure that the interfaces // for the proxy are loadable by the same class loader. Class[] interfaces = null; // First, let's try loading the interfaces with the SEI classLoader ClassLoader classLoader = getClassLoader(sei); try { interfaces = loadClasses(classLoader, interfacesNames); } catch (ClassNotFoundException e1) { // Let's try with context classLoader now classLoader = getContextClassLoader(); try { interfaces = loadClasses(classLoader, interfacesNames); } catch (ClassNotFoundException e2) { throw ExceptionFactory.makeWebServiceException(Messages.getMessage("portErr1"), e2); } } JAXWSProxyHandler proxyHandler = new JAXWSProxyHandler(this, interfaces[0], endpointDesc, features); Object proxyClass = Proxy.newProxyInstance(classLoader, interfaces, proxyHandler); return sei.cast(proxyClass); } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getExecutor() */ public Executor getExecutor() { //FIXME: Use client provider executor too. if (executor == null) { executor = getDefaultExecutor(); } return executor; } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getHandlerResolver() */ public HandlerResolver getHandlerResolver() { verifyServiceDescriptionActive(); if (handlerResolver == null) { handlerResolver = new HandlerResolverImpl(serviceDescription, this); } return handlerResolver; } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getPorts() */ public Iterator<QName> getPorts() { verifyServiceDescriptionActive(); return getServiceDescription().getPorts(this).iterator(); } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getServiceName() */ public QName getServiceName() { return serviceQname; } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#getWSDLDocumentLocation() */ public URL getWSDLDocumentLocation() { verifyServiceDescriptionActive(); try { String wsdlLocation = ((ServiceDescriptionWSDL) serviceDescription).getWSDLLocation(); if(wsdlLocation == null) { return null; } return new URL(wsdlLocation); } catch (MalformedURLException e) { throw ExceptionFactory .makeWebServiceException(e); } } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#setExecutor(java.util.concurrent.Executor) */ public void setExecutor(Executor e) { if (e == null) { throw ExceptionFactory .makeWebServiceException(Messages.getMessage("cannotSetExcutorToNull")); } executor = e; } /* * (non-Javadoc) * @see javax.xml.ws.spi.ServiceDelegate#setHandlerResolver(javax.xml.ws.handler.HandlerResolver) */ public void setHandlerResolver(HandlerResolver handlerresolver) { this.handlerResolver = handlerresolver; } //================================================ // Internal public APIs //================================================ /** Get the ServiceDescription tree that this ServiceDelegate */ public ServiceDescription getServiceDescription() { return serviceDescription; } //TODO Change when ServiceDescription has to return ServiceClient or OperationClient /** * */ public ServiceClient getServiceClient(QName portQName) throws WebServiceException { verifyServiceDescriptionActive(); return serviceDescription.getServiceClient(portQName, this); } public <T> T getPort(org.apache.axis2.addressing.EndpointReference axis2EPR, String addressingNamespace, Class<T> sei, WebServiceFeature... features) { verifyServiceDescriptionActive(); DescriptionBuilderComposite sparseComposite = getPortMetadata(); resetPortMetadata(); EndpointDescription endpointDesc = null; if (sparseComposite != null) { endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, sei, axis2EPR, addressingNamespace, DescriptionFactory.UpdateType.GET_PORT, sparseComposite, this); } else { endpointDesc = DescriptionFactory.updateEndpoint(serviceDescription, sei, axis2EPR, addressingNamespace, DescriptionFactory.UpdateType.GET_PORT, null, this); } if (endpointDesc == null) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("serviceDelegateNoPort", axis2EPR.toString())); } String[] interfacesNames = new String [] {sei.getName(), org.apache.axis2.jaxws.spi.BindingProvider.class.getName()}; // As required by java.lang.reflect.Proxy, ensure that the interfaces // for the proxy are loadable by the same class loader. Class[] interfaces = null; // First, let's try loading the interfaces with the SEI classLoader ClassLoader classLoader = getClassLoader(sei); try { interfaces = loadClasses(classLoader, interfacesNames); } catch (ClassNotFoundException e1) { // Let's try with context classLoader now classLoader = getContextClassLoader(); try { interfaces = loadClasses(classLoader, interfacesNames); } catch (ClassNotFoundException e2) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("serviceDelegateProxyError", e2.getMessage())); } } JAXWSProxyHandler proxyHandler = new JAXWSProxyHandler(this, interfaces[0], endpointDesc, axis2EPR, addressingNamespace, features); Object proxyClass = Proxy.newProxyInstance(classLoader, interfaces, proxyHandler); return sei.cast(proxyClass); } //================================================ // Impl methods //================================================ //TODO: Need to make the default number of threads configurable private Executor getDefaultExecutor() { ExecutorFactory executorFactory = (ExecutorFactory) FactoryRegistry.getFactory( ExecutorFactory.class); return executorFactory.getExecutorInstance(ExecutorFactory.CLIENT_EXECUTOR); } private boolean isValidServiceName() { return serviceQname != null && !"".equals(serviceQname.toString().trim()); } private boolean isValidWSDLLocation() { URL wsdlLocation = getWSDLDocumentLocation(); return wsdlLocation != null && !"".equals(wsdlLocation.toString().trim()); } // TODO: Remove this method and put the WSDLWrapper methods on the ServiceDescriptor directly private WSDLWrapper getWSDLWrapper() { verifyServiceDescriptionActive(); return ((ServiceDescriptionWSDL)serviceDescription).getWSDLWrapper(); } private boolean isServiceDefined(QName serviceName) { return getWSDLWrapper().getService(serviceName) != null; } private boolean isValidDispatchType(Class clazz) { return clazz != null && (clazz == String.class || clazz == Source.class || clazz == DataSource.class || clazz == SOAPMessage.class || clazz == OMElement.class); } private boolean isValidDispatchTypeWithMode(Class clazz, Mode mode) { if (clazz != null && !(clazz == SOAPMessage.class && mode.equals(Service.Mode.PAYLOAD))) { return true; } else { return false; } } /** @return ClassLoader */ private static ClassLoader getClassLoader(final Class cls) { // NOTE: This method must remain private because it uses AccessController ClassLoader cl = null; try { cl = (ClassLoader)AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { return cls.getClassLoader(); } } ); } catch (PrivilegedActionException e) { if (log.isDebugEnabled()) { log.debug("Exception thrown from AccessController: " + e); } throw ExceptionFactory.makeWebServiceException(e.getException()); } return cl; } /** @return ClassLoader */ private static ClassLoader getContextClassLoader() { // NOTE: This method must remain private because it uses AccessController ClassLoader cl = null; try { cl = (ClassLoader)AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { return Thread.currentThread().getContextClassLoader(); } } ); } catch (PrivilegedActionException e) { if (log.isDebugEnabled()) { log.debug("Exception thrown from AccessController: " + e); } throw ExceptionFactory.makeWebServiceException(e.getException()); } return cl; } /** * Return the class for this name * * @return Class */ private static Class forName(final String className, final boolean initialize, final ClassLoader classLoader) throws ClassNotFoundException { // NOTE: This method must remain protected because it uses AccessController Class cl = null; try { cl = (Class)AccessController.doPrivileged( new PrivilegedExceptionAction() { public Object run() throws ClassNotFoundException { return Class.forName(className, initialize, classLoader); } } ); } catch (PrivilegedActionException e) { if (log.isDebugEnabled()) { log.debug("Exception thrown from AccessController: " + e); } throw (ClassNotFoundException)e.getException(); } return cl; } private static Class[] loadClasses(ClassLoader classLoader, String[] classNames) throws ClassNotFoundException { Class[] classes = new Class[classNames.length]; for (int i = 0; i < classNames.length; i++) { classes[i] = forName(classNames[i], true, classLoader); } return classes; } /** * PROPRIETARY METHOD TO RELEASE RESOUCES. USE OF THIS METHOD IS NOT JAX-WS COMPLIANT * AND IS NON-PORTABLE! * * This method can be called by client code to try to release * resources associated with the Service instance parameter. These resources include * the JAX-WS metadata objects (e.g. ServiceDescription, EndpointDescription) and the * associated Axis2 objects (e.g. AxisService and realted objects). Note that these * resources can be shared across multiple service delegates, and so they will not actually * be released until the last service delegate using them is closed. * * Note that it is not necessary to call this method since the service delegate finalizer * will also release the resources as appropriate. However, finalizers are not necessarily run * in a timely fashion and the timing varies across JVMs. To predictibly release resources * to prevent large memory requirements and/or OutOfMemory errors, this proprietary release * method can be called. * * @param service Instance of the Service for which resources may be released. */ public static void releaseService(Service service) { // Find the ServiceDelegate corresponding to the service to be closed // This is the back way around since there is no close on the Service ServiceDelegate serviceDelegate = getServiceDelegateForService(service); serviceDelegate.releaseServiceResources(); } private static ServiceDelegate getServiceDelegateForService(Service service) { // Need to get to the private Service._delegate ServiceDelegate returnServiceDelegate = null; try { try { Field serviceDelgateField = service.getClass().getDeclaredField("delegate"); serviceDelgateField.setAccessible(true); returnServiceDelegate = (ServiceDelegate) serviceDelgateField.get(service); } catch (NoSuchFieldException e) { // This may be a generated service subclass, so get the delegate from the superclass Field serviceDelegateField = service.getClass().getSuperclass().getDeclaredField("delegate"); serviceDelegateField.setAccessible(true); returnServiceDelegate = (ServiceDelegate) serviceDelegateField.get(service); } } catch (SecurityException e) { if (log.isDebugEnabled()) { log.debug("Attempt to get service delegate for service caught exception.", e); } throw ExceptionFactory.makeWebServiceException(e); } catch (IllegalAccessException e) { if (log.isDebugEnabled()) { log.debug("Attempt to get service delegate for service caught exception.", e); } throw ExceptionFactory.makeWebServiceException(e); } catch (NoSuchFieldException e) { if (log.isDebugEnabled()) { log.debug("Attempt to get service delegate for service caught exception.", e); } throw ExceptionFactory.makeWebServiceException(e); } return returnServiceDelegate; } /** * This can be called from the proprietary static release method (which can be called via * client code), or it can be called by the finalizer. This method tries to release resources * associated with the ServiceDelegate. Note that since other ServiceDelegates can share these * resources (e.g. ServiceDescription, EndpointDescription, AxisService), the resources may * not be releaseed until the last ServiceDelegate using them issues a close. */ private void releaseServiceResources() { if (log.isDebugEnabled()) { log.debug("ServiceDelegate.releaseServiceResouces entry"); } // This can be called indirectly by client code or by the finalizer. If it hasn't been // called yet, have the endpointDescriptions release resources. if (serviceDescription != null) { serviceDescription.releaseResources(this); serviceDescription = null; } } /** * Verify that there is an associated serviceDescription for this delegate. If not, a * webServiceException will be thrown. A serviceDelegate may have a null serviceDescription * if the client code issues the proprietary method call relealseServiceResources. */ private void verifyServiceDescriptionActive() { if (serviceDescription == null) { // TODO: This should be NLS'd throw ExceptionFactory.makeWebServiceException("Attempt to use Service after it was released"); } } protected void finalize() throws Throwable { if (log.isDebugEnabled()) { log.debug("ServiceDelegate.finalize entered for " + this); } try { releaseServiceResources(); } catch (Exception e) { if (log.isDebugEnabled()) { log.debug("ServiceDelgate Finalizer caught exception", e); } } finally { super.finalize(); } if (log.isDebugEnabled()) { log.debug("ServiceDelegate.finalize exited"); } } }