Switchyard Reference with Multiple JMS Bindings: How to Endpoint it

Latest response

Howdy!

Using ye ol venerable and most excellent switchyard-quickstart-rules-camel-cdr and setting up a Routing Drools rule to access a reference service of type JMS which has 2+ defined binding gateways:

<sca:reference name="MAPSOutboundService" multiplicity="0..1">
      <sca:interface.java interface="org.switchyard.quickstarts.rules.camel.cbr.ProcessMessageService"/>
      <jms:binding.jms name="MCI_CTL">
        <jms:topic>MCI_CTL</jms:topic>
        <jms:connectionFactory>#MAPSTS1ConnectionFactory</jms:connectionFactory>
      </jms:binding.jms>
      <jms:binding.jms name="SMM_STAT">
        <jms:topic>SMM_STAT</jms:topic>
        <jms:connectionFactory>#MAPSTS1ConnectionFactory</jms:connectionFactory>
      </jms:binding.jms>
    </sca:reference>

When I compile and deploy, I see:

17:12:05,668 INFO  [org.switchyard.common.camel.SwitchYardCamelContext] (MSC service thread 1-3) Route: direct:{urn:org.switchyard.quickstarts.rules.camel.cbr:1.0}RoutingService/MAPSOutboundBindingService started and consuming from: Endpoint[direct://%7Burn:org.switchyard.quickstarts.rules.camel.cbr:1.0%7DRoutingService/MAPSOutboundBindingService]

And when I invoke the rule, which is defined as:

rule "MAPS Wrapper Bindings Outbound"
    when
        $facadeMessage : IFacadeMessage(msgID matches "001XXX-.*")
    then
        $facadeMessage.setDestination("switchyard://MAPSOutboundService@SMM_STAT");
end

The result is:

Caused by: java.lang.NullPointerException: SWITCHYARD033900: No ServiceReference was found for uri [switchyard://MAPSOutboundBindingService@SMM_STAT]
        at org.switchyard.component.camel.SwitchYardProducer.lookupServiceReference(SwitchYardProducer.java:178) [switchyard-component-camel-switchyard-1.1.1-p5-redhat-1.jar:1.1.1-p5-redhat-1]

So I have to deduce then that how I am referencing the swithcyard endpoint from Drools is incorrect, so I try other forms:

$facadeMessage.setDestination("switchyard://MAPSOutboundService/SMM_STAT");
$facadeMessage.setDestination("switchyard://MAPSOutboundService.SMM_STAT");
$facadeMessage.setDestination("switchyard://MAPSOutboundService/@SMM_STAT");
$facadeMessage.setDestination("switchyard://MAPSOutboundService:SMM_STAT");

Actually what I found that that when using switchyard://MAPSOutboundService/SMM_STAT, I would get a JMS publish to MCI_CTL topic, which is listed FIRST in the list of Gateway bindings.

So I said to myself, "Self... what if these other bindings are not registered". So I use the admin web gui, and look at switchyard subsystem, open up reference MAPSOutboundService, then details and PRESTO! There are my defined Gateways! So they are indeed in the system and registered.

Even used a ModelControllerClient implementation to pull the switchyard subsystem directly, here is what I got:

{"name" => "{urn:org.switchyard.quickstarts.rules.camel.cbr:1.0}MAPSOutboundBindingService","application" => "{urn:org.switchyard.quickstarts.rules.camel.cbr:1.0}wst-facade","interface" => "org.switchyard.quickstarts.rules.camel.cbr.common.service.ProcessMessageService","promotedReference" => "RoutingService/MAPSOutboundBindingService","gateways" => [{"name" => "TS1_MAPS_SMM_STAT","type" => "jms","configuration" => "<jms:binding.jms xmlns:jms=\"urn:switchyard-component-camel-jms:config:1.1\" name=\"TS1_MAPS_SMM_STAT\">
    <jms:contextMapper includes=\".*\"/>
    <jms:messageComposer class=\"org.switchyard.quickstarts.rules.camel.cbr.block1.maps.data.composer.MAPSComposer\"/>
    <jms:topic>SMM_STAT</jms:topic>
    <jms:connectionFactory>#MAPSTS1ConnectionFactory</jms:connectionFactory>
</jms:binding.jms>","state" => "STARTED"},{"name" => "MCI_CTL","type" => "jms","configuration" => "<jms:binding.jms xmlns:jms=\"urn:switchyard-component-camel-jms:config:1.1\" name=\"TS1_MAPS_BK_CTL\">
    <jms:contextMapper includes=\".*\"/>
    <jms:messageComposer class=\"org.switchyard.quickstarts.rules.camel.cbr.block1.maps.data.composer.MAPSComposer\"/>
    <jms:topic>MCI_CTL</jms:topic>
    <jms:connectionFactory>#MAPSTS1ConnectionFactory</jms:connectionFactory>
</jms:binding.jms>","state" => "STARTED"},{"name" => "SMM_STAT","type" => "jms","configuration" => "<jms:binding.jms xmlns:jms=\"urn:switchyard-component-camel-jms:config:1.1\" name=\"TS1_MAPS_VLF_CTL\">
    <jms:contextMapper includes=\".*\"/>
    <jms:messageComposer class=\"org.switchyard.quickstarts.rules.camel.cbr.block1.maps.data.composer.MAPSComposer\"/>
    <jms:topic>VLF_CTL</jms:topic>
    <jms:connectionFactory>#MAPSTS1ConnectionFactory</jms:connectionFactory>
</jms:binding.jms>","state" => "STARTED"}}

With all that said... it seems like this is a proper use of assigning multiple gateway bindings to a reference service. But I have no clue how to access the Bindings?!?!? Any ideas?!

Responses

Good morning. I also posted to the Switchyard Developer forums and got a reply which answers my question. Following is the answer, although not the one I was hoping for. You can close or open as an enhancement request. Thanks. John

Keith Babo May 5, 2015 7:41 PM (in response to John Martin)
The SCA spec allows for multiple bindings to be defined on a composite reference, but SwitchYard will only use one binding per composite reference. Pretty sure that the tooling provides a validation warning if you try to do that. If you want to send the message to multiple JMS queues, then you can promote the reference multiple times with a unique name and binding for each promoted reference. Then it's just a matter of calling each reference from within your Drools logic.

The background here (in brief) is that the SCA spec allows multiple bindings on a reference, but there is not a definitive answer on how that is treated at runtime. Are messages load balanced over the bindings or is a copy of each message sent over every binding? Once enhancement we've discussed is the ability to inform the SY runtime dynamically which binding should be invoked by specifying the binding name as a context property.