1 /*
2 * Copyright 2005-2012 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.ws.transport.http;
18
19 import java.util.HashMap;
20 import java.util.Map;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
23 import javax.xml.transform.Source;
24 import javax.xml.transform.Transformer;
25 import javax.xml.transform.dom.DOMResult;
26 import javax.xml.transform.dom.DOMSource;
27 import javax.xml.transform.stream.StreamResult;
28
29 import org.springframework.beans.factory.InitializingBean;
30 import org.springframework.web.servlet.HandlerAdapter;
31 import org.springframework.web.servlet.ModelAndView;
32 import org.springframework.ws.wsdl.WsdlDefinition;
33 import org.springframework.xml.xpath.XPathExpression;
34 import org.springframework.xml.xpath.XPathExpressionFactory;
35
36 import org.w3c.dom.Document;
37
38 /**
39 * Adapter to use the {@code WsdlDefinition} interface with the generic {@code DispatcherServlet}.
40 * <p/>
41 * Reads the source from the mapped {@code WsdlDefinition} implementation, and writes that as the result to the
42 * {@code HttpServletResponse}.
43 * <p/>
44 * If the property {@code transformLocations} is set to {@code true}, this adapter will change
45 * {@code location} attributes in the WSDL definition to reflect the URL of the incoming request. If the location
46 * field in the original WSDL is an absolute path, the scheme, hostname, and port will be changed. If the location is a
47 * relative path, the scheme, hostname, port, and context path will be prepended. This behavior can be customized by
48 * overriding the {@code transformLocation()} method.
49 * <p/>
50 * For instance, if the location attribute defined in the WSDL is {@code http://localhost:8080/context/services/myService},
51 * and the request URI for the WSDL is {@code http://example.com/context/myService.wsdl}, the location will be
52 * changed to {@code http://example.com/context/services/myService}.
53 * <p/>
54 * If the location attribute defined in the WSDL is {@code /services/myService}, and the request URI for the WSDL
55 * is {@code http://example.com:8080/context/myService.wsdl}, the location will be changed to
56 * {@code http://example.com:8080/context/services/myService}.
57 * <p/>
58 * When {@code transformLocations} is enabled, all {@code location} attributes found in the WSDL definition
59 * are changed by default. This behavior can be customized by changing the {@code locationExpression} property,
60 * which is an XPath expression that matches the attributes to change.
61 *
62 * @author Arjen Poutsma
63 * @see WsdlDefinition
64 * @see #setTransformLocations(boolean)
65 * @see #setLocationExpression(String)
66 * @see #transformLocation(String,javax.servlet.http.HttpServletRequest)
67 * @since 1.0.0
68 */
69 public class WsdlDefinitionHandlerAdapter extends LocationTransformerObjectSupport implements HandlerAdapter, InitializingBean {
70
71 /** Default XPath expression used for extracting all {@code location} attributes from the WSDL definition. */
72 public static final String DEFAULT_LOCATION_EXPRESSION = "//@location";
73
74 /** Default XPath expression used for extracting all {@code schemaLocation} attributes from the WSDL definition. */
75 public static final String DEFAULT_SCHEMA_LOCATION_EXPRESSION = "//@schemaLocation";
76
77 private static final String CONTENT_TYPE = "text/xml";
78
79 private Map<String, String> expressionNamespaces = new HashMap<String, String>();
80
81 private String locationExpression = DEFAULT_LOCATION_EXPRESSION;
82
83 private String schemaLocationExpression = DEFAULT_SCHEMA_LOCATION_EXPRESSION;
84
85 private XPathExpression locationXPathExpression;
86
87 private XPathExpression schemaLocationXPathExpression;
88
89 private boolean transformLocations = false;
90
91 private boolean transformSchemaLocations = false;
92
93 /**
94 * Sets the XPath expression used for extracting the {@code location} attributes from the WSDL 1.1 definition.
95 * <p/>
96 * Defaults to {@code DEFAULT_LOCATION_EXPRESSION}.
97 */
98 public void setLocationExpression(String locationExpression) {
99 this.locationExpression = locationExpression;
100 }
101
102 /**
103 * Sets the XPath expression used for extracting the {@code schemaLocation} attributes from the WSDL 1.1 definition.
104 * <p/>
105 * Defaults to {@code DEFAULT_SCHEMA_LOCATION_EXPRESSION}.
106 */
107 public void setSchemaLocationExpression(String schemaLocationExpression) {
108 this.schemaLocationExpression = schemaLocationExpression;
109 }
110
111 /**
112 * Sets whether relative address locations in the WSDL are to be transformed using the request URI of the incoming
113 * {@code HttpServletRequest}. Defaults to {@code false}.
114 */
115 public void setTransformLocations(boolean transformLocations) {
116 this.transformLocations = transformLocations;
117 }
118
119 /**
120 * Sets whether relative address schema locations in the WSDL are to be transformed using the request URI of the
121 * incoming {@code HttpServletRequest}. Defaults to {@code false}.
122 */
123 public void setTransformSchemaLocations(boolean transformSchemaLocations) {
124 this.transformSchemaLocations = transformSchemaLocations;
125 }
126
127 public long getLastModified(HttpServletRequest request, Object handler) {
128 Source definitionSource = ((WsdlDefinition) handler).getSource();
129 return LastModifiedHelper.getLastModified(definitionSource);
130 }
131
132 public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
133 throws Exception {
134 if (HttpTransportConstants.METHOD_GET.equals(request.getMethod())) {
135 WsdlDefinition definition = (WsdlDefinition) handler;
136
137 Transformer transformer = createTransformer();
138 Source definitionSource = definition.getSource();
139
140 if (transformLocations || transformSchemaLocations) {
141 DOMResult domResult = new DOMResult();
142 transformer.transform(definitionSource, domResult);
143 Document definitionDocument = (Document) domResult.getNode();
144 if (transformLocations) {
145 transformLocations(definitionDocument, request);
146 }
147 if (transformSchemaLocations) {
148 transformSchemaLocations(definitionDocument, request);
149 }
150 definitionSource = new DOMSource(definitionDocument);
151 }
152
153 response.setContentType(CONTENT_TYPE);
154 StreamResult responseResult = new StreamResult(response.getOutputStream());
155 transformer.transform(definitionSource, responseResult);
156 }
157 else {
158 response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
159 }
160 return null;
161 }
162
163 public boolean supports(Object handler) {
164 return handler instanceof WsdlDefinition;
165 }
166
167 public void afterPropertiesSet() throws Exception {
168 locationXPathExpression =
169 XPathExpressionFactory.createXPathExpression(locationExpression, expressionNamespaces);
170 schemaLocationXPathExpression =
171 XPathExpressionFactory.createXPathExpression(schemaLocationExpression, expressionNamespaces);
172 }
173
174 /**
175 * Transforms all {@code location} attributes to reflect the server name given {@code HttpServletRequest}.
176 * Determines the suitable attributes by evaluating the defined XPath expression, and delegates to
177 * {@code transformLocation} to do the transformation for all attributes that match.
178 * <p/>
179 * This method is only called when the {@code transformLocations} property is true.
180 *
181 * @see #setLocationExpression(String)
182 * @see #setTransformLocations(boolean)
183 * @see #transformLocation(String,javax.servlet.http.HttpServletRequest)
184 */
185 protected void transformLocations(Document definitionDocument, HttpServletRequest request) throws Exception {
186 transformLocations(locationXPathExpression, definitionDocument, request);
187 }
188
189 /**
190 * Transforms all {@code schemaLocation} attributes to reflect the server name given {@code HttpServletRequest}.
191 * Determines the suitable attributes by evaluating the defined XPath expression, and delegates to
192 * {@code transformLocation} to do the transformation for all attributes that match.
193 * <p/>
194 * This method is only called when the {@code transformSchemaLocations} property is true.
195 *
196 * @see #setSchemaLocationExpression(String)
197 * @see #setTransformSchemaLocations(boolean)
198 * @see #transformLocation(String,javax.servlet.http.HttpServletRequest)
199 */
200 protected void transformSchemaLocations(Document definitionDocument, HttpServletRequest request) throws Exception {
201 transformLocations(schemaLocationXPathExpression, definitionDocument, request);
202 }
203
204 }