001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.remoting.jaxws; 018 019import java.util.Arrays; 020import java.util.LinkedHashSet; 021import java.util.Map; 022import java.util.Set; 023import java.util.concurrent.Executor; 024import javax.jws.WebService; 025import javax.xml.ws.Endpoint; 026import javax.xml.ws.WebServiceFeature; 027import javax.xml.ws.WebServiceProvider; 028 029import org.springframework.beans.BeanUtils; 030import org.springframework.beans.factory.BeanFactory; 031import org.springframework.beans.factory.BeanFactoryAware; 032import org.springframework.beans.factory.CannotLoadBeanClassException; 033import org.springframework.beans.factory.DisposableBean; 034import org.springframework.beans.factory.InitializingBean; 035import org.springframework.beans.factory.ListableBeanFactory; 036import org.springframework.beans.factory.config.ConfigurableBeanFactory; 037import org.springframework.lang.UsesJava7; 038import org.springframework.util.Assert; 039import org.springframework.util.ClassUtils; 040 041/** 042 * Abstract exporter for JAX-WS services, autodetecting annotated service beans 043 * (through the JAX-WS {@link javax.jws.WebService} annotation). Compatible with 044 * JAX-WS 2.1 and 2.2, as included in JDK 6 update 4+ and Java 7/8. 045 * 046 * <p>Subclasses need to implement the {@link #publishEndpoint} template methods 047 * for actual endpoint exposure. 048 * 049 * @author Juergen Hoeller 050 * @since 2.5.5 051 * @see javax.jws.WebService 052 * @see javax.xml.ws.Endpoint 053 * @see SimpleJaxWsServiceExporter 054 * @see SimpleHttpServerJaxWsServiceExporter 055 */ 056public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean { 057 058 private Map<String, Object> endpointProperties; 059 060 private Executor executor; 061 062 private String bindingType; 063 064 private WebServiceFeature[] endpointFeatures; 065 066 private Object[] webServiceFeatures; 067 068 private ListableBeanFactory beanFactory; 069 070 private final Set<Endpoint> publishedEndpoints = new LinkedHashSet<Endpoint>(); 071 072 073 /** 074 * Set the property bag for the endpoint, including properties such as 075 * "javax.xml.ws.wsdl.service" or "javax.xml.ws.wsdl.port". 076 * @see javax.xml.ws.Endpoint#setProperties 077 * @see javax.xml.ws.Endpoint#WSDL_SERVICE 078 * @see javax.xml.ws.Endpoint#WSDL_PORT 079 */ 080 public void setEndpointProperties(Map<String, Object> endpointProperties) { 081 this.endpointProperties = endpointProperties; 082 } 083 084 /** 085 * Set the JDK concurrent executor to use for dispatching incoming requests 086 * to exported service instances. 087 * @see javax.xml.ws.Endpoint#setExecutor 088 */ 089 public void setExecutor(Executor executor) { 090 this.executor = executor; 091 } 092 093 /** 094 * Specify the binding type to use, overriding the value of 095 * the JAX-WS {@link javax.xml.ws.BindingType} annotation. 096 */ 097 public void setBindingType(String bindingType) { 098 this.bindingType = bindingType; 099 } 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}