How can a Spring Soap interceptor modify the contents of a message?

非 Y 不嫁゛ 提交于 2019-12-09 12:53:46

问题


I'm trying to write an interceptor for a web service that will modify the contents of the Soap message before is sent on to the endpoint. If a client sent a message where the value of some element is 1, I want to be able to alter that element to a 2 so that, when the message arrives at the endpoint, it looks as if the client submitted a 2 instead of a 1. I'm not sure if this is a difficult task which is elluding me, or an easy task which I am making harder than it needs to be.

I have stepped through some of the Spring interceptors; but the validation and logging interceptors don't every alter the message that is in transit. The Wss4jSecurityInterceptor does add some properties to the MessageContext; but I haven't been able to leverage anything that it is doing. I have a shell of an interceptor; but nothing that is doing anything of any value.

public boolean handleRequest(MessageContext messageContext, Object endpoint)
        throws Exception {

    SaajSoapMessage saajSoapMessage = (SaajSoapMessage) messageContext
            .getRequest();
    SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
    SOAPBody soapBody = soapMessage.getSOAPBody();

    return true;
}

I was hoping there was a chance that soembody else had already solved this particular problem. Any insight would be appreciated. Thanks.


回答1:


Modifying the payload is a little bit tricky. The only way I've found to make this work is to use the getPayloadSource() and getPayloadResult() methods on SoapBody, which expose javax.xml.transform-friendly objects for manipulating the data.

It's annoyingly heavyweight, but you can do something like this:

Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
DOMResult domResult = new DOMResult();
identityTransform.transform(soapBody.getPayloadSource(), domResult);

Node bodyContent = domResult.getNode(); // modify this

identityTransform.transform(new DOMSource(bodyContent), soapBody.getPayloadResult());

I'd love to see a better way of doing this.




回答2:


I realized that it was easer to alter the request at a later point. I did not need to modify the original SOAP message, so long as I was able to modify the data before it reached my endpoint.

The endpoints I am working with all extend AbstractDom4jPayloadEndpoint - so I wrapped these endpoints in a proxy that allowed me to modify the request element before proceeding to my endpoint. i.e.:

public class MyProxyEndpoint extends AbstractDom4jPayloadEndpoint

    @Override
    protected Element invokeInternal( 
        Element requestElement,
        Document responseDocument ) throws Exception
    {
        if( requestElement != null )
        {
            // alter request element
        }

        return ( Element ) this.invokeMethod.invoke( 
            this.target,
            requestElement,
            responseDocument );
    }



回答3:


I modified the code in this answer to insert an <authentication/> element into all SOAP body requests:

@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
    logger.trace("Enter handleMessage");
    try {
        SaajSoapMessage request = (SaajSoapMessage) messageContext.getRequest();
        addAuthn(request);
    } catch (Exception e) {
        logger.error(e.getMessage(),e);
    }

    return true;
}

protected void addAuthn(SaajSoapMessage request) throws TransformerException {
    Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
    DOMResult domResult = new DOMResult();
    identityTransform.transform(request.getPayloadSource(), domResult);

    Node bodyContent = domResult.getNode();
    Document doc = (Document) bodyContent;
    doc.getFirstChild().appendChild(authNode(doc));

    identityTransform.transform(new DOMSource(bodyContent), request.getPayloadResult());
}

protected Node authNode(Document doc) {
    Element authentication = doc.createElementNS(ns, "authentication");
    Element username = doc.createElementNS(ns, "username");
    username.setTextContent(authn.getUsername());
    Element password = doc.createElementNS(ns, "password");
    password.setTextContent(authn.getPassword());
    authentication.appendChild(username);
    authentication.appendChild(password);
    return authentication;
}

This solution was used because the WebServiceMessageCallback would require me to change the Document, and the SaajSoapMessageFactory is activated before the soap body has been inserted by the configured Jaxb2Marshaller.



来源:https://stackoverflow.com/questions/3207163/how-can-a-spring-soap-interceptor-modify-the-contents-of-a-message

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!