diff --git a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java index 7b5e1708415..5a2f3ba7c4b 100644 --- a/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.java +++ b/org.springframework.web/src/main/java/org/springframework/remoting/jaxws/AbstractJaxWsServiceExporter.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. @@ -16,6 +16,7 @@ package org.springframework.remoting.jaxws; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Map; @@ -23,8 +24,10 @@ import java.util.Set; import java.util.concurrent.Executor; import javax.jws.WebService; import javax.xml.ws.Endpoint; +import javax.xml.ws.WebServiceFeature; import javax.xml.ws.WebServiceProvider; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.CannotLoadBeanClassException; @@ -32,12 +35,17 @@ import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; /** * Abstract exporter for JAX-WS services, autodetecting annotated service beans - * (through the JAX-WS {@link javax.jws.WebService} annotation). Subclasses - * need to implement the {@link #publishEndpoint} template method for actual - * endpoint exposure. + * (through the JAX-WS {@link javax.jws.WebService} annotation). + * Compatible with JAX-WS 2.0, 2.1 and 2.2. + * + *

Subclasses need to implement the {@link #publishEndpoint} template methods + * for actual endpoint exposure. * * @author Juergen Hoeller * @since 2.5.5 @@ -52,6 +60,10 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, private Executor executor; + private String bindingType; + + private Object[] webServiceFeatures; + private ListableBeanFactory beanFactory; private final Set publishedEndpoints = new LinkedHashSet(); @@ -77,6 +89,23 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, this.executor = executor; } + /** + * Specify the binding type to use, overriding the value of + * the JAX-WS {@link javax.xml.ws.BindingType} annotation. + */ + public void setBindingType(String bindingType) { + this.bindingType = bindingType; + } + + /** + * Allows for providing JAX-WS 2.2 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; + } + /** * Obtains all web service beans and publishes them as JAX-WS endpoints. */ @@ -114,7 +143,7 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, WebService wsAnnotation = type.getAnnotation(WebService.class); WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class); if (wsAnnotation != null || wsProviderAnnotation != null) { - Endpoint endpoint = Endpoint.create(this.beanFactory.getBean(beanName)); + Endpoint endpoint = createEndpoint(this.beanFactory.getBean(beanName)); if (this.endpointProperties != null) { endpoint.setProperties(this.endpointProperties); } @@ -137,6 +166,23 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, } } + /** + * Create the actual Endpoint instance. + * @param bean the service object to wrap + * @return the Endpoint instance + * @see Endpoint#create(Object) + * @see Endpoint#create(String, Object) + */ + protected Endpoint createEndpoint(Object bean) { + if (this.webServiceFeatures != null) { + return new FeatureEndpointProvider().createEndpoint(this.bindingType, bean, this.webServiceFeatures); + } + else { + return Endpoint.create(this.bindingType, bean); + } + } + + /** * Actually publish the given endpoint. To be implemented by subclasses. * @param endpoint the JAX-WS Endpoint object @@ -161,4 +207,53 @@ public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, } } + + /** + * Inner class in order to avoid a hard-coded JAX-WS 2.2 dependency. + * JAX-WS 2.0 and 2.1 didn't have WebServiceFeatures for endpoints yet... + */ + private class FeatureEndpointProvider { + + public Endpoint createEndpoint(String bindingType, Object implementor, Object[] features) { + WebServiceFeature[] wsFeatures = new WebServiceFeature[features.length]; + for (int i = 0; i < features.length; i++) { + wsFeatures[i] = convertWebServiceFeature(features[i]); + } + try { + Method create = Endpoint.class.getMethod("create", String.class, Object.class, WebServiceFeature[].class); + return (Endpoint) ReflectionUtils.invokeMethod(create, null, bindingType, implementor, wsFeatures); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("JAX-WS 2.2 not available - cannot create feature endpoints", ex); + } + } + + 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()); + } + } + + private ClassLoader getBeanClassLoader() { + return (beanFactory instanceof ConfigurableBeanFactory ? + ((ConfigurableBeanFactory) beanFactory).getBeanClassLoader() : ClassUtils.getDefaultClassLoader()); + } + } + } 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 60039cb4319..87611e725d6 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 @@ -43,8 +43,8 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** - * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a - * specific port of a JAX-WS service. + * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a specific + * port of a JAX-WS service. Compatible with JAX-WS 2.0, 2.1 and 2.2. * *

Uses either {@link LocalJaxWsServiceFactory}'s facilities underneath, * or takes an explicit reference to an existing JAX-WS Service instance @@ -515,7 +515,6 @@ public class JaxWsPortClientInterceptor extends LocalJaxWsServiceFactory throw new IllegalArgumentException("Unknown WebServiceFeature specification type: " + feature.getClass()); } } - } }