/* * Copyright 2005-2014 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.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.springframework.beans.factory.InitializingBean; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; import org.springframework.xml.xpath.XPathExpression; import org.springframework.xml.xpath.XPathExpressionFactory; import org.springframework.xml.xsd.XsdSchema; /** * Adapter to use the {@link XsdSchema} interface with the generic {@code DispatcherServlet}. * * <p>Reads the source from the mapped {@link XsdSchema} implementation, and writes that as the result to the * {@code HttpServletResponse}. Allows for post-processing the schema in subclasses. * * @author Arjen Poutsma * @see XsdSchema * @see #getSchemaSource(XsdSchema) * @since 1.5.3 */ public class XsdSchemaHandlerAdapter extends LocationTransformerObjectSupport implements HandlerAdapter, InitializingBean { /** * Default XPath expression used for extracting all {@code schemaLocation} attributes from the WSDL definition. */ public static final String DEFAULT_SCHEMA_LOCATION_EXPRESSION = "//@schemaLocation"; private static final String CONTENT_TYPE = "text/xml"; private Map<String, String> expressionNamespaces = new HashMap<String, String>(); private String schemaLocationExpression = DEFAULT_SCHEMA_LOCATION_EXPRESSION; private XPathExpression schemaLocationXPathExpression; private boolean transformSchemaLocations = false; /** * Sets the XPath expression used for extracting the {@code schemaLocation} attributes from the WSDL 1.1 definition. * * <p>Defaults to {@code DEFAULT_SCHEMA_LOCATION_EXPRESSION}. */ public void setSchemaLocationExpression(String schemaLocationExpression) { this.schemaLocationExpression = schemaLocationExpression; } /** * Sets whether relative address schema locations in the WSDL are to be transformed using the request URI of the * incoming {@code HttpServletRequest}. Defaults to {@code false}. */ public void setTransformSchemaLocations(boolean transformSchemaLocations) { this.transformSchemaLocations = transformSchemaLocations; } @Override public long getLastModified(HttpServletRequest request, Object handler) { Source schemaSource = ((XsdSchema) handler).getSource(); return LastModifiedHelper.getLastModified(schemaSource); } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (HttpTransportConstants.METHOD_GET.equals(request.getMethod())) { Transformer transformer = createTransformer(); Source schemaSource = getSchemaSource((XsdSchema) handler); if (transformSchemaLocations) { DOMResult domResult = new DOMResult(); transformer.transform(schemaSource, domResult); Document schemaDocument = (Document) domResult.getNode(); transformSchemaLocations(schemaDocument, request); schemaSource = new DOMSource(schemaDocument); } response.setContentType(CONTENT_TYPE); StreamResult responseResult = new StreamResult(response.getOutputStream()); transformer.transform(schemaSource, responseResult); } else { response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } return null; } @Override public boolean supports(Object handler) { return handler instanceof XsdSchema; } @Override public void afterPropertiesSet() throws Exception { schemaLocationXPathExpression = XPathExpressionFactory.createXPathExpression(schemaLocationExpression, expressionNamespaces); } /** * Returns the {@link Source} of the given schema. Allows for post-processing and transformation of the schema in * sub-classes. * * <p>Default implementation simply returns {@link XsdSchema#getSource()}. * * @param schema the schema * @return the source of the given schema * @throws Exception in case of errors */ protected Source getSchemaSource(XsdSchema schema) throws Exception { return schema.getSource(); } /** * Transforms all {@code schemaLocation} attributes to reflect the server name given {@code HttpServletRequest}. * Determines the suitable attributes by evaluating the defined XPath expression, and delegates to {@code * transformLocation} to do the transformation for all attributes that match. * * <p>This method is only called when the {@code transformSchemaLocations} property is true. * * @see #setSchemaLocationExpression(String) * @see #transformLocation(String, javax.servlet.http.HttpServletRequest) */ protected void transformSchemaLocations(Document definitionDocument, HttpServletRequest request) throws Exception { transformLocations(schemaLocationXPathExpression, definitionDocument, request); } }