001: /*
002: * Copyright 2007 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: * http://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:
017: package org.springframework.ws.transport.http;
018:
019: import java.util.Map;
020: import javax.servlet.ServletException;
021: import javax.servlet.http.HttpServletRequest;
022: import javax.servlet.http.HttpServletResponse;
023:
024: import org.springframework.beans.BeansException;
025: import org.springframework.beans.factory.BeanFactoryUtils;
026: import org.springframework.beans.factory.BeanInitializationException;
027: import org.springframework.beans.factory.BeanNameAware;
028: import org.springframework.beans.factory.NoSuchBeanDefinitionException;
029: import org.springframework.core.io.ClassPathResource;
030: import org.springframework.web.servlet.DispatcherServlet;
031: import org.springframework.web.servlet.FrameworkServlet;
032: import org.springframework.web.util.WebUtils;
033: import org.springframework.ws.WebServiceMessageFactory;
034: import org.springframework.ws.server.EndpointAdapter;
035: import org.springframework.ws.server.EndpointExceptionResolver;
036: import org.springframework.ws.server.EndpointMapping;
037: import org.springframework.ws.server.MessageDispatcher;
038: import org.springframework.ws.transport.WebServiceMessageReceiver;
039: import org.springframework.ws.transport.support.DefaultStrategiesHelper;
040: import org.springframework.ws.wsdl.WsdlDefinition;
041:
042: /**
043: * Servlet for simplified dispatching of Web service messages.
044: * <p/>
045: * This servlet is a convenient alternative to the standard Spring-MVC {@link DispatcherServlet} with separate {@link
046: * WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and {@link WsdlDefinitionHandlerAdapter}
047: * instances.
048: * <p/>
049: * This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, {@link EndpointMapping
050: * EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} <i>by type</i>.
051: * <p/>
052: * This servlet also automatically detects any {@link WsdlDefinition} defined in its application context. This WSDL is
053: * exposed under the bean name: for example, a <code>WsdlDefinition</code> bean named '<code>echo</code>' will be
054: * exposed as <code>echo.wsdl</code> in this servlet's context: <code>http://localhost:8080/spring-ws/echo.wsdl</code>.
055: * When the <code>transformWsdlLocations</code> init-param is set to <code>true</code> in this servlet's configuration
056: * in <code>web.xml</code>, all <code>location</code> attributes in the WSDL definitions will reflect the URL of the
057: * incoming request.
058: *
059: * @author Arjen Poutsma
060: * @see org.springframework.web.servlet.DispatcherServlet
061: * @see org.springframework.ws.server.MessageDispatcher
062: * @see org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter
063: * @since 1.0.0
064: */
065: public class MessageDispatcherServlet extends FrameworkServlet {
066:
067: /** Well-known name for the {@link WebServiceMessageFactory} bean in the bean factory for this namespace. */
068: public static final String DEFAULT_MESSAGE_FACTORY_BEAN_NAME = "messageFactory";
069:
070: /** Well-known name for the {@link WebServiceMessageReceiver} object in the bean factory for this namespace. */
071: public static final String DEFAULT_MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
072:
073: /**
074: * Name of the class path resource (relative to the {@link MessageDispatcherServlet} class) that defines
075: * <code>MessageDispatcherServlet's</code> default strategy names.
076: */
077: private static final String DEFAULT_STRATEGIES_PATH = "MessageDispatcherServlet.properties";
078:
079: /** Suffix of a WSDL request uri. */
080: private static final String WSDL_SUFFIX_NAME = ".wsdl";
081:
082: private final DefaultStrategiesHelper defaultStrategiesHelper;
083:
084: private String messageFactoryBeanName = DEFAULT_MESSAGE_FACTORY_BEAN_NAME;
085:
086: /** The {@link WebServiceMessageReceiverHandlerAdapter} used by this servlet. */
087: private WebServiceMessageReceiverHandlerAdapter messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter();
088:
089: /** The {@link WsdlDefinitionHandlerAdapter} used by this servlet. */
090: private WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
091:
092: private String messageReceiverBeanName = DEFAULT_MESSAGE_RECEIVER_BEAN_NAME;
093:
094: /** The {@link WebServiceMessageReceiver} used by this servlet. */
095: private WebServiceMessageReceiver messageReceiver;
096:
097: /** Keys are bean names, values are {@link WsdlDefinition WsdlDefinitions}. */
098: private Map wsdlDefinitions;
099:
100: private boolean transformWsdlLocations = false;
101:
102: /** Public constructor, necessary for some Web application servers. */
103: public MessageDispatcherServlet() {
104: defaultStrategiesHelper = new DefaultStrategiesHelper(
105: new ClassPathResource(DEFAULT_STRATEGIES_PATH,
106: MessageDispatcherServlet.class));
107: }
108:
109: /** Returns the bean name used to lookup a {@link WebServiceMessageFactory}. */
110: public String getMessageFactoryBeanName() {
111: return messageFactoryBeanName;
112: }
113:
114: /**
115: * Sets the bean name used to lookup a {@link WebServiceMessageFactory}. Defaults to {@link
116: * #DEFAULT_MESSAGE_FACTORY_BEAN_NAME}.
117: */
118: public void setMessageFactoryBeanName(String messageFactoryBeanName) {
119: this .messageFactoryBeanName = messageFactoryBeanName;
120: }
121:
122: /** Returns the bean name used to lookup a {@link WebServiceMessageReceiver}. */
123: public String getMessageReceiverBeanName() {
124: return messageReceiverBeanName;
125: }
126:
127: /**
128: * Sets the bean name used to lookup a {@link WebServiceMessageReceiver}. Defaults to {@link
129: * #DEFAULT_MESSAGE_RECEIVER_BEAN_NAME}.
130: */
131: public void setMessageReceiverBeanName(
132: String messageReceiverBeanName) {
133: this .messageReceiverBeanName = messageReceiverBeanName;
134: }
135:
136: /**
137: * Indicates whether relative address locations in the WSDL are to be transformed using the request URI of the
138: * incoming {@link HttpServletRequest}.
139: */
140: public boolean isTransformWsdlLocations() {
141: return transformWsdlLocations;
142: }
143:
144: /**
145: * Sets whether relative address locations in the WSDL are to be transformed using the request URI of the incoming
146: * {@link HttpServletRequest}. Defaults to <code>false</code>.
147: */
148: public void setTransformWsdlLocations(boolean transformWsdlLocations) {
149: this .transformWsdlLocations = transformWsdlLocations;
150: }
151:
152: protected void doService(HttpServletRequest httpServletRequest,
153: HttpServletResponse httpServletResponse) throws Exception {
154: WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
155: if (definition != null) {
156: wsdlDefinitionHandlerAdapter.handle(httpServletRequest,
157: httpServletResponse, definition);
158: } else {
159: messageReceiverHandlerAdapter.handle(httpServletRequest,
160: httpServletResponse, messageReceiver);
161: }
162: }
163:
164: protected void initFrameworkServlet() throws ServletException,
165: BeansException {
166: initHandlerAdapters();
167: initMessageReceiver();
168: initWsdlDefinitions();
169: }
170:
171: protected long getLastModified(HttpServletRequest httpServletRequest) {
172: WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
173: if (definition != null) {
174: return wsdlDefinitionHandlerAdapter.getLastModified(
175: httpServletRequest, definition);
176: } else {
177: return messageReceiverHandlerAdapter.getLastModified(
178: httpServletRequest, messageReceiver);
179: }
180: }
181:
182: /** Returns the {@link WebServiceMessageReceiver} used by this servlet. */
183: protected WebServiceMessageReceiver getMessageReceiver() {
184: return messageReceiver;
185: }
186:
187: /**
188: * Determines the {@link WsdlDefinition} for a given request, or <code>null</code> if none is found.
189: * <p/>
190: * Default implementation checks whether the request method is <code>GET</code>, whether the request uri ends with
191: * <code>".wsdl"</code>, and if there is a <code>WsdlDefinition</code> with the same name as the filename in the
192: * request uri.
193: *
194: * @param request the <code>HttpServletRequest</code>
195: * @return a definition, or <code>null</code>
196: */
197: protected WsdlDefinition getWsdlDefinition(
198: HttpServletRequest request) {
199: if ("GET".equals(request.getMethod())
200: && request.getRequestURI().endsWith(WSDL_SUFFIX_NAME)) {
201: String fileName = WebUtils
202: .extractFilenameFromUrlPath(request.getRequestURI());
203: return (WsdlDefinition) wsdlDefinitions.get(fileName);
204: } else {
205: return null;
206: }
207: }
208:
209: private void initHandlerAdapters() throws BeansException {
210: try {
211: // setup the receiver adapter
212: messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter();
213: initWebServiceMessageFactory();
214: messageReceiverHandlerAdapter.afterPropertiesSet();
215: // setup the wsdl adapter
216: wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
217: wsdlDefinitionHandlerAdapter
218: .setTransformLocations(isTransformWsdlLocations());
219: wsdlDefinitionHandlerAdapter.afterPropertiesSet();
220: } catch (Exception ex) {
221: throw new BeanInitializationException(
222: "Could not initialize handler adapters", ex);
223: }
224: }
225:
226: private void initWebServiceMessageFactory() throws Exception {
227: WebServiceMessageFactory messageFactory;
228: try {
229: messageFactory = (WebServiceMessageFactory) getWebApplicationContext()
230: .getBean(getMessageFactoryBeanName(),
231: WebServiceMessageFactory.class);
232: } catch (NoSuchBeanDefinitionException ignored) {
233: messageFactory = (WebServiceMessageFactory) defaultStrategiesHelper
234: .getDefaultStrategy(WebServiceMessageFactory.class,
235: getWebApplicationContext());
236: if (logger.isDebugEnabled()) {
237: logger
238: .debug("No WebServiceMessageFactory found in servlet '"
239: + getServletName() + "': using default");
240: }
241: }
242: messageReceiverHandlerAdapter.setMessageFactory(messageFactory);
243: }
244:
245: private void initMessageReceiver() {
246: try {
247: messageReceiver = (WebServiceMessageReceiver) getWebApplicationContext()
248: .getBean(getMessageReceiverBeanName(),
249: WebServiceMessageReceiver.class);
250: } catch (NoSuchBeanDefinitionException ex) {
251: messageReceiver = (WebServiceMessageReceiver) defaultStrategiesHelper
252: .getDefaultStrategy(
253: WebServiceMessageReceiver.class,
254: getWebApplicationContext());
255: if (messageReceiver instanceof BeanNameAware) {
256: ((BeanNameAware) messageReceiver)
257: .setBeanName(getServletName());
258: }
259: if (logger.isDebugEnabled()) {
260: logger.debug("No MessageDispatcher found in servlet '"
261: + getServletName() + "': using default");
262: }
263: }
264: }
265:
266: /** Find all {@link WsdlDefinition WsdlDefinitions} in the ApplicationContext, incuding ancestor contexts. */
267: private void initWsdlDefinitions() {
268: wsdlDefinitions = BeanFactoryUtils
269: .beansOfTypeIncludingAncestors(
270: getWebApplicationContext(),
271: WsdlDefinition.class, true, false);
272: }
273: }
|