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.
Spring WS Intercept Soap MessagesInterceptors must implement the EndpointInterceptor interface. This interface defines 4 methods. handleRequest this method is invoked before the endpoint and returns a boolean value. You can use this method to interrupt or continue the processing of the invocation chain.
How do I intercept SOAP message and where I have to do it? You need a SoapHandler to capture the soap request before the execution of the bussiness logic of the endpoint, and other SoapHandler to transform the outbound response.
public interface ClientInterceptor. Workflow interface that allows for customized client-side message interception. Applications can register any number of existing or custom interceptors on a WebServiceTemplate , to add common pre- and postprocessing behavior without needing to modify payload handling code.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With