Package org.springframework.ws.soap.addressing.version

Source Code of org.springframework.ws.soap.addressing.version.AbstractAddressingVersion

/*
* 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.soap.addressing.version;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;

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

import org.springframework.util.StringUtils;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.addressing.AddressingException;
import org.springframework.ws.soap.addressing.core.EndpointReference;
import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
import org.springframework.ws.soap.soap11.Soap11Body;
import org.springframework.ws.soap.soap12.Soap12Body;
import org.springframework.ws.soap.soap12.Soap12Fault;
import org.springframework.xml.namespace.QNameUtils;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.xml.xpath.XPathExpression;
import org.springframework.xml.xpath.XPathExpressionFactory;

/**
* Abstract base class for {@link AddressingVersion} implementations. Uses {@link XPathExpression}s to retrieve
* addressing information.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
public abstract class AbstractAddressingVersion extends TransformerObjectSupport implements AddressingVersion {

    private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();

    private final XPathExpression toExpression;

    private final XPathExpression actionExpression;

    private final XPathExpression messageIdExpression;

    private final XPathExpression fromExpression;

    private final XPathExpression replyToExpression;

    private final XPathExpression faultToExpression;

    private final XPathExpression addressExpression;

    private final XPathExpression referencePropertiesExpression;

    private final XPathExpression referenceParametersExpression;

    protected AbstractAddressingVersion() {
        Map<String, String> namespaces = new HashMap<String, String>();
        namespaces.put(getNamespacePrefix(), getNamespaceUri());
        toExpression = createNormalizedExpression(getToName(), namespaces);
        actionExpression = createNormalizedExpression(getActionName(), namespaces);
        messageIdExpression = createNormalizedExpression(getMessageIdName(), namespaces);
        fromExpression = createExpression(getFromName(), namespaces);
        replyToExpression = createExpression(getReplyToName(), namespaces);
        faultToExpression = createExpression(getFaultToName(), namespaces);
        addressExpression = createNormalizedExpression(getAddressName(), namespaces);
        if (getReferencePropertiesName() != null) {
            referencePropertiesExpression = createChildrenExpression(getReferencePropertiesName(), namespaces);
        }
        else {
            referencePropertiesExpression = null;
        }
        if (getReferenceParametersName() != null) {
            referenceParametersExpression = createChildrenExpression(getReferenceParametersName(), namespaces);
        }
        else {
            referenceParametersExpression = null;
        }
    }

    private XPathExpression createExpression(QName name, Map<String, String> namespaces) {
        String expression = name.getPrefix() + ":" + name.getLocalPart();
        return XPathExpressionFactory.createXPathExpression(expression, namespaces);
    }

    private XPathExpression createNormalizedExpression(QName name, Map<String, String> namespaces) {
        String expression = "normalize-space(" + name.getPrefix() + ":" + name.getLocalPart() + ")";
        return XPathExpressionFactory.createXPathExpression(expression, namespaces);
    }

    private XPathExpression createChildrenExpression(QName name, Map<String, String> namespaces) {
        String expression = name.getPrefix() + ":" + name.getLocalPart() + "/*";
        return XPathExpressionFactory.createXPathExpression(expression, namespaces);
    }

    @Override
    public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) {
        Element headerElement = getSoapHeaderElement(message);
        URI to = getUri(headerElement, toExpression);
        if (to == null) {
            to = getDefaultTo();
        }
        EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
        EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
        if (replyTo == null) {
            replyTo = getDefaultReplyTo(from);
        }
        EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
        if (faultTo == null) {
            faultTo = replyTo;
        }
        URI action = getUri(headerElement, actionExpression);
        URI messageId = getUri(headerElement, messageIdExpression);
        return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
    }

    private URI getUri(Node node, XPathExpression expression) {
        String messageId = expression.evaluateAsString(node);
        if (!StringUtils.hasLength(messageId)) {
            return null;
        }
        try {
            return new URI(messageId);
        }
        catch (URISyntaxException e) {
            return null;
        }
    }

    private Element getSoapHeaderElement(SoapMessage message) {
        Source source = message.getSoapHeader().getSource();
        if (source instanceof DOMSource) {
            DOMSource domSource = (DOMSource) source;
            if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
                return (Element) domSource.getNode();
            }
        }
        try {
            DOMResult domResult = new DOMResult();
            transform(source, domResult);
            Document document = (Document) domResult.getNode();
            return document.getDocumentElement();
        }
        catch (TransformerException ex) {
            throw new AddressingException("Could not transform SoapHeader to Document", ex);
        }
    }

    /** Given a ReplyTo, FaultTo, or From node, returns an endpoint reference. */
    private EndpointReference getEndpointReference(Node node) {
        if (node == null) {
            return null;
        }
        URI address = getUri(node, addressExpression);
        if (address == null) {
            return null;
        }
        List<Node> referenceProperties =
                referencePropertiesExpression != null ? referencePropertiesExpression.evaluateAsNodeList(node) :
                        Collections.<Node>emptyList();
        List<Node> referenceParameters =
                referenceParametersExpression != null ? referenceParametersExpression.evaluateAsNodeList(node) :
                        Collections.<Node>emptyList();
        return new EndpointReference(address, referenceProperties, referenceParameters);
    }

    @Override
    public void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
        SoapHeader header = message.getSoapHeader();
        header.addNamespaceDeclaration(getNamespacePrefix(), getNamespaceUri());
        // To
        if (map.getTo() != null) {
            SoapHeaderElement to = header.addHeaderElement(getToName());
            to.setText(map.getTo().toString());
            to.setMustUnderstand(true);
        }
        // From
        if (map.getFrom() != null) {
            SoapHeaderElement from = header.addHeaderElement(getFromName());
            addEndpointReference(from, map.getFrom());
        }
        //ReplyTo
        if (map.getReplyTo() != null) {
            SoapHeaderElement replyTo = header.addHeaderElement(getReplyToName());
            addEndpointReference(replyTo, map.getReplyTo());
        }
        // FaultTo
        if (map.getFaultTo() != null) {
            SoapHeaderElement faultTo = header.addHeaderElement(getFaultToName());
            addEndpointReference(faultTo, map.getFaultTo());
        }
        // Action
        SoapHeaderElement action = header.addHeaderElement(getActionName());
        action.setText(map.getAction().toString());
        // MessageID
        if (map.getMessageId() != null) {
            SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName());
            messageId.setText(map.getMessageId().toString());
        }
        // RelatesTo
        if (map.getRelatesTo() != null) {
            SoapHeaderElement relatesTo = header.addHeaderElement(getRelatesToName());
            relatesTo.setText(map.getRelatesTo().toString());
        }
        addReferenceNodes(header.getResult(), map.getReferenceParameters());
        addReferenceNodes(header.getResult(), map.getReferenceProperties());
    }

    @Override
    public final boolean understands(SoapHeaderElement headerElement) {
        return getNamespaceUri().equals(headerElement.getName().getNamespaceURI());
    }

    /** Adds ReplyTo, FaultTo, or From EPR to the given header Element. */
    protected void addEndpointReference(SoapHeaderElement headerElement, EndpointReference epr) {
        if (epr == null || epr.getAddress() == null) {
            return;
        }
        try {
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.newDocument();
            Element address = document.createElementNS(getNamespaceUri(), QNameUtils.toQualifiedName(getAddressName()));
            address.setTextContent(epr.getAddress().toString());
            transform(new DOMSource(address), headerElement.getResult());
            if (getReferenceParametersName() != null && !epr.getReferenceParameters().isEmpty()) {
                Element referenceParams = document.createElementNS(getNamespaceUri(),
                        QNameUtils.toQualifiedName(getReferenceParametersName()));
                addReferenceNodes(new DOMResult(referenceParams), epr.getReferenceParameters());
                transform(new DOMSource(referenceParams), headerElement.getResult());
            }
            if (getReferencePropertiesName() != null && !epr.getReferenceProperties().isEmpty()) {
                Element referenceProps = document.createElementNS(getNamespaceUri(),
                        QNameUtils.toQualifiedName(getReferencePropertiesName()));
                addReferenceNodes(new DOMResult(referenceProps), epr.getReferenceProperties());
                transform(new DOMSource(referenceProps), headerElement.getResult());
            }
        }
        catch (ParserConfigurationException ex) {
            throw new AddressingException("Could not add Endpoint Reference [" + epr + "] to header element", ex);
        }
        catch (TransformerException ex) {
            throw new AddressingException("Could not add reference properties/parameters to message", ex);
        }
    }

    protected void addReferenceNodes(Result result, List<Node> nodes) {
        try {
            for (Node node : nodes) {
                DOMSource source = new DOMSource(node);
                transform(source, result);
            }
        }
        catch (TransformerException ex) {
            throw new AddressingException("Could not add reference properties/parameters to message", ex);
        }
    }

    @Override
    public final SoapFault addInvalidAddressingHeaderFault(SoapMessage message) {
        return addAddressingFault(message, getInvalidAddressingHeaderFaultSubcode(),
                getInvalidAddressingHeaderFaultReason());
    }

    @Override
    public final SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) {
        return addAddressingFault(message, getMessageAddressingHeaderRequiredFaultSubcode(),
                getMessageAddressingHeaderRequiredFaultReason());
    }

    private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) {
        if (message.getSoapBody() instanceof Soap11Body) {
            Soap11Body soapBody = (Soap11Body) message.getSoapBody();
            return soapBody.addFault(subcode, reason, Locale.ENGLISH);
        }
        else if (message.getSoapBody() instanceof Soap12Body) {
            Soap12Body soapBody = (Soap12Body) message.getSoapBody();
            Soap12Fault soapFault =
                soapBody.addClientOrSenderFault(reason, Locale.ENGLISH);
            soapFault.addFaultSubcode(subcode);
            return soapFault;
        }
        return null;
    }

    /*
    * Address URIs
    */

    @Override
    public final boolean hasAnonymousAddress(EndpointReference epr) {
        URI anonymous = getAnonymous();
        return anonymous != null && anonymous.equals(epr.getAddress());
    }

    @Override
    public final boolean hasNoneAddress(EndpointReference epr) {
        URI none = getNone();
        return none != null && none.equals(epr.getAddress());
    }

    /** Returns the prefix associated with the WS-Addressing namespace handled by this specification. */
    protected String getNamespacePrefix() {
        return "wsa";
    }

    /** Returns the WS-Addressing namespace handled by this specification. */
    protected abstract String getNamespaceUri();

    /*
     * Message addressing properties
     */

    /** Returns the qualified name of the {@code To} addressing header. */
    protected QName getToName() {
      return new QName(getNamespaceUri(), "To", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code From} addressing header. */
    protected QName getFromName() {
      return new QName(getNamespaceUri(), "From", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code ReplyTo} addressing header. */
    protected QName getReplyToName() {
      return new QName(getNamespaceUri(), "ReplyTo", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code FaultTo} addressing header. */
    protected QName getFaultToName() {
      return new QName(getNamespaceUri(), "FaultTo", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code Action} addressing header. */
    protected QName getActionName() {
      return new QName(getNamespaceUri(), "Action", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code MessageID} addressing header. */
    protected QName getMessageIdName() {
      return new QName(getNamespaceUri(), "MessageID", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code RelatesTo} addressing header. */
    protected QName getRelatesToName() {
      return new QName(getNamespaceUri(), "RelatesTo", getNamespacePrefix());
    }

    /** Returns the qualified name of the {@code RelatesTo} addressing header. */
    protected QName getRelationshipTypeName() {
        return new QName("RelationshipType");
    }

    /**
     * Returns the qualified name of the {@code ReferenceProperties} in the endpoint reference. Returns
     * {@code null} when reference properties are not supported by this version of the spec.
     */
    protected QName getReferencePropertiesName() {
      return new QName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix());
    }

    /**
     * Returns the qualified name of the {@code ReferenceParameters} in the endpoint reference. Returns
     * {@code null} when reference parameters are not supported by this version of the spec.
     */
    protected QName getReferenceParametersName() {
      return new QName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix());
    }

    /*
     * Endpoint Reference
     */

    /** The qualified name of the {@code Address} in {@code EndpointReference}. */
    protected QName getAddressName() {
      return new QName(getNamespaceUri(), "Address", getNamespacePrefix());
    }

    /** Returns the default To URI. */
    protected abstract URI getDefaultTo();

    /** Returns the default ReplyTo EPR. Can be based on the From EPR, or the anonymous URI. */
    protected abstract EndpointReference getDefaultReplyTo(EndpointReference from);

    /*
     * Address URIs
     */

    /** Returns the anonymous URI. */
    protected abstract URI getAnonymous();

    /** Returns the none URI, or {@code null} if the spec does not define it. */
    protected abstract URI getNone();

    /*
     * Faults
     */

    /** Returns the qualified name of the fault subcode that indicates that a header is missing. */
    protected abstract QName getMessageAddressingHeaderRequiredFaultSubcode();

    /** Returns the reason of the fault that indicates that a header is missing. */
    protected abstract String getMessageAddressingHeaderRequiredFaultReason();

    /** Returns the qualified name of the fault subcode that indicates that a header is invalid. */
    protected abstract QName getInvalidAddressingHeaderFaultSubcode();

    /** Returns the reason of the fault that indicates that a header is invalid. */
    protected abstract String getInvalidAddressingHeaderFaultReason();
}
TOP

Related Classes of org.springframework.ws.soap.addressing.version.AbstractAddressingVersion

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.