Package org.springframework.ws.transport.http

Source Code of org.springframework.ws.transport.http.MessageDispatcherServlet

/*
* 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.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.util.WebUtils;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.EndpointExceptionResolver;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.support.DefaultStrategiesHelper;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.wsdl.WsdlDefinition;
import org.springframework.xml.xsd.XsdSchema;

/**
* Servlet for simplified dispatching of Web service messages.
*
* <p>This servlet is a convenient alternative to the standard Spring-MVC {@link DispatcherServlet} with separate {@link
* WebServiceMessageReceiverHandlerAdapter}, {@link MessageDispatcher}, and {@link WsdlDefinitionHandlerAdapter}
* instances.
*
* <p>This servlet automatically detects {@link EndpointAdapter EndpointAdapters}, {@link EndpointMapping
* EndpointMappings}, and {@link EndpointExceptionResolver EndpointExceptionResolvers} <i>by type</i>.
*
* <p>This servlet also automatically detects any {@link WsdlDefinition} defined in its application context. This WSDL is
* exposed under the bean name: for example, a {@code WsdlDefinition} bean named '{@code echo}' will be
* exposed as {@code echo.wsdl} in this servlet's context: {@code http://localhost:8080/spring-ws/echo.wsdl}.
* When the {@code transformWsdlLocations} init-param is set to {@code true} in this servlet's configuration
* in {@code web.xml}, all {@code location} attributes in the WSDL definitions will reflect the URL of the
* incoming request.
*
* @author Arjen Poutsma
* @see org.springframework.web.servlet.DispatcherServlet
* @see org.springframework.ws.server.MessageDispatcher
* @see org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter
* @since 1.0.0
*/
@SuppressWarnings("serial")
public class MessageDispatcherServlet extends FrameworkServlet {

    /** Well-known name for the {@link WebServiceMessageFactory} bean in the bean factory for this namespace. */
    public static final String DEFAULT_MESSAGE_FACTORY_BEAN_NAME = "messageFactory";

    /** Well-known name for the {@link WebServiceMessageReceiver} object in the bean factory for this namespace. */
    public static final String DEFAULT_MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";

    /**
     * Well-known name for the {@link WebServiceMessageReceiverHandlerAdapter} object in the bean factory for this
     * namespace.
     */
    public static final String DEFAULT_MESSAGE_RECEIVER_HANDLER_ADAPTER_BEAN_NAME = "messageReceiverHandlerAdapter";

    /** Well-known name for the {@link WsdlDefinitionHandlerAdapter} object in the bean factory for this namespace. */
    public static final String DEFAULT_WSDL_DEFINITION_HANDLER_ADAPTER_BEAN_NAME = "wsdlDefinitionHandlerAdapter";

    /** Well-known name for the {@link XsdSchemaHandlerAdapter} object in the bean factory for this namespace. */
    public static final String DEFAULT_XSD_SCHEMA_HANDLER_ADAPTER_BEAN_NAME = "xsdSchemaHandlerAdapter";

    /** Suffix of a WSDL request uri. */
    private static final String WSDL_SUFFIX_NAME = ".wsdl";

    /** Suffix of a XSD request uri. */
    private static final String XSD_SUFFIX_NAME = ".xsd";

    private final DefaultStrategiesHelper defaultStrategiesHelper;

    private String messageFactoryBeanName = DEFAULT_MESSAGE_FACTORY_BEAN_NAME;

    private String messageReceiverHandlerAdapterBeanName = DEFAULT_MESSAGE_RECEIVER_HANDLER_ADAPTER_BEAN_NAME;

    /** The {@link WebServiceMessageReceiverHandlerAdapter} used by this servlet. */
    private WebServiceMessageReceiverHandlerAdapter messageReceiverHandlerAdapter;

    private String wsdlDefinitionHandlerAdapterBeanName = DEFAULT_WSDL_DEFINITION_HANDLER_ADAPTER_BEAN_NAME;

    /** The {@link WsdlDefinitionHandlerAdapter} used by this servlet. */
    private WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter;

