Apache Camel CXF difficulty calling an RPC/Encoded WSDL when updating list of elements

177 Views Asked by At

While not officially supported, with a few minor modifications to the WSDL I was able to successfully generate CXF Objects for the WSDL and get Camel CXF to talk to an RPC/Encoded WSDL endpoint. The code is incredibly simple and most request/responses work without issue except for attempting to send updates of a list of elements. Here is what the service expects:

<elements arrayType="UpdateElement">

VS here is what is being sent:

<elements>

I need to add the arrayType into the outgoing message. I looked into a number of ways of doing this:

1) An interceptor right before the SOAP message is sent by CXF then use XPath to add the element but I was not clear how to accomplish this using Apache Camel + Camel CXF. How to retrieve the CXF client from the Camel Context?

MyService client = ???

2) Fix it via WSDL? Is it possible to add this element to the WSDL so it is generated as a part of the CXF Objects? It is defined like this presently:

<message name="wsdlElementRequest"> <part name="elements" type="tns:UpdateElements" /></message>

'message' and 'part' come from http://schemas.xmlsoap.org/wsdl/.

Any ideas or suggestions would be appreciated. Thanks!

1

There are 1 best solutions below

0
On BEST ANSWER

In case anyone ever stumbles on this with a similar issue, I figured it out myself. I was able to retrieve the CxfEndpoint via CamelContext:

camelContext.getEndpoint(endpointUrl, CxfEndpoint.class);

Then I was able to add the interceptor I created:

public class MyCxfInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
...

Using the CxfEndpoint methods:

cxfEndpoint.getOutInterceptors().add(new MyCxfInterceptor());

In my interceptor I also incorporated another interceptor, SAAJOutInterceptor, that converts the SOAP into an easy to work with object:

private List<PhaseInterceptor<? extends Message>> extras = new ArrayList<>(1);

public MyCxfInterceptor() {
    super(Phase.USER_PROTOCOL);
    extras.add(new SAAJOutInterceptor());
}

public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() {
    return extras;
}

The easy to work with SOAP message:

@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
    SOAPMessage msg = soapMessage.getContent(SOAPMessage.class);

    try {
        SOAPBody soapBody = msg.getSOAPBody();

Then it was a simple matter of using XPATH to make the correction to the outgoing SOAP message.

private XPath xpath = XPathFactory.newInstance().newXPath();
...
NodeList nodeList = soapBody.getElementsByTagName("tagName");
for (int x = 0; x < nodeList.getLength(); x++) {
    Node node = nodeList.item(x);
    ((Element) node).setAttribute("missingAttributeName", "missingAttributeValue");
}

I hope this helps anyone working with challenging SOAP services!

Credit to the blog which played a big part in enabling me to implement this solution: https://xceptionale.wordpress.com/2016/06/26/message-interceptor-to-modify-outbound-soap-request/