diff --git a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java index 51b39b3dad6e4490a6f22f53167a25b7783719c3..60039cb431981dbbb2c87da0ea29798364a5655f 100644 --- a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java +++ b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortClientInterceptor.java @@ -25,17 +25,22 @@ import javax.xml.ws.BindingProvider; import javax.xml.ws.ProtocolException; import javax.xml.ws.Service; import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; import javax.xml.ws.soap.SOAPFaultException; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.InitializingBean; import org.springframework.remoting.RemoteAccessException; import org.springframework.remoting.RemoteConnectFailureException; import org.springframework.remoting.RemoteLookupFailureException; import org.springframework.remoting.RemoteProxyFailureException; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; /** * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a @@ -54,7 +59,7 @@ import org.springframework.remoting.RemoteProxyFailureException; * @see org.springframework.jndi.JndiObjectFactoryBean */ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory - implements MethodInterceptor, InitializingBean { + implements MethodInterceptor, BeanClassLoaderAware, InitializingBean { private Service jaxWsService; @@ -74,10 +79,14 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory private Map customProperties; + private Object[] webServiceFeatures; + private Class serviceInterface; private boolean lookupServiceOnStartup = true; + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + private QName portQName; private Object portStub; @@ -244,6 +253,15 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory getCustomProperties().put(name, value); } + /** + * Allows for providing JAX-WS 2.1 WebServiceFeature specifications: + * in the form of actual {@link javax.xml.ws.WebServiceFeature} objects, + * WebServiceFeature Class references, or WebServiceFeature class names. + */ + public void setWebServiceFeatures(Object[] webServiceFeatures) { + this.webServiceFeatures = webServiceFeatures; + } + /** * Set the interface of the service that this factory should create a proxy for. */ @@ -271,6 +289,23 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory this.lookupServiceOnStartup = lookupServiceOnStartup; } + /** + * Set the bean ClassLoader to use for this interceptor: + * for resolving WebServiceFeature class names as specified through + * {@link #setWebServiceFeatures}, and also for building a client + * proxy in the {@link JaxWsPortProxyFactoryBean} subclass. + */ + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + /** + * Return the bean ClassLoader to use for this interceptor. + */ + protected ClassLoader getBeanClassLoader() { + return this.beanClassLoader; + } + public void afterPropertiesSet() { if (this.lookupServiceOnStartup) { @@ -278,6 +313,9 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory } } + /** + * Initialize the JAX-WS port for this interceptor. + */ public void prepare() { if (getServiceInterface() == null) { throw new IllegalArgumentException("Property 'serviceInterface' is required"); @@ -287,8 +325,7 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory serviceToUse = createJaxWsService(); } this.portQName = getQName(getPortName() != null ? getPortName() : getServiceInterface().getName()); - Object stub = (getPortName() != null ? - serviceToUse.getPort(this.portQName, getServiceInterface()) : serviceToUse.getPort(getServiceInterface())); + Object stub = getPortStub(serviceToUse, (getPortName() != null ? this.portQName : null)); preparePortStub(stub); this.portStub = stub; } @@ -312,6 +349,23 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory return this.portQName; } + /** + * Obtain the port stub from the given JAX-WS Service. + * @param service the Service object to obtain the port from + * @param portQName the name of the desired port, if specified + * @return the corresponding port object as returned from + * Service.getPort(...) + */ + protected Object getPortStub(Service service, QName portQName) { + if (this.webServiceFeatures != null) { + return new FeaturePortProvider().getPortStub(service, portQName, this.webServiceFeatures); + } + else { + return (portQName != null ? service.getPort(portQName, getServiceInterface()) : + service.getPort(getServiceInterface())); + } + } + /** * Prepare the given JAX-WS port stub, applying properties to it. * Called by {@link #prepare}. @@ -424,4 +478,44 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory } } + + /** + * Inner class in order to avoid a hard-coded JAX-WS 2.1 dependency. + * JAX-WS 2.0, as used in Java EE 5, didn't have WebServiceFeatures yet... + */ + private class FeaturePortProvider { + + public Object getPortStub(Service service, QName portQName, Object[] features) { + WebServiceFeature[] wsFeatures = new WebServiceFeature[features.length]; + for (int i = 0; i < features.length; i++) { + wsFeatures[i] = convertWebServiceFeature(features[i]); + } + return (portQName != null ? service.getPort(portQName, getServiceInterface(), wsFeatures) : + service.getPort(getServiceInterface(), wsFeatures)); + } + + private WebServiceFeature convertWebServiceFeature(Object feature) { + Assert.notNull(feature, "WebServiceFeature specification object must not be null"); + if (feature instanceof WebServiceFeature) { + return (WebServiceFeature) feature; + } + else if (feature instanceof Class) { + return (WebServiceFeature) BeanUtils.instantiate((Class) feature); + } + else if (feature instanceof String) { + try { + Class featureClass = getBeanClassLoader().loadClass((String) feature); + return (WebServiceFeature) BeanUtils.instantiate(featureClass); + } + catch (ClassNotFoundException ex) { + throw new IllegalArgumentException("Could not load WebServiceFeature class [" + feature + "]"); + } + } + else { + throw new IllegalArgumentException("Unknown WebServiceFeature specification type: " + feature.getClass()); + } + } + + } + } diff --git a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java index fa9cfd2c0f7ddedb07d9a1da868b97768269ef39..85ddbef62e7a3475eaf3a1708533405697599d60 100644 --- a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java +++ b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/JaxWsPortProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,7 @@ package org.springframework.remoting.jaxws; import javax.xml.ws.BindingProvider; import org.springframework.aop.framework.ProxyFactory; -import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.FactoryBean; -import org.springframework.util.ClassUtils; /** * {@link org.springframework.beans.factory.FactoryBean} for a specific port of a @@ -34,17 +32,11 @@ import org.springframework.util.ClassUtils; * @see LocalJaxWsServiceFactoryBean */ public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor - implements FactoryBean, BeanClassLoaderAware { - - private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + implements FactoryBean { private Object serviceProxy; - public void setBeanClassLoader(ClassLoader classLoader) { - this.beanClassLoader = classLoader; - } - @Override public void afterPropertiesSet() { super.afterPropertiesSet(); @@ -54,7 +46,7 @@ public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor pf.addInterface(getServiceInterface()); pf.addInterface(BindingProvider.class); pf.addAdvice(this); - this.serviceProxy = pf.getProxy(this.beanClassLoader); + this.serviceProxy = pf.getProxy(getBeanClassLoader()); } diff --git a/org.springframework.web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java b/org.springframework.web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java index cdf810bcca8bf5ce1dee5d964ce99c44601b7f9a..db3af3d30a24d5b45df92c583415e9bc6fd4657c 100644 --- a/org.springframework.web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java +++ b/org.springframework.web/src/test/java/org/springframework/remoting/jaxws/JaxWsSupportTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,15 @@ package org.springframework.remoting.jaxws; import java.net.MalformedURLException; import java.net.URL; - import javax.xml.namespace.QName; import javax.xml.ws.BindingProvider; import javax.xml.ws.Service; import javax.xml.ws.WebServiceClient; import javax.xml.ws.WebServiceRef; +import javax.xml.ws.soap.AddressingFeature; -import junit.framework.TestCase; +import static org.junit.Assert.*; +import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.support.GenericBeanDefinition; @@ -37,9 +38,29 @@ import org.springframework.context.support.GenericApplicationContext; * @author Juergen Hoeller * @since 2.5 */ -public class JaxWsSupportTests extends TestCase { +public class JaxWsSupportTests { + @Test public void testJaxWsPortAccess() throws Exception { + doTestJaxWsPortAccess((Object[]) null); + } + + @Test + public void testJaxWsPortAccessWithFeatureObject() throws Exception { + doTestJaxWsPortAccess(new AddressingFeature()); + } + + @Test + public void testJaxWsPortAccessWithFeatureClass() throws Exception { + doTestJaxWsPortAccess(AddressingFeature.class); + } + + @Test + public void testJaxWsPortAccessWithFeatureString() throws Exception { + doTestJaxWsPortAccess("javax.xml.ws.soap.AddressingFeature"); + } + + private void doTestJaxWsPortAccess(Object... features) throws Exception { GenericApplicationContext ac = new GenericApplicationContext(); GenericBeanDefinition serviceDef = new GenericBeanDefinition(); @@ -60,6 +81,9 @@ public class JaxWsSupportTests extends TestCase { clientDef.getPropertyValues().add("serviceName", "OrderService"); clientDef.getPropertyValues().add("serviceInterface", OrderService.class); clientDef.getPropertyValues().add("lookupServiceOnStartup", Boolean.FALSE); + if (features != null) { + clientDef.getPropertyValues().add("webServiceFeatures", features); + } ac.registerBeanDefinition("client", clientDef); GenericBeanDefinition serviceFactoryDef = new GenericBeanDefinition();