    private String xsdSchemaHandlerAdapterBeanName = DEFAULT_XSD_SCHEMA_HANDLER_ADAPTER_BEAN_NAME;

    /** The {@link XsdSchemaHandlerAdapter} used by this servlet. */
    private XsdSchemaHandlerAdapter xsdSchemaHandlerAdapter;

    private String messageReceiverBeanName = DEFAULT_MESSAGE_RECEIVER_BEAN_NAME;

    /** The {@link WebServiceMessageReceiver} used by this servlet. */
    private WebServiceMessageReceiver messageReceiver;

    /** Keys are bean names, values are {@link WsdlDefinition WsdlDefinitions}. */
    private Map<String, WsdlDefinition> wsdlDefinitions;

    private Map<String, XsdSchema> xsdSchemas;

    private boolean transformWsdlLocations = false;

    private boolean transformSchemaLocations = false;

    /**
     * Public constructor, necessary for some Web application servers.
     */
    public MessageDispatcherServlet() {
        this(null);
    }

    /**
     * Constructor to support programmatic configuration of the Servlet with the specified
     * web application context. This constructor is useful in Servlet 3.0+ environments
     * where instance-based registration of servlets is possible through the
     * {@code ServletContext#addServlet} API.
     * <p>Using this constructor indicates that the following properties / init-params
     * will be ignored:
     * <ul>
     * <li>{@link #setContextClass(Class)} / 'contextClass'</li>
     * <li>{@link #setContextConfigLocation(String)} / 'contextConfigLocation'</li>
     * <li>{@link #setContextAttribute(String)} / 'contextAttribute'</li>
     * <li>{@link #setNamespace(String)} / 'namespace'</li>
     * </ul>
     * <p>The given web application context may or may not yet be {@linkplain
     * org.springframework.web.context.ConfigurableWebApplicationContext#refresh() refreshed}.
     * If it has <strong>not</strong> already been refreshed (the recommended approach), then
     * the following will occur:
     * <ul>
     * <li>If the given context does not already have a {@linkplain
     * org.springframework.web.context.ConfigurableWebApplicationContext#setParent parent},
     * the root application context will be set as the parent.</li>
     * <li>If the given context has not already been assigned an {@linkplain
     * org.springframework.web.context.ConfigurableWebApplicationContext#setId id}, one
     * will be assigned to it</li>
     * <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to
     * the application context</li>
     * <li>{@link #postProcessWebApplicationContext} will be called</li>
     * <li>Any {@code ApplicationContextInitializer}s specified through the
     * "contextInitializerClasses" init-param or through the {@link
     * #setContextInitializers} property will be applied.</li>
     * <li>{@link org.springframework.web.context.ConfigurableWebApplicationContext#refresh refresh()}
     * will be called if the context implements
     * {@link org.springframework.web.context.ConfigurableWebApplicationContext}</li>
     * </ul>
     * If the context has already been refreshed, none of the above will occur, under the
     * assumption that the user has performed these actions (or not) per their specific
     * needs.
     * <p>See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
     *
     * @param webApplicationContext the context to use
     * @see FrameworkServlet#FrameworkServlet(WebApplicationContext)
     * @see org.springframework.web.WebApplicationInitializer
     * @see #initWebApplicationContext()
     * @see #configureAndRefreshWebApplicationContext(org.springframework.web.context.ConfigurableWebApplicationContext)
     */
    public MessageDispatcherServlet(WebApplicationContext webApplicationContext) {
        super(webApplicationContext);
        defaultStrategiesHelper = new DefaultStrategiesHelper(MessageDispatcherServlet.class);
    }

    /** Returns the bean name used to lookup a {@link WebServiceMessageFactory}. */
    public String getMessageFactoryBeanName() {
        return messageFactoryBeanName;
    }

    /**
     * Sets the bean name used to lookup a {@link WebServiceMessageFactory}. Defaults to {@link
     * #DEFAULT_MESSAGE_FACTORY_BEAN_NAME}.
     */
    public void setMessageFactoryBeanName(String messageFactoryBeanName) {
        this.messageFactoryBeanName = messageFactoryBeanName;
    }

