View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.remoting.jaxws;
18  
19  import java.util.Arrays;
20  import java.util.LinkedHashSet;
21  import java.util.Map;
22  import java.util.Set;
23  import java.util.concurrent.Executor;
24  import javax.jws.WebService;
25  import javax.xml.ws.Endpoint;
26  import javax.xml.ws.WebServiceFeature;
27  import javax.xml.ws.WebServiceProvider;
28  
29  import org.springframework.beans.BeanUtils;
30  import org.springframework.beans.factory.BeanFactory;
31  import org.springframework.beans.factory.BeanFactoryAware;
32  import org.springframework.beans.factory.CannotLoadBeanClassException;
33  import org.springframework.beans.factory.DisposableBean;
34  import org.springframework.beans.factory.InitializingBean;
35  import org.springframework.beans.factory.ListableBeanFactory;
36  import org.springframework.beans.factory.config.ConfigurableBeanFactory;
37  import org.springframework.lang.UsesJava7;
38  import org.springframework.util.Assert;
39  import org.springframework.util.ClassUtils;
40  
41  /**
42   * Abstract exporter for JAX-WS services, autodetecting annotated service beans
43   * (through the JAX-WS {@link javax.jws.WebService} annotation). Compatible with
44   * JAX-WS 2.1 and 2.2, as included in JDK 6 update 4+ and Java 7/8.
45   *
46   * <p>Subclasses need to implement the {@link #publishEndpoint} template methods
47   * for actual endpoint exposure.
48   *
49   * @author Juergen Hoeller
50   * @since 2.5.5
51   * @see javax.jws.WebService
52   * @see javax.xml.ws.Endpoint
53   * @see SimpleJaxWsServiceExporter
54   * @see SimpleHttpServerJaxWsServiceExporter
55   */
56  public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean {
57  
58  	private Map<String, Object> endpointProperties;
59  
60  	private Executor executor;
61  
62  	private String bindingType;
63  
64  	private WebServiceFeature[] endpointFeatures;
65  
66  	private Object[] webServiceFeatures;
67  
68  	private ListableBeanFactory beanFactory;
69  
70  	private final Set<Endpoint> publishedEndpoints = new LinkedHashSet<Endpoint>();
71  
72  
73  	/**
74  	 * Set the property bag for the endpoint, including properties such as
75  	 * "javax.xml.ws.wsdl.service" or "javax.xml.ws.wsdl.port".
76  	 * @see javax.xml.ws.Endpoint#setProperties
77  	 * @see javax.xml.ws.Endpoint#WSDL_SERVICE
78  	 * @see javax.xml.ws.Endpoint#WSDL_PORT
79  	 */
80  	public void setEndpointProperties(Map<String, Object> endpointProperties) {
81  		this.endpointProperties = endpointProperties;
82  	}
83  
84  	/**
85  	 * Set the JDK concurrent executor to use for dispatching incoming requests
86  	 * to exported service instances.
87  	 * @see javax.xml.ws.Endpoint#setExecutor
88  	 */
89  	public void setExecutor(Executor executor) {
90  		this.executor = executor;
91  	}
92  
93  	/**
94  	 * Specify the binding type to use, overriding the value of
95  	 * the JAX-WS {@link javax.xml.ws.BindingType} annotation.
96  	 */
97  	public void setBindingType(String bindingType) {
98  		this.bindingType = bindingType;
99  	}
100 
101 	/**
102 	 * Specify WebServiceFeature objects (e.g. as inner bean definitions)
103 	 * to apply to JAX-WS endpoint creation.
104 	 * @since 4.0
105 	 */
106 	public void setEndpointFeatures(WebServiceFeature... endpointFeatures) {
107 		this.endpointFeatures = endpointFeatures;
108 	}
109 
110 	/**
111 	 * Allows for providing JAX-WS 2.2 WebServiceFeature specifications:
112 	 * in the form of actual {@link javax.xml.ws.WebServiceFeature} objects,
113 	 * WebServiceFeature Class references, or WebServiceFeature class names.
114 	 * <p>As of Spring 4.0, this is effectively just an alternative way of
115 	 * specifying {@link #setEndpointFeatures "endpointFeatures"}. Do not specify
116 	 * both properties at the same time; prefer "endpointFeatures" moving forward.
117 	 * @deprecated as of Spring 4.0, in favor of {@link #setEndpointFeatures}
118 	 */
119 	@Deprecated
120 	public void setWebServiceFeatures(Object[] webServiceFeatures) {
121 		this.webServiceFeatures = webServiceFeatures;
122 	}
123 
124 	/**
125 	 * Obtains all web service beans and publishes them as JAX-WS endpoints.
126 	 */
127 	@Override
128 	public void setBeanFactory(BeanFactory beanFactory) {
129 		if (!(beanFactory instanceof ListableBeanFactory)) {
130 			throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
131 		}
132 		this.beanFactory = (ListableBeanFactory) beanFactory;
133 	}
134 
135 
136 	/**
137 	 * Immediately publish all endpoints when fully configured.
138 	 * @see #publishEndpoints()
139 	 */
140 	@Override
141 	public void afterPropertiesSet() throws Exception {
142 		publishEndpoints();
143 	}
144 
145 	/**
146 	 * Publish all {@link javax.jws.WebService} annotated beans in the
147 	 * containing BeanFactory.
148 	 * @see #publishEndpoint
149 	 */
150 	public void publishEndpoints() {
151 		Set<String> beanNames = new LinkedHashSet<String>(this.beanFactory.getBeanDefinitionCount());
152 		beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames()));
153 		if (this.beanFactory instanceof ConfigurableBeanFactory) {
154 			beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames()));
155 		}
156 		for (String beanName : beanNames) {
157 			try {
158 				Class<?> type = this.beanFactory.getType(beanName);
159 				if (type != null && !type.isInterface()) {
160 					WebService wsAnnotation = type.getAnnotation(WebService.class);
161 					WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
162 					if (wsAnnotation != null || wsProviderAnnotation != null) {
163 						Endpoint endpoint = createEndpoint(this.beanFactory.getBean(beanName));
164 						if (this.endpointProperties != null) {
165 							endpoint.setProperties(this.endpointProperties);
166 						}
167 						if (this.executor != null) {
168 							endpoint.setExecutor(this.executor);
169 						}
170 						if (wsAnnotation != null) {
171 							publishEndpoint(endpoint, wsAnnotation);
172 						}
173 						else {
174 							publishEndpoint(endpoint, wsProviderAnnotation);
175 						}
176 						this.publishedEndpoints.add(endpoint);
177 					}
178 				}
179 			}
180 			catch (CannotLoadBeanClassException ex) {
181 				// ignore beans where the class is not resolvable
182 			}
183 		}
184 	}
185 
186 	/**
187 	 * Create the actual Endpoint instance.
188 	 * @param bean the service object to wrap
189 	 * @return the Endpoint instance
190 	 * @see Endpoint#create(Object)
191 	 * @see Endpoint#create(String, Object)
192 	 */
193 	@UsesJava7  // optional use of Endpoint#create with WebServiceFeature[]
194 	protected Endpoint createEndpoint(Object bean) {
195 		if (this.endpointFeatures != null || this.webServiceFeatures != null) {
196 			WebServiceFeature[] endpointFeaturesToUse = this.endpointFeatures;
197 			if (endpointFeaturesToUse == null) {
198 				endpointFeaturesToUse = new WebServiceFeature[this.webServiceFeatures.length];
199 				for (int i = 0; i < this.webServiceFeatures.length; i++) {
200 					endpointFeaturesToUse[i] = convertWebServiceFeature(this.webServiceFeatures[i]);
201 				}
202 			}
203 			return Endpoint.create(this.bindingType, bean, endpointFeaturesToUse);
204 		}
205 		else {
206 			return Endpoint.create(this.bindingType, bean);
207 		}
208 	}
209 
210 	private WebServiceFeature convertWebServiceFeature(Object feature) {
211 		Assert.notNull(feature, "WebServiceFeature specification object must not be null");
212 		if (feature instanceof WebServiceFeature) {
213 			return (WebServiceFeature) feature;
214 		}
215 		else if (feature instanceof Class) {
216 			return (WebServiceFeature) BeanUtils.instantiate((Class<?>) feature);
217 		}
218 		else if (feature instanceof String) {
219 			try {
220 				Class<?> featureClass = getBeanClassLoader().loadClass((String) feature);
221 				return (WebServiceFeature) BeanUtils.instantiate(featureClass);
222 			}
223 			catch (ClassNotFoundException ex) {
224 				throw new IllegalArgumentException("Could not load WebServiceFeature class [" + feature + "]");
225 			}
226 		}
227 		else {
228 			throw new IllegalArgumentException("Unknown WebServiceFeature specification type: " + feature.getClass());
229 		}
230 	}
231 
232 	private ClassLoader getBeanClassLoader() {
233 		return (beanFactory instanceof ConfigurableBeanFactory ?
234 				((ConfigurableBeanFactory) beanFactory).getBeanClassLoader() : ClassUtils.getDefaultClassLoader());
235 	}
236 
237 
238 	/**
239 	 * Actually publish the given endpoint. To be implemented by subclasses.
240 	 * @param endpoint the JAX-WS Endpoint object
241 	 * @param annotation the service bean's WebService annotation
242 	 */
243 	protected abstract void publishEndpoint(Endpoint endpoint, WebService annotation);
244 
245 	/**
246 	 * Actually publish the given provider endpoint. To be implemented by subclasses.
247 	 * @param endpoint the JAX-WS Provider Endpoint object
248 	 * @param annotation the service bean's WebServiceProvider annotation
249 	 */
250 	protected abstract void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation);
251 
252 
253 	/**
254 	 * Stops all published endpoints, taking the web services offline.
255 	 */
256 	@Override
257 	public void destroy() {
258 		for (Endpoint endpoint : this.publishedEndpoints) {
259 			endpoint.stop();
260 		}
261 	}
262 
263 }