Author: scheu Date: Mon Jul 12 18:32:17 2010 New Revision: 963419 URL: http://svn.apache.org/viewvc?rev=963419&view=rev Log: AXIS2-4774 Contributor:Rich Scheuerle During a JAX-WS client proxy invocation determine if the context classloader or the SEI's classloader should be used to marshal the data.
Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java?rev=963419&r1=963418&r2=963419&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/client/proxy/JAXWSProxyHandler.java Mon Jul 12 18:32:17 2010 @@ -22,6 +22,7 @@ package org.apache.axis2.jaxws.client.pr import org.apache.axis2.addressing.AddressingConstants; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.addressing.AddressingConstants.Final; +import org.apache.axis2.java.security.AccessController; import org.apache.axis2.jaxws.BindingProvider; import org.apache.axis2.jaxws.ExceptionFactory; import org.apache.axis2.jaxws.client.async.AsyncResponse; @@ -37,7 +38,10 @@ import org.apache.axis2.jaxws.descriptio import org.apache.axis2.jaxws.i18n.Messages; import org.apache.axis2.jaxws.marshaller.factory.MethodMarshallerFactory; import org.apache.axis2.jaxws.message.Message; +import org.apache.axis2.jaxws.message.databinding.JAXBUtils; import org.apache.axis2.jaxws.registry.FactoryRegistry; +import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescription; +import org.apache.axis2.jaxws.runtime.description.marshal.MarshalServiceRuntimeDescriptionFactory; import org.apache.axis2.jaxws.spi.Binding; import org.apache.axis2.jaxws.spi.Constants; import org.apache.axis2.jaxws.spi.ServiceDelegate; @@ -47,7 +51,9 @@ import org.apache.axis2.transport.http.H import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import javax.xml.bind.JAXBContext; import javax.xml.ws.AsyncHandler; +import javax.xml.ws.Holder; import javax.xml.ws.Response; import javax.xml.ws.WebServiceException; import javax.xml.ws.WebServiceFeature; @@ -55,6 +61,8 @@ import javax.xml.ws.soap.SOAPBinding; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -463,6 +471,14 @@ public class JAXWSProxyHandler extends B OperationDescription operationDesc = endpointDesc.getEndpointInterfaceDescription().getOperation(method); + MessageContext request = new MessageContext(); + + // Select a Classloader to use for marshaling + ClassLoader cl = chooseClassLoader(seiClazz, serviceDesc); + + // Make sure the same classloader is used on the response + request.setProperty(Constants.CACHE_CLASSLOADER, cl); + Message message = MethodMarshallerFactory.getMarshaller(operationDesc, true, null) .marshalRequest(args, operationDesc, this.getRequestContext()); @@ -470,7 +486,6 @@ public class JAXWSProxyHandler extends B log.debug("Request Message created successfully."); } - MessageContext request = new MessageContext(); request.setMessage(message); if (log.isDebugEnabled()) { @@ -505,7 +520,27 @@ public class JAXWSProxyHandler extends B Throwable t = getFaultResponse(responseContext, operationDesc); throw t; } + + // Get the classloader that was used for the request processing ClassLoader cl = (ClassLoader) responseContext.getProperty(Constants.CACHE_CLASSLOADER); + if (cl == null) { + InvocationContext ic = responseContext.getInvocationContext(); + if (ic != null) { + MessageContext requestMC = ic.getRequestMessageContext(); + if (requestMC != null) { + cl = (ClassLoader) responseContext.getProperty(Constants.CACHE_CLASSLOADER); + if (cl != null) { + if (log.isDebugEnabled()) { + log.debug("Obtained ClassLoader for the request context: " + cl); + } + } + } + } + } else { + if (log.isDebugEnabled()) { + log.debug("Obtained ClassLoader for the response context: " + cl); + } + } Object object = MethodMarshallerFactory.getMarshaller(operationDesc, true, cl) .demarshalResponse(responseMsg, args, operationDesc); @@ -603,4 +638,162 @@ public class JAXWSProxyHandler extends B public void setSeiClazz(Class seiClazz) { this.seiClazz = seiClazz; } + + /** + * Choose a classloader most likely to marshal the message + * successfully + * @param cls + * @return ClassLoader + */ + private static ClassLoader chooseClassLoader(Class cls, ServiceDescription serviceDesc) { + if (log.isDebugEnabled()) { + log.debug("Choose Classloader for " + cls); + } + ClassLoader cl = null; + ClassLoader contextCL = getContextClassLoader(); + ClassLoader classCL = getClassLoader(cls); + if (log.isDebugEnabled()) { + log.debug("Context ClassLoader is " + contextCL); + log.debug("Class ClassLoader is " + classCL); + } + + if (classCL == null || + contextCL == classCL) { + // Normal case: Use the context ClassLoader + cl = contextCL; + } else { + // Choose the better of the JAXBContexts + MarshalServiceRuntimeDescription marshalDesc = + MarshalServiceRuntimeDescriptionFactory.get(serviceDesc); + + // Get the JAXBContext for the context classloader + Holder<JAXBUtils.CONSTRUCTION_TYPE> holder_contextCL = new Holder<JAXBUtils.CONSTRUCTION_TYPE>(); + JAXBContext jbc_contextCL = null; + try { + jbc_contextCL = JAXBUtils.getJAXBContext(marshalDesc.getPackages(), + holder_contextCL, + marshalDesc.getPackagesKey(), + contextCL, + null); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Error occured..Processing continues " + t); + } + } + + // Get the JAXBContext using the class's ClassLoader + Holder<JAXBUtils.CONSTRUCTION_TYPE> holder_classCL = new Holder<JAXBUtils.CONSTRUCTION_TYPE>(); + JAXBContext jbc_classCL = null; + try { + jbc_classCL = JAXBUtils.getJAXBContext(marshalDesc.getPackages(), + holder_classCL, + marshalDesc.getPackagesKey(), + contextCL, + null); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Error occured..Processing continues " + t); + } + } + + // Heuristic to choose the better classloader to marshal the + // data. Slight priority given to the classloader that loaded + // the sei class. + if (jbc_classCL == null) { + // A JAXBContext could not be loaded for the class's classlaoder, + // choose the context ClassLoader + if (log.isDebugEnabled()) { + log.debug("Could not load JAXBContext for Class ClassLoader"); + } + cl = contextCL; + } else if (jbc_contextCL == null) { + // A JAXBContext could not be loaded for the context's classloader, + // choose the class ClassLoader + if (log.isDebugEnabled()) { + log.debug("Could not load JAXBContext for Context ClassLoader"); + } + cl = classCL; + } else if (holder_contextCL.value == JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH && + holder_classCL.value == JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH) { + // Both were successfully built with the context path. + // Choose the one associated with the proxy class + if (log.isDebugEnabled()) { + log.debug("Loaded both JAXBContexts with BY_CONTEXT_PATH. Choose Class ClassLoader"); + } + cl = classCL; + } else if (holder_contextCL.value == JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH) { + // Successfully found all classes with classloader, use this one + if (log.isDebugEnabled()) { + log.debug("Successfully loaded JAXBContext with Contxst ClassLoader. Choose Context ClassLoader"); + } + cl = contextCL; + } else if (holder_classCL.value == JAXBUtils.CONSTRUCTION_TYPE.BY_CONTEXT_PATH) { + // Successfully found all classes with classloader, use this one + if (log.isDebugEnabled()) { + log.debug("Successfully loaded JAXBContext with Class ClassLoader. Choose Class ClassLoader"); + } + cl = classCL; + } else { + if (log.isDebugEnabled()) { + log.debug("Default to Class ClassLoader"); + } + cl = classCL; + } + } + + + + if (log.isDebugEnabled()) { + log.debug("Chosen ClassLoader is " + cls); + } + return cl; + } + + 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; + } + + /** + * @param cls + * @return ClassLoader or null if cannot be obtained + */ + private static ClassLoader getClassLoader(final Class cls) { + // NOTE: This method must remain private because it uses AccessController + if (cls == null) { + return null; + } + 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); + } + } + + return cl; + } }