    /** Returns the bean name used to lookup a {@link WebServiceMessageReceiver}. */
    public String getMessageReceiverBeanName() {
        return messageReceiverBeanName;
    }

    /**
     * Sets the bean name used to lookup a {@link WebServiceMessageReceiver}. Defaults to {@link
     * #DEFAULT_MESSAGE_RECEIVER_BEAN_NAME}.
     */
    public void setMessageReceiverBeanName(String messageReceiverBeanName) {
        this.messageReceiverBeanName = messageReceiverBeanName;
    }

    /**
     * Indicates whether relative address locations in the WSDL are to be transformed using the request URI of the
     * incoming {@link HttpServletRequest}.
     */
    public boolean isTransformWsdlLocations() {
        return transformWsdlLocations;
    }

    /**
     * Sets whether relative address locations in the WSDL are to be transformed using the request URI of the incoming
     * {@link HttpServletRequest}. Defaults to {@code false}.
     */
    public void setTransformWsdlLocations(boolean transformWsdlLocations) {
        this.transformWsdlLocations = transformWsdlLocations;
    }

    /**
     * Indicates whether relative address locations in the XSD are to be transformed using the request URI of the
     * incoming {@link HttpServletRequest}.
     */
    public boolean isTransformSchemaLocations() {
        return transformSchemaLocations;
    }

    /**
     * Sets whether relative address locations in the XSD are to be transformed using the request URI of the incoming
     * {@link HttpServletRequest}. Defaults to {@code false}.
     */
    public void setTransformSchemaLocations(boolean transformSchemaLocations) {
        this.transformSchemaLocations = transformSchemaLocations;
    }

    /** Returns the bean name used to lookup a {@link WebServiceMessageReceiverHandlerAdapter}. */
    public String getMessageReceiverHandlerAdapterBeanName() {
        return messageReceiverHandlerAdapterBeanName;
    }

    /**
     * Sets the bean name used to lookup a {@link WebServiceMessageReceiverHandlerAdapter}. Defaults to {@link
     * #DEFAULT_MESSAGE_RECEIVER_HANDLER_ADAPTER_BEAN_NAME}.
     */
    public void setMessageReceiverHandlerAdapterBeanName(String messageReceiverHandlerAdapterBeanName) {
        this.messageReceiverHandlerAdapterBeanName = messageReceiverHandlerAdapterBeanName;
    }

    /** Returns the bean name used to lookup a {@link WsdlDefinitionHandlerAdapter}. */
    public String getWsdlDefinitionHandlerAdapterBeanName() {
        return wsdlDefinitionHandlerAdapterBeanName;
    }

    /**
     * Sets the bean name used to lookup a {@link WsdlDefinitionHandlerAdapter}. Defaults to {@link
     * #DEFAULT_WSDL_DEFINITION_HANDLER_ADAPTER_BEAN_NAME}.
     */
    public void setWsdlDefinitionHandlerAdapterBeanName(String wsdlDefinitionHandlerAdapterBeanName) {
        this.wsdlDefinitionHandlerAdapterBeanName = wsdlDefinitionHandlerAdapterBeanName;
    }

    /** Returns the bean name used to lookup a {@link XsdSchemaHandlerAdapter}. */
    public String getXsdSchemaHandlerAdapterBeanName() {
        return xsdSchemaHandlerAdapterBeanName;
    }

    /**
     * Sets the bean name used to lookup a {@link XsdSchemaHandlerAdapter}. Defaults to {@link
     * #DEFAULT_XSD_SCHEMA_HANDLER_ADAPTER_BEAN_NAME}.
     */
    public void setXsdSchemaHandlerAdapterBeanName(String xsdSchemaHandlerAdapterBeanName) {
        this.xsdSchemaHandlerAdapterBeanName = xsdSchemaHandlerAdapterBeanName;
    }


