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.List;
20  import javax.servlet.http.HttpServletRequest;
21  
22  import org.springframework.util.Assert;
23  import org.springframework.util.StringUtils;
24  import org.springframework.xml.transform.TransformerObjectSupport;
25  import org.springframework.xml.xpath.XPathExpression;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.w3c.dom.Attr;
30  import org.w3c.dom.Document;
31  import org.w3c.dom.Node;
32  
33  /**
34   * Abstract base class for {@link WsdlDefinitionHandlerAdapter} and {@link XsdSchemaHandlerAdapter} that transforms
35   * XSD and WSDL location attributes.
36   *
37   * @author Arjen Poutsma
38   * @since 2.1.2
39   */
40  public abstract class LocationTransformerObjectSupport extends TransformerObjectSupport {
41  
42      /** Logger available to subclasses. */
43      private final Log logger = LogFactory.getLog(getClass());
44  
45      /**
46       * Transforms the locations of the given definition document using the given XPath expression.
47       * @param xPathExpression the XPath expression
48       * @param definitionDocument the definition document
49       * @param request the request, used to determine the location to transform to
50       */
51      protected void transformLocations(XPathExpression xPathExpression,
52                                        Document definitionDocument,
53                                        HttpServletRequest request) {
54          Assert.notNull(xPathExpression, "'xPathExpression' must not be null");
55          Assert.notNull(definitionDocument, "'definitionDocument' must not be null");
56          Assert.notNull(request, "'request' must not be null");
57  
58          List<Node> locationNodes = xPathExpression.evaluateAsNodeList(definitionDocument);
59          for (Node locationNode : locationNodes) {
60              if (locationNode instanceof Attr) {
61                  Attr location = (Attr) locationNode;
62                  if (StringUtils.hasLength(location.getValue())) {
63                      String newLocation = transformLocation(location.getValue(), request);
64                      if (logger.isDebugEnabled()) {
65                          logger.debug("Transforming [" + location.getValue() + "] to [" + newLocation + "]");
66                      }
67                      location.setValue(newLocation);
68                  }
69              }
70          }
71      }
72  
73      /**
74       * Transform the given location string to reflect the given request. If the given location is a full url, the
75       * scheme, server name, and port are changed. If it is a relative url, the scheme, server name, and port are
76       * prepended. Can be overridden in subclasses to change this behavior.
77       * <p/>
78       * For instance, if the location attribute defined in the WSDL is {@code http://localhost:8080/context/services/myService},
79       * and the request URI for the WSDL is {@code http://example.com:80/context/myService.wsdl}, the location
80       * will be changed to {@code http://example.com:80/context/services/myService}.
81       * <p/>
82       * If the location attribute defined in the WSDL is {@code /services/myService}, and the request URI for the
83       * WSDL is {@code http://example.com:8080/context/myService.wsdl}, the location will be changed to
84       * {@code http://example.com:8080/context/services/myService}.
85       * <p/>
86       * This method is only called when the {@code transformLocations} property is true.
87       */
88      protected String transformLocation(String location, HttpServletRequest request) {
89          StringBuilder url = new StringBuilder(request.getScheme());
90          url.append("://").append(request.getServerName()).append(':').append(request.getServerPort());
91          if (location.startsWith("/")) {
92              // a relative path, prepend the context path
93              url.append(request.getContextPath()).append(location);
94              return url.toString();
95          }
96          else {
97              int idx = location.indexOf("://");
98              if (idx != -1) {
99                  // a full url
100                 idx = location.indexOf('/', idx + 3);
101                 if (idx != -1) {
102                     String path = location.substring(idx);
103                     url.append(path);
104                     return url.toString();
105                 }
106             }
107         }
108         // unknown location, return the original
109         return location;
110     }
111 }