/*
* Copyright 2005-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.transport.http;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.xml.xpath.XPathExpression;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* Abstract base class for {@link WsdlDefinitionHandlerAdapter} and {@link XsdSchemaHandlerAdapter} that transforms
* XSD and WSDL location attributes.
*
* @author Arjen Poutsma
* @since 2.1.2
*/
public abstract class LocationTransformerObjectSupport extends TransformerObjectSupport {
/** Logger available to subclasses. */
private final Log logger = LogFactory.getLog(getClass());
/**
* Transforms the locations of the given definition document using the given XPath expression.
* @param xPathExpression the XPath expression
* @param definitionDocument the definition document
* @param request the request, used to determine the location to transform to
*/
protected void transformLocations(XPathExpression xPathExpression,
Document definitionDocument,
HttpServletRequest request) {
Assert.notNull(xPathExpression, "'xPathExpression' must not be null");
Assert.notNull(definitionDocument, "'definitionDocument' must not be null");
Assert.notNull(request, "'request' must not be null");
List<Node> locationNodes = xPathExpression.evaluateAsNodeList(definitionDocument);
for (Node locationNode : locationNodes) {
if (locationNode instanceof Attr) {
Attr location = (Attr) locationNode;
if (StringUtils.hasLength(location.getValue())) {
String newLocation = transformLocation(location.getValue(), request);
if (logger.isDebugEnabled()) {
logger.debug("Transforming [" + location.getValue() + "] to [" + newLocation + "]");
}
location.setValue(newLocation);
}
}
}
}
/**
* Transform the given location string to reflect the given request. If the given location is a full url, the
* scheme, server name, and port are changed. If it is a relative url, the scheme, server name, and port are
* prepended. Can be overridden in subclasses to change this behavior.
*
* <p>For instance, if the location attribute defined in the WSDL is {@code http://localhost:8080/context/services/myService},
* and the request URI for the WSDL is {@code http://example.com:80/context/myService.wsdl}, the location
* will be changed to {@code http://example.com:80/context/services/myService}.
*
* <p>If the location attribute defined in the WSDL is {@code /services/myService}, and the request URI for the
* WSDL is {@code http://example.com:8080/context/myService.wsdl}, the location will be changed to
* {@code http://example.com:8080/context/services/myService}.
*
* <p>This method is only called when the {@code transformLocations} property is true.
*/
protected String transformLocation(String location, HttpServletRequest request) {
StringBuilder url = new StringBuilder(request.getScheme());
url.append("://").append(request.getServerName()).append(':').append(request.getServerPort());
if (location.startsWith("/")) {
// a relative path, prepend the context path
url.append(request.getContextPath()).append(location);
return url.toString();
}
else {
int idx = location.indexOf("://");
if (idx != -1) {
// a full url
idx = location.indexOf('/', idx + 3);
if (idx != -1) {
String path = location.substring(idx);
url.append(path);
return url.toString();
}
}
}
// unknown location, return the original
return location;
}
}