Package org.springframework.ws.server.endpoint.adapter

Source Code of org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter

/*
* 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.server.endpoint.adapter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.adapter.method.MessageContextMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.MethodReturnValueHandler;
import org.springframework.ws.server.endpoint.adapter.method.SourcePayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.StaxPayloadMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver;
import org.springframework.ws.server.endpoint.adapter.method.dom.Dom4jPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.DomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.JDomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.dom.XomPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.JaxbElementPayloadMethodProcessor;
import org.springframework.ws.server.endpoint.adapter.method.jaxb.XmlRootElementPayloadMethodProcessor;

/**
* Default extension of {@link AbstractMethodEndpointAdapter} with support for pluggable {@linkplain
* MethodArgumentResolver argument resolvers} and {@linkplain MethodReturnValueHandler return value handlers}.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class DefaultMethodEndpointAdapter extends AbstractMethodEndpointAdapter
        implements BeanClassLoaderAware, InitializingBean {

    private static final String DOM4J_CLASS_NAME = "org.dom4j.Element";

    private static final String JAXB2_CLASS_NAME = "javax.xml.bind.Binder";

    private static final String JDOM_CLASS_NAME = "org.jdom2.Element";

    private static final String STAX_CLASS_NAME = "javax.xml.stream.XMLInputFactory";

    private static final String XOM_CLASS_NAME = "nu.xom.Element";

    private static final String SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME =
            "org.springframework.ws.soap.server.endpoint.adapter.method.SoapMethodArgumentResolver";

    private static final String SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME =
            "org.springframework.ws.soap.server.endpoint.adapter.method.SoapHeaderElementMethodArgumentResolver";

    private List<MethodArgumentResolver> methodArgumentResolvers;

  private List<MethodArgumentResolver> customMethodArgumentResolvers;

    private List<MethodReturnValueHandler> methodReturnValueHandlers;

    private List<MethodReturnValueHandler> customMethodReturnValueHandlers;

    private ClassLoader classLoader;

  /**
   * Returns the list of {@code MethodArgumentResolver}s to use.
   */
  public List<MethodArgumentResolver> getMethodArgumentResolvers() {
        return methodArgumentResolvers;
    }

  /**
   * Sets the list of {@code MethodArgumentResolver}s to use.
   */
  public void setMethodArgumentResolvers(List<MethodArgumentResolver> methodArgumentResolvers) {
        this.methodArgumentResolvers = methodArgumentResolvers;
    }

  /**
   * Returns the custom argument resolvers.
   */
  public List<MethodArgumentResolver> getCustomMethodArgumentResolvers() {
    return customMethodArgumentResolvers;
  }

  /**
   * Sets the custom handlers for method arguments. Custom handlers are
   * ordered after built-in ones. To override the built-in support for
   * return value handling use {@link #setMethodArgumentResolvers(List)}.
   */
  public void setCustomMethodArgumentResolvers(
      List<MethodArgumentResolver> customMethodArgumentResolvers) {
    this.customMethodArgumentResolvers = customMethodArgumentResolvers;
  }

  /**
   * Returns the list of {@code MethodReturnValueHandler}s to use.
   */
  public List<MethodReturnValueHandler> getMethodReturnValueHandlers() {
        return methodReturnValueHandlers;
    }

  /**
   * Sets the list of {@code MethodReturnValueHandler}s to use.
   */
  public void setMethodReturnValueHandlers(List<MethodReturnValueHandler> methodReturnValueHandlers) {
        this.methodReturnValueHandlers = methodReturnValueHandlers;
    }

  /**
   * Returns the custom return value handlers.
   */
  public List<MethodReturnValueHandler> getCustomMethodReturnValueHandlers() {
    return customMethodReturnValueHandlers;
  }

  /**
   * Sets the handlers for custom return value types. Custom handlers are
   * ordered after built-in ones. To override the built-in support for
   * return value handling use {@link #setMethodReturnValueHandlers(List)}.
   */
  public void setCustomMethodReturnValueHandlers(
      List<MethodReturnValueHandler> customMethodReturnValueHandlers) {
    this.customMethodReturnValueHandlers = customMethodReturnValueHandlers;
  }

  private ClassLoader getClassLoader() {
        return this.classLoader != null ? this.classLoader : DefaultMethodEndpointAdapter.class.getClassLoader();
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        initDefaultStrategies();
    }

    /** Initialize the default implementations for the adapter's strategies. */
    protected void initDefaultStrategies() {
        initMethodArgumentResolvers();
        initMethodReturnValueHandlers();
    }

    private void initMethodArgumentResolvers() {
        if (CollectionUtils.isEmpty(methodArgumentResolvers)) {
            List<MethodArgumentResolver> methodArgumentResolvers = new ArrayList<MethodArgumentResolver>();
            methodArgumentResolvers.add(new DomPayloadMethodProcessor());
            methodArgumentResolvers.add(new MessageContextMethodArgumentResolver());
            methodArgumentResolvers.add(new SourcePayloadMethodProcessor());
            methodArgumentResolvers.add(new XPathParamMethodArgumentResolver());
            addMethodArgumentResolver(SOAP_METHOD_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
            addMethodArgumentResolver(SOAP_HEADER_ELEMENT_ARGUMENT_RESOLVER_CLASS_NAME, methodArgumentResolvers);
            if (isPresent(DOM4J_CLASS_NAME)) {
                methodArgumentResolvers.add(new Dom4jPayloadMethodProcessor());
            }
            if (isPresent(JAXB2_CLASS_NAME)) {
                methodArgumentResolvers.add(new XmlRootElementPayloadMethodProcessor());
                methodArgumentResolvers.add(new JaxbElementPayloadMethodProcessor());
            }
            if (isPresent(JDOM_CLASS_NAME)) {
                methodArgumentResolvers.add(new JDomPayloadMethodProcessor());
            }
            if (isPresent(STAX_CLASS_NAME)) {
                methodArgumentResolvers.add(new StaxPayloadMethodArgumentResolver());
            }
            if (isPresent(XOM_CLASS_NAME)) {
                methodArgumentResolvers.add(new XomPayloadMethodProcessor());
            }
            if (logger.isDebugEnabled()) {
                logger.debug("No MethodArgumentResolvers set, using defaults: " + methodArgumentResolvers);
            }
          if (getCustomMethodArgumentResolvers() != null) {
            methodArgumentResolvers.addAll(getCustomMethodArgumentResolvers());
          }
            setMethodArgumentResolvers(methodArgumentResolvers);
        }
    }

    /**
     * Certain (SOAP-specific) {@code MethodArgumentResolver}s have to be instantiated by class name, in order to not
     * introduce a cyclic dependency.
     */
    @SuppressWarnings("unchecked")
    private void addMethodArgumentResolver(String className, List<MethodArgumentResolver> methodArgumentResolvers) {
        try {
            Class<MethodArgumentResolver> methodArgumentResolverClass =
                    (Class<MethodArgumentResolver>) ClassUtils.forName(className, getClassLoader());
            methodArgumentResolvers.add(BeanUtils.instantiate(methodArgumentResolverClass));
        }
        catch (ClassNotFoundException e) {
            logger.warn("Could not find \"" + className + "\" on the classpath");
        }
    }

    private void initMethodReturnValueHandlers() {
        if (CollectionUtils.isEmpty(methodReturnValueHandlers)) {
            List<MethodReturnValueHandler> methodReturnValueHandlers = new ArrayList<MethodReturnValueHandler>();
            methodReturnValueHandlers.add(new DomPayloadMethodProcessor());
            methodReturnValueHandlers.add(new SourcePayloadMethodProcessor());
            if (isPresent(DOM4J_CLASS_NAME)) {
                methodReturnValueHandlers.add(new Dom4jPayloadMethodProcessor());
            }
            if (isPresent(JAXB2_CLASS_NAME)) {
                methodReturnValueHandlers.add(new XmlRootElementPayloadMethodProcessor());
                methodReturnValueHandlers.add(new JaxbElementPayloadMethodProcessor());
            }
            if (isPresent(JDOM_CLASS_NAME)) {
                methodReturnValueHandlers.add(new JDomPayloadMethodProcessor());
            }
            if (isPresent(XOM_CLASS_NAME)) {
                methodReturnValueHandlers.add(new XomPayloadMethodProcessor());
            }
            if (logger.isDebugEnabled()) {
                logger.debug("No MethodReturnValueHandlers set, using defaults: " + methodReturnValueHandlers);
            }
          if (getCustomMethodReturnValueHandlers() != null) {
            methodReturnValueHandlers.addAll(getCustomMethodReturnValueHandlers());
          }
            setMethodReturnValueHandlers(methodReturnValueHandlers);
        }
    }

    private boolean isPresent(String className) {
        return ClassUtils.isPresent(className, getClassLoader());
    }

    @Override
    protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
        return supportsParameters(methodEndpoint.getMethodParameters()) &&
                supportsReturnType(methodEndpoint.getReturnType());
    }

    private boolean supportsParameters(MethodParameter[] methodParameters) {
        for (MethodParameter methodParameter : methodParameters) {
            boolean supported = false;
            for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
                            methodParameter.getGenericParameterType() + "]");
                }
                if (methodArgumentResolver.supportsParameter(methodParameter)) {
                    supported = true;
                    break;
                }
            }
            if (!supported) {
                return false;
            }
        }
        return true;
    }

    private boolean supportsReturnType(MethodParameter methodReturnType) {
        if (Void.TYPE.equals(methodReturnType.getParameterType())) {
            return true;
        }
        for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
            if (methodReturnValueHandler.supportsReturnType(methodReturnType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    protected final void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
        Object[] args = getMethodArguments(messageContext, methodEndpoint);

        if (logger.isTraceEnabled()) {
          logger.trace("Invoking [" + methodEndpoint + "] with arguments " + Arrays.asList(args));
        }

        Object returnValue = methodEndpoint.invoke(args);

        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + methodEndpoint + "] returned [" + returnValue + "]");
        }

        Class<?> returnType = methodEndpoint.getMethod().getReturnType();
        if (!Void.TYPE.equals(returnType)) {
            handleMethodReturnValue(messageContext, returnValue, methodEndpoint);
        }
    }

    /**
     * Returns the argument array for the given method endpoint.
     *
     * <p>This implementation iterates over the set {@linkplain #setMethodArgumentResolvers(List) argument resolvers} to
     * resolve each argument.
     *
     * @param messageContext the current message context
     * @param methodEndpoint the method endpoint to get arguments for
     * @return the arguments
     * @throws Exception in case of errors
     */
    protected Object[] getMethodArguments(MessageContext messageContext, MethodEndpoint methodEndpoint)
            throws Exception {
        MethodParameter[] parameters = methodEndpoint.getMethodParameters();
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            for (MethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
                if (methodArgumentResolver.supportsParameter(parameters[i])) {
                    args[i] = methodArgumentResolver.resolveArgument(messageContext, parameters[i]);
                    break;
                }
            }
        }
        return args;
    }

    /**
     * Handle the return value for the given method endpoint.
     *
     * <p>This implementation iterates over the set {@linkplain #setMethodReturnValueHandlers(java.util.List)}  return value
     * handlers} to resolve the return value.
     *
     * @param messageContext the current message context
     * @param returnValue    the return value
     * @param methodEndpoint the method endpoint to get arguments for
     * @throws Exception in case of errors
     */
    protected void handleMethodReturnValue(MessageContext messageContext,
                                           Object returnValue,
                                           MethodEndpoint methodEndpoint) throws Exception {
        MethodParameter returnType = methodEndpoint.getReturnType();
        for (MethodReturnValueHandler methodReturnValueHandler : methodReturnValueHandlers) {
            if (methodReturnValueHandler.supportsReturnType(returnType)) {
                methodReturnValueHandler.handleReturnValue(messageContext, returnType, returnValue);
                return;
            }
        }
        throw new IllegalStateException(
                "Return value [" + returnValue + "] not resolved by any MethodReturnValueHandler");
    }
}
TOP

Related Classes of org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter

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.