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

Source Code of org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver

/*
* 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.method;

import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.ConversionServiceFactory;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.springframework.ws.server.endpoint.support.NamespaceUtils;
import org.springframework.xml.transform.TransformerHelper;

/**
* Implementation of {@link MethodArgumentResolver} that supports the {@link XPathParam @XPathParam} annotation.
*
* <p>This resolver supports parameters annotated with {@link XPathParam @XPathParam} that specifies the XPath expression
* that should be bound to that parameter. The parameter can either a "natively supported" XPath type ({@link Boolean
* boolean}, {@link Double double}, {@link String}, {@link Node}, or {@link NodeList}), or a type that is {@linkplain
* ConversionService#canConvert(Class, Class) supported} by the {@link ConversionService}.
*
* @author Arjen Poutsma
* @since 2.0
*/
public class XPathParamMethodArgumentResolver implements MethodArgumentResolver {

    private final XPathFactory xpathFactory = createXPathFactory();

    private TransformerHelper transformerHelper = new TransformerHelper();

    private ConversionService conversionService = new DefaultConversionService();

    /**
     * Sets the conversion service to use.
     *
     * <p>Defaults to the {@linkplain ConversionServiceFactory#createDefaultConversionService() default conversion
     * service}.
     */
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    public void setTransformerHelper(TransformerHelper transformerHelper) {
        this.transformerHelper = transformerHelper;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        if (parameter.getParameterAnnotation(XPathParam.class) == null) {
            return false;
        }
        Class<?> parameterType = parameter.getParameterType();
        if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType) ||
                Double.class.equals(parameterType) || Double.TYPE.equals(parameterType) ||
                Node.class.isAssignableFrom(parameterType) || NodeList.class.isAssignableFrom(parameterType) ||
                String.class.isAssignableFrom(parameterType)) {
            return true;
        }
        else {
            return conversionService.canConvert(String.class, parameterType);
        }
    }

    @Override
    public Object resolveArgument(MessageContext messageContext, MethodParameter parameter)
            throws TransformerException, XPathExpressionException {
        Class<?> parameterType = parameter.getParameterType();
        QName evaluationReturnType = getReturnType(parameterType);
        boolean useConversionService = false;
        if (evaluationReturnType == null) {
            evaluationReturnType = XPathConstants.STRING;
            useConversionService = true;
        }

        XPath xpath = createXPath();
        xpath.setNamespaceContext(NamespaceUtils.getNamespaceContext(parameter.getMethod()));

        Element rootElement = getRootElement(messageContext.getRequest().getPayloadSource());
        String expression = parameter.getParameterAnnotation(XPathParam.class).value();
        Object result = xpath.evaluate(expression, rootElement, evaluationReturnType);
        return useConversionService ? conversionService.convert(result, parameterType) : result;
    }

    private QName getReturnType(Class<?> parameterType) {
        if (Boolean.class.equals(parameterType) || Boolean.TYPE.equals(parameterType)) {
            return XPathConstants.BOOLEAN;
        }
        else if (Double.class.equals(parameterType) || Double.TYPE.equals(parameterType)) {
            return XPathConstants.NUMBER;
        }
        else if (Node.class.equals(parameterType)) {
            return XPathConstants.NODE;
        }
        else if (NodeList.class.equals(parameterType)) {
            return XPathConstants.NODESET;
        }
        else if (String.class.equals(parameterType)) {
            return XPathConstants.STRING;
        }
        else {
            return null;
        }
    }

    private XPath createXPath() {
        synchronized (xpathFactory) {
            return xpathFactory.newXPath();
        }
    }

    private Element getRootElement(Source source) throws TransformerException {
        DOMResult domResult = new DOMResult();
        transformerHelper.transform(source, domResult);
        Document document = (Document) domResult.getNode();
        return document.getDocumentElement();
    }

    /**
     * Create a {@code XPathFactory} that this resolver will use to create {@link XPath} objects.
     *
     * <p>Can be overridden in subclasses, adding further initialization of the factory. The resulting factory is cached,
     * so this method will only be called once.
     *
     * @return the created factory
     */
    protected XPathFactory createXPathFactory() {
        return XPathFactory.newInstance();
    }


}
TOP

Related Classes of org.springframework.ws.server.endpoint.adapter.method.XPathParamMethodArgumentResolver

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.