    @Override
    protected void doService(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
            throws Exception {
        WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
        if (definition != null) {
            wsdlDefinitionHandlerAdapter.handle(httpServletRequest, httpServletResponse, definition);
            return;
        }
        XsdSchema schema = getXsdSchema(httpServletRequest);
        if (schema != null) {
            xsdSchemaHandlerAdapter.handle(httpServletRequest, httpServletResponse, schema);
            return;
        }
        messageReceiverHandlerAdapter.handle(httpServletRequest, httpServletResponse, messageReceiver);
    }

    /**
     * This implementation calls {@link #initStrategies}.
     */
    @Override
    protected void onRefresh(ApplicationContext context) {
        initStrategies(context);
    }

    @Override
    protected long getLastModified(HttpServletRequest httpServletRequest) {
        WsdlDefinition definition = getWsdlDefinition(httpServletRequest);
        if (definition != null) {
            return wsdlDefinitionHandlerAdapter.getLastModified(httpServletRequest, definition);
        }
        XsdSchema schema = getXsdSchema(httpServletRequest);
        if (schema != null) {
            return xsdSchemaHandlerAdapter.getLastModified(httpServletRequest, schema);
        }
        return messageReceiverHandlerAdapter.getLastModified(httpServletRequest, messageReceiver);
    }

    /** Returns the {@link WebServiceMessageReceiver} used by this servlet. */
    protected WebServiceMessageReceiver getMessageReceiver() {
        return messageReceiver;
    }

    /**
     * Determines the {@link WsdlDefinition} for a given request, or {@code null} if none is found.
     *
     * <p>Default implementation checks whether the request method is {@code GET}, whether the request uri ends with
     * {@code ".wsdl"}, and if there is a {@code WsdlDefinition} with the same name as the filename in the
     * request uri.
     *
     * @param request the {@code HttpServletRequest}
     * @return a definition, or {@code null}
     */
    protected WsdlDefinition getWsdlDefinition(HttpServletRequest request) {
        if (HttpTransportConstants.METHOD_GET.equals(request.getMethod()) &&
                request.getRequestURI().endsWith(WSDL_SUFFIX_NAME)) {
            String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI());
            return wsdlDefinitions.get(fileName);
        }
        else {
            return null;
        }
    }

    /**
     * Determines the {@link XsdSchema} for a given request, or {@code null} if none is found.
     *
     * <p>Default implementation checks whether the request method is {@code GET}, whether the request uri ends with
     * {@code ".xsd"}, and if there is a {@code XsdSchema} with the same name as the filename in the request
     * uri.
     *
     * @param request the {@code HttpServletRequest}
     * @return a schema, or {@code null}
     */
    protected XsdSchema getXsdSchema(HttpServletRequest request) {
        if (HttpTransportConstants.METHOD_GET.equals(request.getMethod()) &&
                request.getRequestURI().endsWith(XSD_SUFFIX_NAME)) {
            String fileName = WebUtils.extractFilenameFromUrlPath(request.getRequestURI());
            return xsdSchemas.get(fileName);
        }
        else {
            return null;
        }
    }

