Announcement Announcement Module
Collapse
No announcement yet.
How I can define a dynamic channels for int:router's "method" referenced Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How I can define a dynamic channels for int:router's "method" referenced

    Hello Guys

    I have the follow

    Code:
    <int:router id="router"
    		input-channel="inicio"		
    	        apply-sequence="true"
    		resolution-required="true" 
    		default-output-channel="noTypeMatchChannel"
    		method="metodoRouter01"
    		ref="myRouterSinAnnotationUno"
    	/>
    where the Java code is

    Code:
    public String metodoRouter01(Message<?> message){
    		
    	logger.info(".... message: {}", message);
    		
    	if(message.getPayload() instanceof String)
    		return "stringChannel";
    	else if(message.getPayload() instanceof Integer)
    		return "integerChannel";
    	else if(message.getPayload() instanceof ItemArticulo)
    		return "instrumentoMusicalChannel";
    	else
    		return null;
    }
    I am checking each payload type to return the name of the channel. Since I use a String return type for the method used by the Router.

    I could declared a static String[] type instead to get later a desired item through an index for each if/elseif scope to do the same approach

    My problem is when I try to do the same with MessageChannel I mean, I must have the follow (code located in other class)

    Code:
    private DirectChannel stringChannel;
    private DirectChannel integerChannel;
    private DirectChannel instrumentoMusicalChannel;
    	
    @Value("#{stringChannel}")
    public void setStringChannel(DirectChannel stringChannel) {
    	this.stringChannel = stringChannel;
    }
    
    @Value("#{integerChannel}")
    public void setIntegerChannel(DirectChannel integerChannel) {
    	this.integerChannel = integerChannel;
    }
    
    @Value("#{instrumentoMusicalChannel}")
    public void setInstrumentoMusicalChannel(DirectChannel instrumentoMusicalChannel) {
    	this.instrumentoMusicalChannel = instrumentoMusicalChannel;
    }
    
    public MessageChannel metodoRouter01(Message<?> message){
    		
    	logger.info("... message: {}", message);
    					
    	if(message.getPayload() instanceof String){
    		return stringChannel; 
    	}
    	else if(message.getPayload() instanceof Integer){			
    		return integerChannel;			
    	}
    	else if(message.getPayload() instanceof ItemArticulo){			
    		return instrumentoMusicalChannel;			
    	}
            else
    	        return null;
    }
    The code work fine, but I must declare each channel like a variable, it could be painful if my flow integration has 10 - 15 channels, exists a way to only declare for example just one

    Code:
    private DirectChannel directChannel;
    	
    public void setDirectChannel(DirectChannel directChannel) {
    	this.directChannel = directChannel;
    }
    and in the if scope in someway just then indicate explicitly which Channel must be returned?

    Code:
    if(message.getPayload() instanceof String){
            //something to do get from my flow integration the stringChannel element
    	return directChannel; 
    }
    Thanks in advanced

  • #2
    Why aren't you using <intayload-type-router> with <mapping>?

    Comment


    • #3
      Hello Oleg


      Why aren't you using <intayload-type-router> with <mapping>?
      I did and work fine

      I am working with this approach only to test the part of Configuring a Router with Annotations where appear the follow snippet code

      Code:
      @Router
      public MessageChannel route(Message message) {...}
      
      @Router
      public List<MessageChannel> route(Message message) {...}
      
      @Router
      public String route(Foo payload) {...}
      
      @Router
      public List<String> route(Foo payload) {...}
      Since I am not calling some Service class, therefore I am doing explicitly this fake resolution like I shown on my first post

      I hope you see my point

      Comment


      • #4
        Well if you doing it in code than you are essentially doing the same thing we do. In other words your if/else is an equivalent of <mapping>. Internally we use ChannelResolver strategy (BeanFactoryChannelResolver) but it does the same thing. I guess I am missing the question.

        Comment


        • #5
          Hello Oleg

          Well if you doing it in code than you are essentially doing the same thing we do. In other words your if/else is an equivalent of <mapping>. Internally we use ChannelResolver strategy (BeanFactoryChannelResolver) but it does the same thing
          Yes, totally agree, I am just testing the other options available, of course with mapping is more cleaner but with int:router I could do about calling a method to later decide the output channel, I mean

          Code:
          public String metodoRouter01(Message<?> message){
          		
          	String x = this.someServiceBo(...);
          		
          	if(x....)
          		return "xxx";
          	else
          		return "yyy";
          }
          I guess I am missing the question.
          Yes

          I have


          Code:
          private DirectChannel stringChannel;
          private DirectChannel integerChannel;
          private DirectChannel instrumentoMusicalChannel;
          	
          @Value("#{stringChannel}")
          public void setStringChannel(DirectChannel stringChannel) {
          	this.stringChannel = stringChannel;
          }
          
          @Value("#{integerChannel}")
          public void setIntegerChannel(DirectChannel integerChannel) {
          	this.integerChannel = integerChannel;
          }
          
          @Value("#{instrumentoMusicalChannel}")
          public void setInstrumentoMusicalChannel(DirectChannel instrumentoMusicalChannel) {
          	this.instrumentoMusicalChannel = instrumentoMusicalChannel;
          }
          I must declare each channel like a variable, it could be painful if my flow integration has 10 - 15 channels, I want to know if exists a way to only declare for example just only one variable

          Code:
          private DirectChannel directChannel;
          	
          public void setDirectChannel(DirectChannel directChannel) {
          	this.directChannel = directChannel;
          }
          and latter in the if scope in someway just then indicate explicitly which Channel must assigned and returned?

          Code:
                String result = this.someServiceBo(...);
          
                 if(result ....){
                       //something to do here 
                       //to get from my flow integration the abcChannel element reference
                       //and assign to directChannel    
          	     return directChannel; 
                 else if(result ...){
                       //something to do here 
                       //to get from my flow integration the xyzChannel element reference
                       //and assign to directChannel    
          	     return directChannel; 
                 }
                 ...
          }
          I edited the code above how a new version to avoid confuse with <intayload-type-router> with <mapping> behavior like you did, sorry for the confusion

          Practically the directChannel is unware about which Channel it must represent by itself until the code enter to some if/else if an then there, this directChannel is assigned to the some desired channel from the flow integration, in this way I avoid to declare 4 or 10 different DirectChannels

          Thank you
          Last edited by dr_pompeii; Aug 23rd, 2011, 11:49 AM.

          Comment


          • #6
            Code:
            	@Autowired
            	Map<String, MessageChannel> channels;
            For each entry in the map, the key is the bean name, the value is the channel.

            Comment


            • #7
              Hello Gary

              Thanks for the reply

              I am working with this router and these channels

              Code:
              <int:channel id="dvdChannel" />	
              <int:channel id="instrumentoMusicalChannel" />
              ...
              <int:router id="router"
              		input-channel="inicio"		
              	        apply-sequence="true"
              		resolution-required="true" 
              		default-output-channel="noTypeMatchChannel"
              		method="metodoRouter01"
              		ref="myRouterConAnnotationUno"
              />
              I am little confused about your code
              Code:
              @Autowired
              Map<String, MessageChannel> channels;
              For each entry in the map, the key is the bean name, the value is the channel.

              With your approach Should I define a stand alone map collection in my flow integration file referring these channels?, Am I right?, or What did you do mean?

              Thank you

              Comment


              • #8
                I was simply answering this question...

                I must declare each channel like a variable, it could be painful if my flow integration has 10 - 15 channels, I want to know if exists a way to only declare for example just only one variable
                You an use a map to get all the channels, mapped by their names. When your code decides which channel name to send to, simply lookup the map.

                Code:
                return channels.get("xyzChannel");
                The point is, though, it's much easier to use the form of router that returns a channel name, not a MessageChannel object; as Oleg said, the framework will do the same thing and resolve the name to a channel.

                Again, the general idea is not to tie your code (router or anything) to the framework. There is no need for your Router to know about channels (Direct or otherwise); just use names.

                Comment


                • #9
                  Hello Gary

                  Thanks again for your time and help

                  You an use a map to get all the channels, mapped by their names. When your code decides which channel name to send to, simply lookup the map.
                  I am totally agree, but is necessary create something like <util:map id="channels">
                  to let my class work in peace with

                  Code:
                  	@Autowired
                  	Map<String, MessageChannel> channels;
                  The point is, though, it's much easier to use the form of router that returns a channel name, not a MessageChannel object; as Oleg said, the framework will do the same thing and resolve the name to a channel.
                  I am agree with you, but I am just testing the other options to learn well the correct configuration and the most appropiate

                  Again, the general idea is not to tie your code (router or anything) to the framework. There is no need for your Router to know
                  Like my previous last sentence

                  Thanks a lot for your time

                  Comment


                  • #10
                    is [ it ] necessary create something like <util:map id="channels">
                    No, spring will collect up all beans of that type in the context and create a Map for you and inject it here. It is the same as calling applicationContext.getBeansOfType(SomeType.class), which returns a Map<String,SomeType>.

                    Comment


                    • #11
                      Hello Gary

                      Thanks for the reply

                      No, spring will collect up all beans of that type in the context and create a Map for you and inject it here.
                      Totally agree, I just tested and work, but it going explain an interesting problem the red part arise in a particular case I going to explain below

                      It is the same as calling applicationContext.getBeansOfType(SomeType.class), which returns a Map<String,SomeType>.
                      Agree

                      The case where it fails is the follow ( I use a List instead of a Map but the idea is the same):

                      spring will collect up all beans of that type
                      See the code

                      Code:
                      @MessageEndpoint
                      public class MyRouterConAnnotationCuatroAltern {
                      
                      	private static final Logger logger = LoggerFactory.getLogger(....class);
                      	
                      	private List<MessageChannel> listChannels;
                      	
                      	@Autowired	
                      	public void setListChannels(List<MessageChannel> listChannels) {
                      		this.listChannels = listChannels;
                      	}
                      	
                      	@Router
                      	public List<MessageChannel> metodoRouter01(Message<?> message){
                      				
                      		logger.info("... metodoRouter01 message: {}", message);	
                      		return listChannels;		
                      	}	
                      }
                      working with

                      Code:
                      <int:channel id="inicio" />
                      
                      <int:channel id="final" >
                      	<int:queue capacity="40"/>
                      </int:channel>
                      
                      <int:channel id="dvdChannel" />	
                      <int:channel id="instrumentoMusicalChannel" />
                      	
                      <int:router id="router" 
                      		input-channel="inicio"
                      		apply-sequence="true"
                      		ref="myRouterConAnnotationCuatroAltern"	
                      		/>
                      ... some service activator
                      The @Autowired work totally fine but my application goes to an infinite loop, I did realize this thanks to the history and logger options

                      ... [Headers={timestamp=1314205383171, id=19570b96-044c-4e7e-8007-13f5973f8983, history=inicio,router,inicio,router,inicio,router,inicio,router,inicio,router,inicio, router,inicio,router,inicio,router,inicio,router,i nicio,router,inicio,router,inicio,router,inicio,ro uter,inicio,router,inicio,router,inicio,router,... .., [345d788e-89fc-46ac-be06-6cd0a4d543c6, 1, 7], [248a7791-b0bc-464d-bf1b-5a02257dbf93, 1, 7]], sequenceNumber=1}]
                      Practically since @Autowired got all the channels, a feedback effect of channels happen, through the orange and green elements shown above

                      I tried therefore create a customized list in this way to use explicitly my desired channels

                      Code:
                      <util:list id="channels"
                      	   list-class="java.util.ArrayList"
                      	   value-type="org.springframework.integration.MessageChannel"
                        	>
                      	<ref bean="dvdChannel"/>		
                      	<ref bean="instrumentoMusicalChannel"/>
                      </util:list>
                      When I use now

                      Code:
                      @Autowired
                      @Qualifier("channels")
                      public void setListChannels(List<MessageChannel> listChannels) {
                      	this.listChannels = listChannels;
                      }
                      I got

                      Code:
                      Exception in thread 
                      "main" org.springframework.beans.factory.BeanCreationException: 
                      Error creating bean with name 'myRouterConAnnotationCuatroAltern': 
                      Injection of autowired dependencies failed; 
                      nested exception is 
                      org.springframework.beans.factory.BeanCreationException: 
                      Could not autowire method: public void com.manuel.jordan.router.conannotation.silista.altern.MyRouterConAnnotationCuatroAltern.setListChannels(java.util.List); 
                      nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
                      No matching bean of type 
                      [org.springframework.integration.MessageChannel] found for dependency 
                      [collection of org.springframework.integration.MessageChannel]: 
                      expected at least 1 bean which qualifies as autowire candidate for this dependency.
                      Dependency annotations: {}
                      has sense since I use <util:list and not some <bean

                      Therefore the solution is

                      Code:
                      @Value("#{channels}") 
                      public void setListChannels(List<MessageChannel> listChannels) {
                      	this.listChannels = listChannels;
                      }
                      And all work fine

                      Thanks for your time and best regards from Peru friend!

                      Comment

                      Working...
                      X