View Javadoc

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.xml.xpath.XPathExpression;
33  import org.springframework.xml.xpath.XPathExpressionFactory;
34  import org.springframework.xml.xsd.XsdSchema;
35  
36  import org.w3c.dom.Document;
37  
38  /**
39   * Adapter to use the {@link XsdSchema} interface with the generic <code>DispatcherServlet</code>.
40   * <p/>
41   * Reads the source from the mapped {@link XsdSchema} implementation, and writes that as the result to the
42   * <code>HttpServletResponse</code>. Allows for post-processing the schema in subclasses.
43   *
44   * @author Arjen Poutsma
45   * @see XsdSchema
46   * @see #getSchemaSource(XsdSchema)
47   * @since 1.5.3
48   */
49  public class XsdSchemaHandlerAdapter extends LocationTransformerObjectSupport
50          implements HandlerAdapter, InitializingBean {
51  
52      /**
53       * Default XPath expression used for extracting all {@code schemaLocation} attributes from the WSDL definition.
54       */
55      public static final String DEFAULT_SCHEMA_LOCATION_EXPRESSION = "//@schemaLocation";
56  
57      private static final String CONTENT_TYPE = "text/xml";
58  
59      private Map<String, String> expressionNamespaces = new HashMap<String, String>();
60  
61      private String schemaLocationExpression = DEFAULT_SCHEMA_LOCATION_EXPRESSION;
62  
63      private XPathExpression schemaLocationXPathExpression;
64  
65      private boolean transformSchemaLocations = false;
66  
67      /**
68       * Sets the XPath expression used for extracting the {@code schemaLocation} attributes from the WSDL 1.1 definition.
69       * <p/>
70       * Defaults to {@code DEFAULT_SCHEMA_LOCATION_EXPRESSION}.
71       */
72      public void setSchemaLocationExpression(String schemaLocationExpression) {
73          this.schemaLocationExpression = schemaLocationExpression;
74      }
75  
76      /**
77       * Sets whether relative address schema locations in the WSDL are to be transformed using the request URI of the
78       * incoming {@code HttpServletRequest}. Defaults to {@code false}.
79       */
80      public void setTransformSchemaLocations(boolean transformSchemaLocations) {
81          this.transformSchemaLocations = transformSchemaLocations;
82      }
83  
84      public long getLastModified(HttpServletRequest request, Object handler) {
85          Source schemaSource = ((XsdSchema) handler).getSource();
86          return LastModifiedHelper.getLastModified(schemaSource);
87      }
88  
89      public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
90              throws Exception {
91          if (HttpTransportConstants.METHOD_GET.equals(request.getMethod())) {
92              Transformer transformer = createTransformer();
93              Source schemaSource = getSchemaSource((XsdSchema) handler);
94  
95              if (transformSchemaLocations) {
96                  DOMResult domResult = new DOMResult();
97                  transformer.transform(schemaSource, domResult);
98                  Document schemaDocument = (Document) domResult.getNode();
99                  transformSchemaLocations(schemaDocument, request);
100                 schemaSource = new DOMSource(schemaDocument);
101             }
102 
103             response.setContentType(CONTENT_TYPE);
104             StreamResult responseResult = new StreamResult(response.getOutputStream());
105             transformer.transform(schemaSource, responseResult);
106         }
107         else {
108             response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
109         }
110         return null;
111     }
112 
113     public boolean supports(Object handler) {
114         return handler instanceof XsdSchema;
115     }
116 
117     public void afterPropertiesSet() throws Exception {
118         schemaLocationXPathExpression =
119                 XPathExpressionFactory.createXPathExpression(schemaLocationExpression, expressionNamespaces);
120     }
121 
122     /**
123      * Returns the {@link Source} of the given schema. Allows for post-processing and transformation of the schema in
124      * sub-classes.
125      * <p/>
126      * Default implementation simply returns {@link XsdSchema#getSource()}.
127      *
128      * @param schema the schema
129      * @return the source of the given schema
130      * @throws Exception in case of errors
131      */
132     protected Source getSchemaSource(XsdSchema schema) throws Exception {
133         return schema.getSource();
134     }
135 
136     /**
137      * Transforms all {@code schemaLocation} attributes to reflect the server name given {@code HttpServletRequest}.
138      * Determines the suitable attributes by evaluating the defined XPath expression, and delegates to {@code
139      * transformLocation} to do the transformation for all attributes that match.
140      * <p/>
141      * This method is only called when the {@code transformSchemaLocations} property is true.
142      *
143      * @see #setSchemaLocationExpression(String)
144      * @see #transformLocation(String, javax.servlet.http.HttpServletRequest)
145      */
146     protected void transformSchemaLocations(Document definitionDocument, HttpServletRequest request) throws Exception {
147         transformLocations(schemaLocationXPathExpression, definitionDocument, request);
148     }
149 
150 
151 }