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;
+    }
 }


Reply via email to