    /**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) {
        initMessageReceiverHandlerAdapter(context);
        initWsdlDefinitionHandlerAdapter(context);
        initXsdSchemaHandlerAdapter(context);
        initMessageReceiver(context);
        initWsdlDefinitions(context);
        initXsdSchemas(context);
    }


    private void initMessageReceiverHandlerAdapter(ApplicationContext context) {
        try {
            try {
                messageReceiverHandlerAdapter = context.getBean(getMessageReceiverHandlerAdapterBeanName(),
                        WebServiceMessageReceiverHandlerAdapter.class);
            }
            catch (NoSuchBeanDefinitionException ignored) {
                messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter();
            }
            initWebServiceMessageFactory(context);
            messageReceiverHandlerAdapter.afterPropertiesSet();
        }
        catch (Exception ex) {
            throw new BeanInitializationException("Could not initialize WebServiceMessageReceiverHandlerAdapter", ex);
        }
    }

    private void initWebServiceMessageFactory(ApplicationContext context) {
        WebServiceMessageFactory messageFactory;
        try {
            messageFactory = context.getBean(getMessageFactoryBeanName(), WebServiceMessageFactory.class);
        }
        catch (NoSuchBeanDefinitionException ignored) {
            messageFactory = defaultStrategiesHelper
                    .getDefaultStrategy(WebServiceMessageFactory.class, context);
            if (logger.isDebugEnabled()) {
                logger.debug("No WebServiceMessageFactory found in servlet '" + getServletName() + "': using default");
            }
        }
        messageReceiverHandlerAdapter.setMessageFactory(messageFactory);
    }

    private void initWsdlDefinitionHandlerAdapter(ApplicationContext context) {
        try {
            try {
                wsdlDefinitionHandlerAdapter =
                        context.getBean(getWsdlDefinitionHandlerAdapterBeanName(), WsdlDefinitionHandlerAdapter.class);

            }
            catch (NoSuchBeanDefinitionException ignored) {
                wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
            }
            wsdlDefinitionHandlerAdapter.setTransformLocations(isTransformWsdlLocations());
            wsdlDefinitionHandlerAdapter.setTransformSchemaLocations(isTransformSchemaLocations());
            wsdlDefinitionHandlerAdapter.afterPropertiesSet();
        }
        catch (Exception ex) {
            throw new BeanInitializationException("Could not initialize WsdlDefinitionHandlerAdapter", ex);
        }
    }

    private void initXsdSchemaHandlerAdapter(ApplicationContext context) {
        try {
            try {
                xsdSchemaHandlerAdapter = context
                        .getBean(getXsdSchemaHandlerAdapterBeanName(), XsdSchemaHandlerAdapter.class);

            }
            catch (NoSuchBeanDefinitionException ignored) {
                xsdSchemaHandlerAdapter = new XsdSchemaHandlerAdapter();
            }
            xsdSchemaHandlerAdapter.setTransformSchemaLocations(isTransformSchemaLocations());
            xsdSchemaHandlerAdapter.afterPropertiesSet();
        }
        catch (Exception ex) {
            throw new BeanInitializationException("Could not initialize XsdSchemaHandlerAdapter", ex);
        }
    }

    private void initMessageReceiver(ApplicationContext context) {
        try {
            messageReceiver = context.getBean(getMessageReceiverBeanName(), WebServiceMessageReceiver.class);
        }
        catch (NoSuchBeanDefinitionException ex) {
            messageReceiver = defaultStrategiesHelper
                    .getDefaultStrategy(WebServiceMessageReceiver.class, context);
            if (messageReceiver instanceof BeanNameAware) {
                ((BeanNameAware) messageReceiver).setBeanName(getServletName());
            }
            if (logger.isDebugEnabled()) {
                logger.debug("No MessageDispatcher found in servlet '" + getServletName() + "': using default");
            }
        }
    }

    private void initWsdlDefinitions(ApplicationContext context) {
        wsdlDefinitions = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, WsdlDefinition.class, true, false);
        if (logger.isDebugEnabled()) {
            for (Map.Entry<String, WsdlDefinition> entry : wsdlDefinitions.entrySet()) {
                String beanName = entry.getKey();
                WsdlDefinition definition = entry.getValue();
                logger.debug("Published [" + definition + "] as " + beanName + WSDL_SUFFIX_NAME);
            }
        }
    }

    private void initXsdSchemas(ApplicationContext context) {
        xsdSchemas = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, XsdSchema.class, true, false);
        if (logger.isDebugEnabled()) {
            for (Map.Entry<String, XsdSchema> entry : xsdSchemas.entrySet()) {
                String beanName = entry.getKey();
                XsdSchema schema = entry.getValue();
                logger.debug("Published [" + schema + "] as " + beanName + XSD_SUFFIX_NAME);
            }
        }
    }
}
TOP

Related Classes of org.springframework.ws.transport.http.MessageDispatcherServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.