001/*
002 * Copyright 2002-2018 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.Collections;
020import java.util.LinkedHashSet;
021import java.util.Map;
022import java.util.Set;
023import java.util.concurrent.Executor;
024
025import javax.jws.WebService;
026import javax.xml.ws.Endpoint;
027import javax.xml.ws.WebServiceFeature;
028import javax.xml.ws.WebServiceProvider;
029
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.Nullable;
038import org.springframework.util.Assert;
039
040/**
041 * Abstract exporter for JAX-WS services, autodetecting annotated service beans
042 * (through the JAX-WS {@link javax.jws.WebService} annotation).
043 *
044 * <p>Subclasses need to implement the {@link #publishEndpoint} template methods
045 * for actual endpoint exposure.
046 *
047 * @author Juergen Hoeller
048 * @since 2.5.5
049 * @see javax.jws.WebService
050 * @see javax.xml.ws.Endpoint
051 * @see SimpleJaxWsServiceExporter
052 */
053public abstract class AbstractJaxWsServiceExporter implements BeanFactoryAware, InitializingBean, DisposableBean {
054
055        @Nullable
056        private Map<String, Object> endpointProperties;
057
058        @Nullable
059        private Executor executor;
060
061        @Nullable
062        private String bindingType;
063
064        @Nullable
065        private WebServiceFeature[] endpointFeatures;
066
067        @Nullable
068        private ListableBeanFactory beanFactory;
069
070        private final Set<Endpoint> publishedEndpoints = new LinkedHashSet<>();
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         * Obtains all web service beans and publishes them as JAX-WS endpoints.
112         */
113        @Override
114        public void setBeanFactory(BeanFactory beanFactory) {
115                if (!(beanFactory instanceof ListableBeanFactory)) {
116                        throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
117                }
118                this.beanFactory = (ListableBeanFactory) beanFactory;
119        }
120
121
122        /**
123         * Immediately publish all endpoints when fully configured.
124         * @see #publishEndpoints()
125         */
126        @Override
127        public void afterPropertiesSet() throws Exception {
128                publishEndpoints();
129        }
130
131        /**
132         * Publish all {@link javax.jws.WebService} annotated beans in the
133         * containing BeanFactory.
134         * @see #publishEndpoint
135         */
136        public void publishEndpoints() {
137                Assert.state(this.beanFactory != null, "No BeanFactory set");
138
139                Set<String> beanNames = new LinkedHashSet<>(this.beanFactory.getBeanDefinitionCount());
140                Collections.addAll(beanNames, this.beanFactory.getBeanDefinitionNames());
141                if (this.beanFactory instanceof ConfigurableBeanFactory) {
142                        Collections.addAll(beanNames, ((ConfigurableBeanFactory) this.beanFactory).getSingletonNames());
143                }
144
145                for (String beanName : beanNames) {
146                        try {
147                                Class<?> type = this.beanFactory.getType(beanName);
148                                if (type != null && !type.isInterface()) {
149                                        WebService wsAnnotation = type.getAnnotation(WebService.class);
150                                        WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
151                                        if (wsAnnotation != null || wsProviderAnnotation != null) {
152                                                Endpoint endpoint = createEndpoint(this.beanFactory.getBean(beanName));
153                                                if (this.endpointProperties != null) {
154                                                        endpoint.setProperties(this.endpointProperties);
155                                                }
156                                                if (this.executor != null) {
157                                                        endpoint.setExecutor(this.executor);
158                                                }
159                                                if (wsAnnotation != null) {
160                                                        publishEndpoint(endpoint, wsAnnotation);
161                                                }
162                                                else {
163                                                        publishEndpoint(endpoint, wsProviderAnnotation);
164                                                }
165                                                this.publishedEndpoints.add(endpoint);
166                                        }
167                                }
168                        }
169                        catch (CannotLoadBeanClassException ex) {
170                                // ignore beans where the class is not resolvable
171                        }
172                }
173        }
174
175        /**
176         * Create the actual Endpoint instance.
177         * @param bean the service object to wrap
178         * @return the Endpoint instance
179         * @see Endpoint#create(Object)
180         * @see Endpoint#create(String, Object)
181         */
182        protected Endpoint createEndpoint(Object bean) {
183                return (this.endpointFeatures != null ?
184                                Endpoint.create(this.bindingType, bean, this.endpointFeatures) :
185                                Endpoint.create(this.bindingType, bean));
186        }
187
188
189        /**
190         * Actually publish the given endpoint. To be implemented by subclasses.
191         * @param endpoint the JAX-WS Endpoint object
192         * @param annotation the service bean's WebService annotation
193         */
194        protected abstract void publishEndpoint(Endpoint endpoint, WebService annotation);
195
196        /**
197         * Actually publish the given provider endpoint. To be implemented by subclasses.
198         * @param endpoint the JAX-WS Provider Endpoint object
199         * @param annotation the service bean's WebServiceProvider annotation
200         */
201        protected abstract void publishEndpoint(Endpoint endpoint, WebServiceProvider annotation);
202
203
204        /**
205         * Stops all published endpoints, taking the web services offline.
206         */
207        @Override
208        public void destroy() {
209                for (Endpoint endpoint : this.publishedEndpoints) {
210                        endpoint.stop();
211                }
212        }
213
214}