Announcement Announcement Module
Collapse
No announcement yet.
Spring remoting via spring integration - Am I missing some concepts? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring remoting via spring integration - Am I missing some concepts?

    Hi all,

    when I got in touch with spring integration, I was certain about the straightforwarded concepts - as usual when it comes to spring.

    I thought SI is an abstract layer above spring remoting and is for example capable of handling synchronous as well as assynchronous service calls. Furthermore I pesumed SI enables the configuration of a message and service bus. But in reality I ran into some Pitfall.

    All I wanted is:

    Client calls ServiceInterface assynchronously by using jms remoting capabilites (with Queue so that the sending and the receiving process can be transactional). Server is receiving the service call and delegates it to the corresponding service implementation.

    The Client should be aware of the following interface

    public interface SpecificService {

    public void foo(SpecificDto dto)

    public void foo(SpecificDto dto1, SpecificDto dto1)

    public SpecificDto bar(SpecificDto dto)

    further methods.....

    }

    Payload type matching, gateway pattern, service activators are all wonderful SI concepts but they didn't turn out to be very succesful - at least for me.

    Spring remoting offers JmsInvokerProxyFactoryBean and JmsInvokerServiceExporter. Are those concepts missing in SI???

    I would appreciate some ideas about the "How can I map the exposed interface on the client's side to my server side's implementation".

    Cheers,
    Matthew

  • #2
    They aren't missing they are different concepts. Spring Integration isn't about remoting it is about loosy coupling yuor system using messages (I suggest a read of the EIP book.) Spring remoting is about making an RPC call, which isn't loose coupled.

    So the misunderstanding is that you are trying to use the wrong means to an end. You want RPC and that is not what Spring Integration was build/designed for.

    Comment


    • #3
      Hi Marten,
      thx for the rough explanation. I agree that the integration of entrprise application by using messages like xml (e.g. communication protocal is jms) is perfectly supported by SI. But nevertheless I was hoping that SI supports an efficient way to couple loosly exposed services among different systems.


      In other words, it would be great if you could have a single service on the server side with multiple methods. All you need is to wire the incoming service message to a corresponding service that is capable of handling it. Now the magic is done by payload type matching. But in real life the same payload could be used to invoke different functionality - that means different methods.

      Now I am looking in more detail into spring RPC.

      Comment


      • #4
        Marten is correct that Spring Integration is rather purposefully NOT taking the RPC approach. With RPC, the client and server are tightly coupled to the level of a particular interface, its methods, and their argument types. Rarely is that degree of coupling between two disparate systems a good idea. It should only be considered an option when both systems are controlled by the same development team and released on the same schedule.

        That said, the closest thing that is supported by Spring Integration is the use of a <gateway/> (internally a GatewayProxyFactoryBean) that exposes an interface that can be injected into client code (much like any of Spring remoting ProxyFactoryBeans). That may *or may not* be the same interface that is implemented by the actual POJO being invoked on the other side of a <service-activator/>. If it is the same interface, then you have something very similar to RPC but with the added "channel" between so that other components may be added to the pipeline (transformation, routing, etc.). The fact that it does not need to be the same interface is what gives you the flexibility to use the same non-invasive approach without the same degree of coupling.

        If you actually do want RPC with JMS as a transport and have no need for transformation, routing, filtering, etc., then I would say that JmsInvokerServiceExporter and JmsProxyFactoryBean are sufficient.

        Hope that helps.
        -Mark

        Comment


        • #5
          Hi Mark,

          thx for the reply. That was the intention why I looked into SI. Sending service messages and transform, route and finally configure them loosly coupled to a specific implementation.

          But how can the <service-activator/> component map a certain service message to a POJO that is able to handle it???

          I mean .... The gateway interface in my case contains multiple methods with multiple arguments. Does SI provide a mechanism to handle such a scenario??

          In case the problem is too abstract I can provide some code snippets.

          Comment


          • #6
            Spring Integration will try to map the Message to the appropriate method (often fine-tuned by either a method name attribute provided in XML or one or more method-level annotations). It attempts to match the payload type to the argument type. Maybe you can create a test case with your specific example and see if there are still limitations?

            Comment


            • #7
              Ok , here is a snippet of the business case. The goal is to inegrate several enterprise applications into one central platform. There is a point2point connection between the central platform and each external aplication. Some p2p-connections I can integrate perfectly with SI by using jms-message-driven-listener, transformer and routers and so on. Others p2p integrations turn out to be difficult. Here one example:

              Some external systems use services provided by the central platform which will be executed asynchronously.

              These external system are aware of the following interface:

              public interface Service {

              public void log(Dto dto);
              public void process(Dto dto);
              public void replicate(Long id, Dto dto)

              }

              The corresponding SI configuration on client looks like:

              <!-- outbound side-->

              <si:channel id="outbound" />

              <jee:jndi-lookup id="exampleQueue" jndi-name="jms/ExampleQueue" />

              <si:gateway
              service-interface="com.example.service.Service"
              id="serviceGateway">
              <si:method name="log" request-channel="outbound" />
              <si:method name="process" request-channel="outbound" />
              <si:method name="replicate" request-channel="outbound" />
              </si:gateway>

              <jms:outbound-channel-adapter channel="outbound"
              destination-name="exampleQueue" />

              The central platform contains all implementations of the exposed services. No surprise when examing an implemtation class of a general service like...

              public class Service implements Service {

              public void log(Dto dto) {
              // implementation
              }

              public void process(Dto dto) {
              // implementation
              }

              public void replicate(Long id, Dto dto) {
              // implementation
              }
              }

              The inbound configuration for that specific point2point connection is:

              <!-- Inbound side-->

              <jee:jndi-lookup id="exampleQueue" jndi-name="jms/ExampleQueue" />

              <si:channel id="inbound" />

              <jms:message-driven-channel-adapter
              channel="inbound" container="exampleListenerContainer" />

              <si:service-activator input-channel="inbound"
              ref="serviceImpl" />

              <beans:bean id="exampleListenerContainer"
              class="org.springframework.jms.listener.DefaultMes sageListenerContainer">
              <beansroperty name="connectionFactory" ref="connectionFactory" />
              <beansroperty name="destinationName" value="exampleQueue" />
              <beansroperty name="sessionTransacted" value="true" />
              </beans:bean>

              <beans:bean id="serviceImpl" class="com.example.service.impl.ServiceImpl" />

              Briefly there is only one queue, which is responsable for logic task (in this case handling a specific service asynchronously)

              How do I have to extend the server side's configuration to be sure that each of the method log, process and replicate is handled by the proper service implementation?

              Does SI support wrapping multiple arguments (@see replicate(Long id, Dto dto) ) into a message's payload?

              Thx for any insights

              Comment


              • #8
                Part of a common misconception with regards to services in general (non-SI related) is the fact that people tend to view Java class as service. IMHO it is wrong. Java class is a collection of related services, while service is just a method. So in a case where you have a class that has multiple methods it is perfectly fine to have multiple service-activator elements referencing the same bean (via 'ref' attribute) while providing method attribute to map each service-activator to a given service.

                Comment


                • #9
                  Hi Oleg,

                  I'm fine with your explanation. The question is how can I use multiple service activators? I discoverd a strange phenomenom when I tried out my SI example.

                  When calling 10 times log unexpectedly 5 times the method log and 5 times the method process were invoked by using the following multiple service activator settings.

                  <si:service-activator input-channel="inbound"
                  ref="serviceImpl" method="log" />

                  <si:service-activator input-channel="inbound"
                  ref="serviceImpl" method="process" />

                  <beans:bean id="serviceImpl" class="com.example.service.impl.ServiceImpl" />

                  For me unexpected behavior but understandable when looking at the concept of payload type matching. SI will try to match the payload type to the argument type like Mark noticed. For the sake of having a clean configuration I like to have just one jms queue that purpose is to handle the communication between two systems.

                  How do I have to configure the service provider side to be sure that for each external gateway interface and its defined methods the pipelined messages towards the queue is handled by the proper method of a certain class?

                  Comment


                  • #10
                    What you are witnessing there is the default "round robin" load-balancing. It's actually invoking those 2 consumers each every other time a Message arrives.

                    If you want dynamic type matching for a single consumer there are really two options. 1) Provide the "method" attribute in the <service-activator/> and make sure that all handler methods have the same name or 2) leave out the method name and rely on type matching across all public methods. For fine-tuning option #2, assuming you have control over the class, you can also add @ServiceActivator on the methods that you want to be considered as candidates.

                    Comment


                    • #11
                      However looking at your class it doesn't seem like dynamic type matching Mark was referring to is an option for you. This means you have to bind each service-activator to an independent input-channel and put a router in front of it:
                      Code:
                                                              input-channel -> service-activator
                                                           / 
                      Gateway -> request-channel -> router
                                                           \
                                                              input-channel -> service-activator
                      The router could route based on the method name which is available from Message History. You can see example of how to retrieve gateway's method name from the Message History in Loan Broker sample - http://blog.springsource.com/2010/03...tation-part-1/

                      Comment

                      Working...
                      X