13 Replies Latest reply on Dec 11, 2012 9:24 AM by igarashitm

    Routing to Switchyard service with multiple methods

    kostas_papag

      Hello ,

       

      I have the following setup :

       

      One service, bound using Camel JMS binding, receives messages and routes them using Camel Router to Switchyard Bean services.

      I want to be able to route the JMS messages to the appropriate methods of switchyard services.

       

      I've considered using operationSelectors in the Camel JMS binding. For this case, I set a String property in the JMS message with the name of the method that should be invoked on the Switchyard service.

      I have my own OperationSelector implementation that gets the name of the method from this String property.

       

      However my approach doesn't seem to work. The Switchyard Bean services don't receive the appropriate messages and Debug information shows me that there is not operation information in the Exchange.

       

      I have created a simple example to demonstrate the above scenario.

       

      Could anyone help me? Any ideas?

       

      I'm working with Switchyard 0.6.0.Final.

       

      Regards,

      Kostas

        • 1. Re: Routing to Switchyard service with multiple methods
          igarashitm

          I could see orderServiceOp was in camel message header and your operation selector successfully got it. It just fails to retrieve SupportService instance from CDIMixIn. I'm not sure if it's possible though.

          • 2. Re: Routing to Switchyard service with multiple methods
            kostas_papag

            Hello Tomohisa,

             

            when you say that the CDIMixIn fails to retrieve the instance, you mean this part of the code : SupportService service = mixin.getObject(SupportService.class);   ?

            The List where I store the messages is static, so even if CDIMixIn fails to retrieve the proper instance of the service, the message should be there anyway.Moreover I get no log message that the message has been received from the Bean Service...

            Running the test in log level = DEBUG , i noticed the following messages :

             

            ...

            22:07:21,782 DEBUG [org.switchyard.internal.ExchangeImpl] Sending IN Message (979726925) on IN_ONLY Exchange (1513306926) for Service '{urn:switchyard-quickstart:camel-jms-example:0.1.0}CustomerService', operation 'null'.  Exchange state: OK

            ....

            22:07:21,804 DEBUG [org.switchyard.internal.ExchangeImpl] Sending IN Message (190331520) on IN_ONLY Exchange (1298706257) for Service '{urn:switchyard-quickstart:camel-jms-example:0.1.0}SupportService', operation 'null'.  Exchange state: OK...

            .....

            22:07:21,812 DEBUG [org.switchyard.internal.ExchangeImpl] Sending OUT Message (1614453842) on IN_ONLY Exchange (1298706257) for Service '{urn:switchyard-quickstart:camel-jms-example:0.1.0}SupportService', operation 'null'.  Exchange state: FAULT

            .....

             

            Seems that although the operation selector is picking the operation name , still the Exchange somehow doesn't  contain the proper operation....

            • 3. Re: Routing to Switchyard service with multiple methods
              igarashitm

              I think I got the root cause. operation name is lost since you're using interface.esb for the reference to the SupportService. If you use interface.java instead, and enable setHeader in the OrderRouteBuilder you're now commenting out, then works fine.

              • 4. Re: Routing to Switchyard service with multiple methods
                ibek

                Hi Kostas,

                 

                I recommend to use the Camel route filtering instead. (http://camel.apache.org/message-filter.html). As a <from> and <to> locations , you can use "switchyard://YourComponentName" so it will look like:

                 

                <component name="DirectProductOrder">

                  <camel:implementation.camel>

                      <route xmlns="http://camel.apache.org/schema/spring">

                          <from uri="switchyard://FromTheService"/>

                            .choice()

                                    .when(header("orderServiceOp").isEqualTo("Hello")).to("switchyard://HelloComponentRef")

                                    .when(header("orderServiceOp").isEqualTo("Bye")).to("switchyard://ByeComponentRef").stop()

                                    .otherwise().to("switchyard://OtherComponentRef")

                              .end()

                          <to uri="switchyard://ResultComponentRef"/>

                       </route>

                </camel:implementation.camel>

                ... your references and service

                </component>

                • 5. Re: Routing to Switchyard service with multiple methods
                  kostas_papag

                  Tomohisa your proposal works indded!

                  I was guessing that switchyard would pick the reference interface , after resolving the service name but seems that not the case. I will use your solution, thanks!

                   

                  Seems though I'm now running in a new problem. When building the jar  of this example and trying to deploy on Switchyard 0.6.0.Final , i get a strange exception :

                    [org.jboss.modules] (MSC service thread 1-6) Failed to define class com.example.order.OrderOperationSelector in Module "deployment.camel-jms-example.jar:main" from Service Module Loader: java.lang.LinkageError: Failed to link com/example/order/OrderOperationSelector (Module "deployment.camel-jms-example.jar:main" from Service Module Loader)

                            at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:396)

                            at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:243)

                            at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:73)

                            at org.jboss.modules.Module.loadModuleClass(Module.java:517)

                            at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:182)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)

                            at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)

                            at org.jboss.as.weld.WeldModuleResourceLoader.classForName(WeldModuleResourceLoader.java:68) [jboss-as-weld-7.1.1.Final.jar:7.1.1.Final]

                            at org.jboss.weld.bootstrap.BeanDeployer.loadClass(BeanDeployer.java:98) [weld-core-1.1.6.Final.jar:2012-03-21 18:52]

                            at org.jboss.weld.bootstrap.BeanDeployer.addClass(BeanDeployer.java:77) [weld-core-1.1.6.Final.jar:2012-03-21 18:52]

                            at org.jboss.weld.bootstrap.BeanDeployer.addClasses(BeanDeployer.java:123) [weld-core-1.1.6.Final.jar:2012-03-21 18:52]

                            at org.jboss.weld.bootstrap.BeanDeployment.createBeans(BeanDeployment.java:184) [weld-core-1.1.6.Final.jar:2012-03-21 18:52]

                            at org.jboss.weld.bootstrap.WeldBootstrap.deployBeans(WeldBootstrap.java:349) [weld-core-1.1.6.Final.jar:2012-03-21 18:52]

                            at org.jboss.as.weld.WeldContainer.start(WeldContainer.java:82) [jboss-as-weld-7.1.1.Final.jar:7.1.1.Final]

                            at org.jboss.as.weld.services.WeldService.start(WeldService.java:76) [jboss-as-weld-7.1.1.Final.jar:7.1.1.Final]

                            at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)

                            at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)

                            at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_35]

                            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_35]

                            at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_35]

                  Caused by: java.lang.NoClassDefFoundError: org/switchyard/component/common/selector/OperationSelector

                            at java.lang.ClassLoader.defineClass1(Native Method) [rt.jar:1.6.0_35]

                            at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) [rt.jar:1.6.0_35]

                            at java.lang.ClassLoader.defineClass(ClassLoader.java:615) [rt.jar:1.6.0_35]

                            at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) [rt.jar:1.6.0_35]

                            at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:327)

                            at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:391)

                            ... 21 more

                  Caused by: java.lang.ClassNotFoundException: org.switchyard.component.common.selector.OperationSelector from [Module "deployment.camel-jms-example.jar:main" from Service Module Loader]

                            at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)

                            at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)

                            at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)

                            ... 27 more

                   

                   

                  ... in my pom file i have the following dependency :

                   

                          <dependency>

                              <groupId>org.switchyard.components</groupId>

                              <artifactId>switchyard-component-common</artifactId>

                              <scope>provided</scope>

                          </dependency>

                   

                  Shouldn't the dependency be picked up by the container?

                  • 6. Re: Routing to Switchyard service with multiple methods
                    kostas_papag

                    Hello Ivo,

                     

                    Indeed this solution works if there is a single operation per service.

                    In my case though, I'm trying to direct the payload to the appropriate operation of one given service, not splitting the payload among different services. 

                    OperationSelector seem to be needed for such a case, so I decided to use my own java implementation of the selector to be able tomake the selection dynamically.

                     

                    Regards,

                    Kostas

                    • 7. Re: Routing to Switchyard service with multiple methods
                      igarashitm

                      Could you try again with adding this dependency to the SwitchYard module def on AS7? Probably it's the one I should have added...

                       

                      --- modules/org/switchyard/main/module.xml.orig
                      2012-12-06 12:08:18.539496142 -0500
                      +++ modules/org/switchyard/main/module.xml
                      2012-12-06 11:53:56.209081840 -0500
                      
                      @@ -57,6 +57,7 @@
                               <module name="org.switchyard.runtime"/>
                               <module name="org.switchyard.serial"/>
                               <module name="org.switchyard.security" export="true"/>
                      +        <module name="org.switchyard.component.common" export="true"/>
                               <module name="org.switchyard.component.http"/>
                               <module name="org.switchyard.component.remote"/>
                               <module name="org.switchyard.component.resteasy"/>
                      
                      1 of 1 people found this helpful
                      • 8. Re: Routing to Switchyard service with multiple methods
                        splatch

                        Specify header org.switchyard.operationName in camel router. It might be calculated, glued or whatever you would like to do. :-)

                        • 9. Re: Routing to Switchyard service with multiple methods
                          kostas_papag

                          Tomohisa, with this last fix I'm able to succesfully deploy my example.

                          Seemed that it was a configuration issue, but now Im sure, thx!

                           

                          Regards,

                          Kostas

                          • 10. Re: Routing to Switchyard service with multiple methods
                            kostas_papag

                            Tomohisa igarashi wrote:

                             

                            I think I got the root cause. operation name is lost since you're using interface.esb for the reference to the SupportService. If you use interface.java instead, and enable setHeader in the OrderRouteBuilder you're now commenting out, then works fine.

                             

                             

                            This solution worked indeed for my example.

                            However, seems that we can run into a different problem here :

                            By defining the services in the following way in switchyard.xml :

                             

                                    <component name="OrderRouteBuilder">

                                        <implementation.camel xmlns="urn:switchyard-component-camel:config:1.0">

                                            <java class="com.example.order.OrderRouteBuilder"/>

                                        </implementation.camel>

                                        <service name="OrderService">

                                            <interface.java interface="com.example.order.OrderService"/>

                                        </service>

                                        <reference name="SupportService">

                                            <interface.java

                                                    interface="com.example.order.SupportService"/>

                                        </reference>

                                    </component>

                                    <component name="SupportService">

                                        <implementation.bean xmlns="urn:switchyard-component-bean:config:1.0"

                                                             class="com.example.order.SupportServiceImpl"/>

                                        <service name="SupportService">

                                            <interface.java

                                                    interface="com.example.order.SupportService"/>

                                        </service>

                                    </component>

                             

                            , in a bit more complex example where transformers would be needed( OrderService and SupportService consuming different type of payload),

                            transfomation wouldn't kick in.

                            From my undestanding , currently switchyard checks the consumer and provider input type from the exchange contract and identifies what kind of transformation is needed. In the above case, the contract  input types are the same!

                             

                            There is a workaround that I see, to define "dummy" interfaces and provide them as a reference interface.

                            As I see it, maybe it would make sense that in the TransfomerHandler , the tranformation is based on the actual message content, and not on the contract.

                             

                            In any case , I attach this "enhanced" example , with the workaround desribed above.

                            • 11. Re: Routing to Switchyard service with multiple methods
                              kcbabo

                              There are actually two forms of transformation available to you in SwitchYard.  Declarative transformation is the type you are referring to in your last post.  The purpose of declarative transformation is to resolve incompatible message types between services, which is a very common problem.  If the message types are the same, then declarative transformation is not as good a fit.  As you mentioned, you could create a separate interface to force a transformation to occur if you really want to use declarative transformation.

                               

                              The other type of transformation would be the classic procedural transformation where you explicitly invoke a transformation from application logic.  The most common example of this would be to create a camel routing service and from within that route you can explicitly invoke a transformation processor (XSLT, data format, etc.).

                               

                              Ultimately, the flexibility is there to go with whatever suits you best.  Personally, I feel that declarative transformation is a good fit for reconciling messages which have the same information, but in different formats.  Procedural transformation is appropriate when you want to introduce business logic to inform the transformation - things like enrichment, code lookups, data cleansing, etc.

                              • 12. Re: Routing to Switchyard service with multiple methods
                                kostas_papag

                                Based on the findings of this topic, I created two tickets , https://issues.jboss.org/browse/SWITCHYARD-1209 and https://issues.jboss.org/browse/SWITCHYARD-1210 .

                                • 13. Re: Routing to Switchyard service with multiple methods
                                  igarashitm

                                  Hi Kostas,

                                   

                                  Thanks for raising it! I'll fix SWITCHYARD-1210 for sure. However, I have rejected SWITCHYARD-1209. interface.esb is only used for single operation one. That's by design.