How to map URNs (QName) to Bean operations with SwitchYard operation selector

Solution Verified - Updated -

Environment

  • Red Hat JBoss Fuse
    • 6.2
  • Red Hat JBoss Fuse Service Works (FSW)
    • 6.0

Issue

  • I have a SwitchYard service with an HTTP binding, which receives a SOAP message. I use the XPath Operation Selector to get the SOAP action. I want to map the different SOAP actions with the Bean operations.
  • My problem is that the Bean operation names don't match the SOAP actions, which are not valid Java operation names because they are URNs.
  • The Operation Selector retrieves the SOAP action of the message using an XPath expression ("/*/*/*[local-name()='Action']/text()"), but the resulting QName does not match any operation name of the Bean service.
  • The SOAP action uses an URN: "urn:com:example:app:myService:doSomething". So, no way to write a java method with such name. The invocation produces this exception:

    16:35:14,500 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] (http-/11.22.33.44:8080-3) Interceptor for {http://www.example.com/app-v1}MyService#{http://www.example.com/app-v1}doSomething has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: The given SOAPAction urn:com:example:app:myService:doSomething does not match an operation.
        at org.apache.cxf.binding.soap.interceptor.SoapActionInInterceptor$SoapActionInAttemptTwoInterceptor.handleMessage(SoapActionInInterceptor.java:188) [cxf-rt-bindings-soap-2.6.8.redhat-7.jar:2.6.8.redhat-7]
    
  • Is there any way to annotate the Java operation? Should I use a different Operation Selector type?

Resolution

Use a custom Java operation selector instead of the XPath selector. The XPath selector is not flexible enough to implement such a scenario. See SwitchYard Development Guide for more information on the available types of operations selector.

Here is a custom Java operation selector example that can be used with such a scenario:

public class ExampleOperationSelector extends HttpOperationSelector {

    public ExampleOperationSelector(OperationSelectorModel model) {
        super(model);
    }

    @Override
    public QName selectOperation(HttpBindingData content) throws Exception {
        String action = xpathMatch("/*/*/*[local-name()='Action']/text()", extractDomDocument(content));
        String[] op = action.split(":");
        return QName.valueOf(op[op.length - 1]);
    }

    private String xpathMatch(String expression, Document content) throws Exception {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        NodeList result = null;
        try {
            XPathExpression expr = xpath.compile(expression);
            result = NodeList.class.cast(expr.evaluate(content, XPathConstants.NODESET));
        } catch (Exception e) {
            throw CommonCommonMessages.MESSAGES.couldnTEvaluateXPathExpression(expression, e);
        }

        if (result.getLength() == 1) {
            return result.item(0).getTextContent();
        } else if (result.getLength() == 0) {
            throw CommonCommonMessages.MESSAGES.noNodeHasBeenMatchedWithTheXPathExpression(expression);
        } else {
            throw CommonCommonMessages.MESSAGES.multipleNodesHaveBeenMatchedWithTheXPathExpression(expression);
        }
    }

}

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.

Comments