Announcement Announcement Module
Collapse
No announcement yet.
Non-annotation driven Cafe example? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Non-annotation driven Cafe example?

    While using annotations to configure the ESB components makes for very little config, I have found it difficult to infer where particular components are. I also don't get an overview of the overall process flow. It feels to me that if I let my team develop services using annotations we would quickly end up with a ball of spaghetti services.

    So what I'd like to do is to ensure that most of the components are clearly defined. What I'm lacking is details on how to define some of the components without using annotations.

    For instance, how do you define a router and link it into the process flow such as that defined in the Cafe example?

    Could someone post a non-annotation driven config for the cafe example? Seeing the annotation driven and non-annotation driven side by side would be really useful.
    Last edited by william_ferguson_au@yahoo; May 26th, 2008, 02:56 AM. Reason: Typo in the header

  • #2
    In M4, we added namespace support for the <router/> and <splitter/> elements. They are not yet documented in the reference manual, but it is fairly straightforward. Here's a simple example:
    Code:
    <router id="router" ref="somePojo" method="someMethod"/>
    Thanks for the suggestion - I think we should provide a parallel version of the cafe demo that uses only XML.

    Comment


    • #3
      Thanks Mark. I had spotted the <router/> and <splitter/> elements and in fact thats what led to my post.

      How do I configure the input-channel for the router/splitter?

      Using annotations its
      Code:
      @MessageEndpoint(input="someChannel")
      but I can't see how it can be done using XML config
      Code:
      <splitter ref="splitter" method="split" output-channel="drinks"/>
      		
      <router ref="drinkRouter" method="resolveDrinkChannel"/>

      Comment


      • #4
        The <router/> and <splitter/> elements actually create instances that implement MessageHandler, so to supply the "input-channel", you just need to register them within a <handler-endpoint/> element. For example (from routerParserTests.xml):
        Code:
        <handler-endpoint handler="router" input-channel="input"/>
        
        <router id="router" ref="pojo" method="route"/>

        Comment


        • #5
          Mark, is the following config the correct way to specify the cafe example without using annotations?

          NB I can't check because I can't find spring-integration-core-1.0.0.M4 in the SpringSource bundle repository. Is there a way to browse the repository?

          Code:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans:beans xmlns="http://www.springframework.org/schema/integration"
          	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          	xmlns:beans="http://www.springframework.org/schema/beans"
          	xmlns:context="http://www.springframework.org/schema/context"
          	xsi:schemaLocation="http://www.springframework.org/schema/beans
          			http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
          			http://www.springframework.org/schema/integration
          			http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
          			http://www.springframework.org/schema/context
          			http://www.springframework.org/schema/context/spring-context-2.5.xsd">
          
          	<message-bus/>
          	<!--annotation-driven/ -->
          
          	<channel id="orders"/>
          	<channel id="drinks"/>
          	<channel id="coldDrinks"/>
          	<channel id="hotDrinks"/>
          	
          	<handler-endpoint handler="drink-splitter" input-channel="orders" />
          	<splitter id="drink-splitter" ref="splitter" method="split" output-channel="drinks"/> 
          	
          	<handler-endpoint handler="drinkRouter" input-channel="drinks"/>
          	<router ref="drinkRouter" method="resolveDrinkChannel"/>
          		
          	<target-endpoint target="barista" method="prepareColdDrink" input-channel="coldDrinks"/>
          	
          	<target-endpoint target="barista" method="prepareHotDrink" input-channel="hotDrinks">
          		<concurrency core="5" max="25" queue-capacity="0"/>
          	</target-endpoint>
          	
          	
          	<!-- Beans -->
          			
          	<beans:bean id="cafe" class="org.springframework.integration.samples.cafe.Cafe">
          		<beans:property name="orderChannel" ref="orders"/>
          	</beans:bean>
          	
          	<beans:bean id="barista" class="org.springframework.integration.samples.cafe.Barista">
          		<!--beans:property name="hotDrinkDelay" value="1000"/-->
          		<!--beans:property name="coldDrinkDelay" value="700"/-->
          	</beans:bean>
          	
          	<beans:bean id="drinkRouter" class="org.springframework.integration.samples.cafe.DrinkRouter"/>
          	
          	<beans:bean id="splitter" class="org.springframework.integration.samples.cafe.OrderSplitter"/>
          	
          </beans:beans>

          Comment


          • #6
            Or perhaps even possible to contract the orders and drinks channel consumers to:

            Code:
            <handler-endpoint handler="splitter" method="split" 
                              output-channel="drinks" input-channel="orders"/>
            	
            <handler-endpoint handler="drinkRouter" method="resolveDrinkChannel" 
                              input-channel="drinks"/>

            Comment


            • #7
              A was also wondering whether any thought had been given to representing the handler-endpoints and handler using contained elements like:

              Code:
              <handler-endpoint input-channel="drinks">
              	<router ref="drinkRouter" method="resolveDrinkChannel"/>
              </handler-endpoint>
              	
                or
              
              <handler-endpoint input-channel="drinks">
              	<handler ref="drinkRouter" method="resolveDrinkChannel"/>
              </handler-endpoint>
              While more verbose than the config immediately above, it his seems to make the distinction between endpoint and handler much clearly. The handler endpoint is only concerned with input/output channels while the contained handler/router/splitter element defines the handler to invoke.

              Also the config for a source-endpoint, which I imagine is something like the following:

              Code:
              <source-adapter id="my-source-adapter" ref="some-bean" method="some-method"/>
              <source-endpoint source="my-source-adapter" channel="some-output-channel">
              	<schedule period="500"/>
              </source-endpoint>
              would seem to be more clearly represented by something like (note change of channel attribute to output-channel as well as contained adapter element):
              Code:
              <source-endpoint output-channel="some-output-channel">
              	<adapter ref="some-source-bean" method="source-bean-method"/>
              	<schedule period="500"/>
              </source-endpoint>
              just my 2 cents, but I'd be interested in feedback.

              Comment


              • #8
                Good ideas. I had the same thought on allowing handlers nested inside handler-enpoints (while reading this post). An argument for it you haven't mentioned is the fact that you might not want to expose the handler to the outside by id.

                Another benefit would be that it is possible to validate nesting with xsd, but references can only be evaluated at runtime.

                The downside is that this would complicate the schema and the namespace handlers. It will also add to the responsibility for backwards compatibility (you can put this in, but you can never take it out).

                The options you have now are already quite sufficient:
                1. namespace support with references (like your sample)
                2. wiring annotated beans explicitly (intermediate solution)
                3. component scanning

                I would personally go for option 2 most of the times I think. I do feel uncomfortable with sticking channel names inside classes, but those can be injected as well.

                Code:
                <bean class="..MyRouter" p:inputChannel="someInput" 
                    p:caseAOutput="AMessages" p:caseBOutput="BMessages" />
                <si:annotation-driven/>
                Code:
                @MessageEndpoint public class MyRouter {
                  @Router String aOrB(Message m){
                    return m.getPayload().isCaseA() ? caseAOutput : caseBOutput;
                  }
                }
                Who needs more namespace features?

                Comment

                Working...
                X