Author: nthaker Date: Thu Jun 17 15:25:12 2010 New Revision: 955636 URL: http://svn.apache.org/viewvc?rev=955636&view=rev Log: JIRA: AXIS2-4745 Changes to allow reading of Generated artifacts from a cache.
Added: axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImplTest.java Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/ClassFinder.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImpl.java axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/ArtifactProcessor.java Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java?rev=955636&r1=955635&r2=955636&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/Constants.java Thu Jun 17 15:25:12 2010 @@ -126,4 +126,8 @@ public interface Constants { * */ public static final String WRITE_HEADER_ELEMENT_IF_NULL = "jaxws.header.parameter.isNull.write.element.with.xsi.nil"; + /** + * This constant will be used to store the location of JAX-WS generated artifacts cache. + */ + public static final String WS_CACHE="wsCache"; } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/ClassFinder.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/ClassFinder.java?rev=955636&r1=955635&r2=955636&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/ClassFinder.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/ClassFinder.java Thu Jun 17 15:25:12 2010 @@ -39,4 +39,14 @@ public interface ClassFinder { */ ArrayList<Class> getClassesFromJarFile(String pkg, ClassLoader cl) throws ClassNotFoundException; + + /** + * This method will be used to add addition paths to existing classpath. + * We may need to add classpath to search for jax-ws wrapper classes that + * applicaiton developer did not package. + * @param filePath: path of the location where wrapper classes may be stored. + * example a cache folder. + * @param cl + */ + public void updateClassPath(String filePath, ClassLoader cl) throws Exception; } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImpl.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImpl.java?rev=955636&r1=955635&r2=955636&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImpl.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImpl.java Thu Jun 17 15:25:12 2010 @@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFac import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.security.PrivilegedActionException; @@ -166,4 +167,42 @@ public class ClassFinderImpl implements return cl; } + + /* (non-Javadoc) + * @see org.apache.axis2.jaxws.message.databinding.ClassFinder#updateClassPath(java.lang.String, java.lang.ClassLoader) + */ + public void updateClassPath(final String filePath, final ClassLoader cl) throws Exception{ + if(filePath == null){ + return; + } + if(filePath.length()==0){ + return; + } + if(cl instanceof URLClassLoader){ + //lets add the path to the classloader. + try{ + AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public Object run() throws Exception{ + URLClassLoader ucl = (URLClassLoader)cl; + //convert file path to URL. + File file = new File(filePath); + URL url = file.toURI().toURL(); + Class uclClass = URLClassLoader.class; + Method method = uclClass.getDeclaredMethod("addURL", new Class[]{URL.class}); + method.setAccessible(true); + method.invoke(ucl, new Object[]{url}); + return ucl; + } + } + ); + } catch (PrivilegedActionException e) { + if (log.isDebugEnabled()) { + log.debug("Exception thrown from AccessController: " + e); + } + throw ExceptionFactory.makeWebServiceException(e.getException()); + } + + } + } } Modified: axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/ArtifactProcessor.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/ArtifactProcessor.java?rev=955636&r1=955635&r2=955636&view=diff ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/ArtifactProcessor.java (original) +++ axis/axis2/java/core/trunk/modules/jaxws/src/org/apache/axis2/jaxws/runtime/description/marshal/impl/ArtifactProcessor.java Thu Jun 17 15:25:12 2010 @@ -19,27 +19,28 @@ package org.apache.axis2.jaxws.runtime.description.marshal.impl; +import java.lang.reflect.Method; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; +import java.util.Map; + import org.apache.axis2.java.security.AccessController; +import org.apache.axis2.jaxws.Constants; import org.apache.axis2.jaxws.ExceptionFactory; import org.apache.axis2.jaxws.description.EndpointDescription; import org.apache.axis2.jaxws.description.FaultDescription; import org.apache.axis2.jaxws.description.OperationDescription; import org.apache.axis2.jaxws.description.ServiceDescription; +import org.apache.axis2.jaxws.message.databinding.ClassFinder; +import org.apache.axis2.jaxws.message.factory.ClassFinderFactory; +import org.apache.axis2.jaxws.registry.FactoryRegistry; import org.apache.axis2.jaxws.runtime.description.marshal.AnnotationDesc; import org.apache.axis2.jaxws.runtime.description.marshal.FaultBeanDesc; import org.apache.axis2.jaxws.utility.ClassUtils; -import org.apache.axis2.jaxws.utility.XMLRootElementUtil; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import java.lang.reflect.Method; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.namespace.QName; - /** * Examines a ServiceDesc and locates and/or builds the JAX-WS artifacts. The JAX-WS artifacts are: * - request wrapper classes - response wrapper classes - fault beans for non-JAX-WS compliant @@ -51,16 +52,16 @@ class ArtifactProcessor { private ServiceDescription serviceDesc; private Map<OperationDescription, String> requestWrapperMap = - new HashMap<OperationDescription, String>(); + new HashMap<OperationDescription, String>(); private Map<OperationDescription, String> responseWrapperMap = - new HashMap<OperationDescription, String>(); + new HashMap<OperationDescription, String>(); private Map<OperationDescription, Method> methodMap = new HashMap<OperationDescription, Method>(); private Map<FaultDescription, FaultBeanDesc> faultBeanDescMap = - new HashMap<FaultDescription, FaultBeanDesc>(); + new HashMap<FaultDescription, FaultBeanDesc>(); static final String JAXWS_SUBPACKAGE = "jaxws"; - + /** * Artifact Processor * @@ -81,7 +82,7 @@ class ArtifactProcessor { Map<FaultDescription, FaultBeanDesc> getFaultBeanDescMap() { return faultBeanDescMap; } - + Map<OperationDescription, Method> getMethodMap() { return methodMap; } @@ -90,13 +91,13 @@ class ArtifactProcessor { for (EndpointDescription ed : serviceDesc.getEndpointDescriptions()) { if (ed.getEndpointInterfaceDescription() != null) { for (OperationDescription opDesc : ed.getEndpointInterfaceDescription() - .getOperations()) { + .getOperations()) { String declaringClassName = opDesc.getJavaDeclaringClassName(); String packageName = getPackageName(declaringClassName); String simpleName = getSimpleClassName(declaringClassName); String methodName = opDesc.getJavaMethodName(); - + // There is no default for @RequestWrapper/@ResponseWrapper classname None is listed in Sec. 7.3 on p. 80 of // the JAX-WS spec, BUT Conformance(Using javax.xml.ws.RequestWrapper) in Sec 2.3.1.2 on p. 13 @@ -107,11 +108,12 @@ class ArtifactProcessor { // @RequestWrapper className processing String requestWrapperName = opDesc.getRequestWrapperClassName(); String foundRequestWrapperName = getWrapperClass("@RequestWrapper", - requestWrapperName, - packageName, - javaMethodToClassName(methodName), - ed.getAxisService().getClassLoader()); - + requestWrapperName, + packageName, + javaMethodToClassName(methodName), + ed.getAxisService().getClassLoader(), + serviceDesc); + if (foundRequestWrapperName != null) { requestWrapperMap.put(opDesc, foundRequestWrapperName); } @@ -119,11 +121,12 @@ class ArtifactProcessor { // @ResponseWrapper className processing String responseWrapperName = opDesc.getResponseWrapperClassName(); String foundResponseWrapperName = getWrapperClass("@ResponseWrapper", - responseWrapperName, - packageName, - javaMethodToClassName(methodName) + "Response", - ed.getAxisService().getClassLoader()); - + responseWrapperName, + packageName, + javaMethodToClassName(methodName) + "Response", + ed.getAxisService().getClassLoader(), + serviceDesc); + if (foundResponseWrapperName != null) { responseWrapperMap.put(opDesc, foundResponseWrapperName); } @@ -132,7 +135,7 @@ class ArtifactProcessor { FaultBeanDesc faultBeanDesc = create(ed, faultDesc, opDesc); faultBeanDescMap.put(faultDesc, faultBeanDesc); } - + // Get the Method Class cls = null; try { @@ -140,19 +143,19 @@ class ArtifactProcessor { } catch(Exception e) { if (log.isDebugEnabled()) { log.debug("Class " + declaringClassName + " was not found by the Context ClassLoader. " + - "Will use the ClassLoader associated with the service. The exception is: " +e); + "Will use the ClassLoader associated with the service. The exception is: " +e); } } - + if (cls == null) { try { cls = loadClass(declaringClassName, ed.getAxisService().getClassLoader()); } catch(Exception e) { if (log.isDebugEnabled()) { log.debug("Class " + declaringClassName + " was not found by the AxisService ClassLoader. " + - "Processing continues. The exception is:" +e); + "Processing continues. The exception is:" +e); } - + } } if (cls != null) { @@ -161,12 +164,12 @@ class ArtifactProcessor { methodMap.put(opDesc, method); } } - + } } } } - + /** * @param type "@RequestWrapper", "@ResponseWrapper", and "@WebFault" * @param providedValue String name of the Wrapper or Fault Bean from annotations @@ -176,26 +179,27 @@ class ArtifactProcessor { * @return */ static private String getWrapperClass(String type, - String providedValue, - String defaultPkg, - String defaultClassName, - ClassLoader altClassLoader) { - + String providedValue, + String defaultPkg, + String defaultClassName, + ClassLoader altClassLoader, + ServiceDescription serviceDesc) { + if (log.isDebugEnabled()) { log.debug("getWrapperClass for " + type + " with value (" + providedValue + ")"); } - + String wrapperClass = null; try { Class cls = null; ClassLoader cl = getContextClassLoader(); if (providedValue != null && providedValue.length() > 0) { - + // If a className is provided try to load it with the context classloader // and then the alternate classloader. // If the class still cannot be loaded, then try inserting the // jaxws sub-package. - + if (log.isDebugEnabled()) { log.debug("Try finding the class with the name provided = " + providedValue); } @@ -228,6 +232,31 @@ class ArtifactProcessor { wrapperClass = newValue; } } + if(cls==null && (type.equals("@WebFault")|| type.equals("faultInfo"))){ + //As per JAX-WS 2.2 Specification section 3.7 an application programmer can choose not to + //package the faultBeans, if we have reached this point in the code then user has choosen + //not to package the fault bean. If there is a cache of generated artifacts available then + //lets look for the missing faultBean there. + + ClassFinderFactory cff = + (ClassFinderFactory)FactoryRegistry.getFactory(ClassFinderFactory.class); + ClassFinder cf = cff.getClassFinder(); + String cachePath = (String)serviceDesc.getAxisConfigContext().getProperty(Constants.WS_CACHE); + if(cachePath!=null){ + //lets add the cache to classpath and retry loading missing artifacts. + if(log.isDebugEnabled()){ + log.debug("updating classpath with cache location"); + } + cf.updateClassPath(cachePath, cl); + if(log.isDebugEnabled()){ + log.debug("trying to load class "+newValue+" from cache."); + } + cls=loadClassOrNull(newValue, cl); + if(cls!=null){ + wrapperClass=newValue; + } + } + } } } } else { @@ -255,14 +284,14 @@ class ArtifactProcessor { log.debug("No provided value. Try the default class name = " + defaultValue); } cls = loadClassOrNull(defaultValue, cl); - + if (cls == null) { cls = loadClassOrNull(defaultValue, altClassLoader); } if (cls != null) { wrapperClass = defaultValue; } - + // Now try the one in the jaxws subpackage if (cls == null) { if (defaultPkg.length() > 0) { @@ -279,6 +308,36 @@ class ArtifactProcessor { wrapperClass = defaultValue; } } + if(cls==null && (type.equals("faultInfo")|| type.equals("@WebFault"))){ + //As per JAX-WS 2.2 Specification section 3.7 an applicaiton programmer can choose not to + //package the faultBeans, if we have reached this point in the code then user has choosen + //not to package the fault bean. If there is a cache of generated artifacts available then + //lets look for the missing faultBean there. + if(log.isDebugEnabled()){ + log.debug("Adding cache to classpath"); + } + ClassFinderFactory cff = + (ClassFinderFactory)FactoryRegistry.getFactory(ClassFinderFactory.class); + ClassFinder cf = cff.getClassFinder(); + String cachePath = (String)serviceDesc.getAxisConfigContext().getProperty(Constants.WS_CACHE); + if(log.isDebugEnabled()){ + log.debug("cachePath = "+cachePath); + } + if(cachePath!=null){ + //lets add the cache to classpath and retry loading missing artifacts. + if(log.isDebugEnabled()){ + log.debug("updating classpath with cache location"); + } + cf.updateClassPath(cachePath, cl); + if(log.isDebugEnabled()){ + log.debug("trying to load class "+defaultValue+" from cache."); + } + cls=loadClassOrNull(defaultValue, cl); + if(cls!=null){ + wrapperClass=defaultValue; + } + } + } } } } @@ -291,7 +350,7 @@ class ArtifactProcessor { log.debug("exit getWrapperClass with " + wrapperClass); } return wrapperClass; - + } private FaultBeanDesc create(EndpointDescription ed, FaultDescription faultDesc, OperationDescription opDesc) { @@ -300,8 +359,8 @@ class ArtifactProcessor { * 2) If not present or invalid, the class defined by getFaultInfo. * 3) If not present, the class is found using the default name and location */ -String declaringClassName = opDesc.getJavaDeclaringClassName(); - + String declaringClassName = opDesc.getJavaDeclaringClassName(); + String type = "@WebFault"; String faultBeanClassName = faultDesc.getFaultBean(); if (faultBeanClassName == null || faultBeanClassName.length() == 0) { @@ -309,10 +368,11 @@ String declaringClassName = opDesc.getJa faultBeanClassName = faultDesc.getFaultInfo(); } String foundClassName = getWrapperClass(type, - faultBeanClassName, - getPackageName(declaringClassName), - getSimpleClassName(faultDesc.getExceptionClassName()) + "Bean", - ed.getAxisService().getClassLoader()); + faultBeanClassName, + getPackageName(declaringClassName), + getSimpleClassName(faultDesc.getExceptionClassName()) + "Bean", + ed.getAxisService().getClassLoader(), + serviceDesc); if (foundClassName == null) { faultBeanClassName = missingArtifact(faultBeanClassName); } @@ -321,10 +381,10 @@ String declaringClassName = opDesc.getJa } /* Local NameAlgorithm: - * 1) The name defined on the @WebFault of the exception. - * 2) If not present, the name defined via the @XmlRootElement of the fault bean class. - * 3) If not present, the <exceptionName>Bean - */ + * 1) The name defined on the @WebFault of the exception. + * 2) If not present, the name defined via the @XmlRootElement of the fault bean class. + * 3) If not present, the <exceptionName>Bean + */ String faultBeanLocalName = faultDesc.getName(); if (faultBeanLocalName == null || faultBeanLocalName.length() == 0) { if (faultBeanClassName != null && faultBeanClassName.length() > 0) { @@ -349,10 +409,10 @@ String declaringClassName = opDesc.getJa } /* Algorithm for fault bean namespace - * 1) The namespace defined on the @WebFault of the exception. - * 2) If not present, the namespace defined via the @XmlRootElement of the class name. - * 3) If not present, the namespace of the method's declared class + "/jaxws" - */ + * 1) The namespace defined on the @WebFault of the exception. + * 2) If not present, the namespace defined via the @XmlRootElement of the class name. + * 3) If not present, the namespace of the method's declared class + "/jaxws" + */ String faultBeanNamespace = faultDesc.getTargetNamespace(); if (faultBeanNamespace == null || faultBeanNamespace.length() == 0) { if (faultBeanClassName != null && faultBeanClassName.length() > 0) { @@ -368,7 +428,7 @@ String declaringClassName = opDesc.getJa faultBeanNamespace = aDesc.getXmlRootElementNamespace(); } } catch (Throwable t) { - throw ExceptionFactory.makeWebServiceException(t); + throw ExceptionFactory.makeWebServiceException(t); } } } @@ -377,9 +437,9 @@ String declaringClassName = opDesc.getJa } return new FaultBeanDescImpl( - faultBeanClassName, - faultBeanLocalName, - faultBeanNamespace); + faultBeanClassName, + faultBeanLocalName, + faultBeanNamespace); } /** @@ -448,7 +508,7 @@ String declaringClassName = opDesc.getJa return null; } } - + private static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { // Don't make this public, its a security exposure return forName(className, true, classLoader); @@ -460,32 +520,32 @@ String declaringClassName = opDesc.getJa * @return Class */ private static Class forName(final String className, final boolean initialize, - final ClassLoader classloader) throws ClassNotFoundException { + 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 { - // Class.forName does not support primitives - Class cls = ClassUtils.getPrimitiveClass(className); - try{ - if (cls == null) { - cls = Class.forName(className, initialize, classloader); - } - return cls; - //Lets catch NoClassDefFoundError as its part of Throwable - //Any Exception that extends Exception will be handled by doPriv method. - } catch (NoClassDefFoundError e) { - /** - * In different jaxws scenarios, some classes may be missing. So it is normal behavior - * to get to this point. The exception is swallowed and a null is returned. - * The exception is not logged...as this would give servicability folks the idea that a problem occurred. - */ - } - return cls; - } + new PrivilegedExceptionAction() { + public Object run() throws ClassNotFoundException { + // Class.forName does not support primitives + Class cls = ClassUtils.getPrimitiveClass(className); + try{ + if (cls == null) { + cls = Class.forName(className, initialize, classloader); + } + return cls; + //Lets catch NoClassDefFoundError as its part of Throwable + //Any Exception that extends Exception will be handled by doPriv method. + } catch (NoClassDefFoundError e) { + /** + * In different jaxws scenarios, some classes may be missing. So it is normal behavior + * to get to this point. The exception is swallowed and a null is returned. + * The exception is not logged...as this would give servicability folks the idea that a problem occurred. + */ + } + return cls; } + } ); } catch (PrivilegedActionException e) { /** @@ -498,7 +558,7 @@ String declaringClassName = opDesc.getJa return cl; } - + /** * Return the Method matching the method name or null * @param methodName String containing method name @@ -511,22 +571,22 @@ String declaringClassName = opDesc.getJa Method method = null; try { method = (Method)AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public Object run() { - Method[] methods = cls.getMethods(); - if (methods != null) { - for (int i=0; i<methods.length; i++) { - if (methods[i].getName().equals(methodName)) { - return methods[i]; - } + new PrivilegedExceptionAction() { + public Object run() { + Method[] methods = cls.getMethods(); + if (methods != null) { + for (int i=0; i<methods.length; i++) { + if (methods[i].getName().equals(methodName)) { + return methods[i]; } } - return null; } + return null; } + } ); } catch (PrivilegedActionException e) { - + } return method; @@ -538,11 +598,11 @@ String declaringClassName = opDesc.getJa ClassLoader cl = null; try { cl = (ClassLoader)AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public Object run() throws ClassNotFoundException { - return Thread.currentThread().getContextClassLoader(); - } + new PrivilegedExceptionAction() { + public Object run() throws ClassNotFoundException { + return Thread.currentThread().getContextClassLoader(); } + } ); } catch (PrivilegedActionException e) { if (log.isDebugEnabled()) { Added: axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImplTest.java URL: http://svn.apache.org/viewvc/axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImplTest.java?rev=955636&view=auto ============================================================================== --- axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImplTest.java (added) +++ axis/axis2/java/core/trunk/modules/jaxws/test/org/apache/axis2/jaxws/message/databinding/impl/ClassFinderImplTest.java Thu Jun 17 15:25:12 2010 @@ -0,0 +1,37 @@ + +package org.apache.axis2.jaxws.message.databinding.impl; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; + +import junit.framework.TestCase; + +public class ClassFinderImplTest extends TestCase { + + public void testUpdateClassPath() { + ClassFinderImpl finder = new ClassFinderImpl(); + URL[] mockpaths = new URL[] {}; + File f = new File("."); + String filePath = f.getAbsolutePath(); + try{ + ClassLoader cl = new MockUCL(mockpaths); + //Add a new file path to classpath + finder.updateClassPath(filePath, cl); + URL[] classPath = ((URLClassLoader)cl).getURLs(); + //check if the classpath was updated with the path. + assertNotNull("ClassPath Object cannot be null",classPath); + assertEquals("expected 1 object in path but found "+classPath.length,classPath.length, 1); + }catch(Exception e){ + fail(e.getMessage()); + } + } + class MockUCL extends URLClassLoader { + public MockUCL(URL[] urls) { + super(urls); + + } + + } +} +