Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Confusion with int:exception-type-router (resolution channels)

  1. #1
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,806

    Question Confusion with int:exception-type-router (resolution channels)

    Hello Guys

    I am trying to solve the problem of configure input/output channels when I use a int:service-activator together with a int:exception-type-router.

    Before to follow just to recall in the section 5.1.2. Routing and Error handling appear the follow

    Spring Integration also provides a special type-based router called
    ErrorMessageExceptionTypeRouter for routing Error Messages
    (Messages whose payload is a Throwable instance).

    ErrorMessageExceptionTypeRouter is very similar to the PayloadTypeRouter.
    In fact they are almost identical.


    The only difference is that while PayloadTypeRouter navigates the instance hierarchy of a payload instance (e.g., payload.getClass().getSuperclass()) to find the most specific type/channel mappings,the ErrorMessageExceptionTypeRouter navigates the hierarchy of 'exception causes' (e.g., payload.getCause()) to find the most specific Throwable type/channel mappings.
    I am assuming that any Exception would be generated or arise from a Service Activator and/or Transformer, perhaps from other endpoint, the point is handle the Exception thrown.

    I going to work with an ErrorMessage since it let has the payload explicitly of type Throwable

    The follow code work fine (match colors for a better understanding)

    Code:
    	
    <int:exception-type-router input-channel="myErrorChannel" >
    	<int:mapping exception-type="com.manuel.jordan.exception.MyErrorMessageException" 
                                channel="myErrorMessageException"/>
    	<int:mapping exception-type="java.lang.IllegalArgumentException" 
                                channel="illegalChannel"/>
    	<int:mapping exception-type="java.lang.NullPointerException" 
                                channel="npeChannel"/>			
    </int:exception-type-router>
    
    <int:service-activator id="errorServiceActivator01"
    		       input-channel="inicio"
    		       output-channel="myErrorChannel"
    		       method="serviceActivator03"
    		       ref="errorServiceActivator"						   					   
    							/>
    	
    <int:service-activator id="objectServiceActivator01"
    		       input-channel="myErrorMessageException"
    		       output-channel="final"
    		       method="serviceActivator03"
    		       ref="objectServiceActivator"						   
    							/>
    I did realize the input-channel attribute of the int:exception-type-router element is mandatory, therefore must exists an exclusive message channel only to send and receive ErrorMessage exclusively for this type of Router

    Below the code of the method serviceActivator03 which belong to errorServiceActivator

    Code:
    public Message<?> serviceActivator03(Message<?> message)throws MyGlobalException{
    		
    	logger.info("serviceActivator03 message: {}", message);
    		
    	boolean control = true;
    		
    	if(control){
    		
    		logger.info("66666666");
    			
    		MyErrorMessageException myErrorMessageException = 
                            new  MyErrorMessageException("MyErrorMessageException");
    
    		ErrorMessage errorMessage = new ErrorMessage(myErrorMessageException);
    									
    		return errorMessage;
    	}
    	else
    		return message;
    		
    	}
    }
    The code work fine, I have some observations, doubts and confusion, please give me a hand

    1) the Service Activator has explicitly configured the output channel to myErrorChannel, therefore practically it call the Router (it is little illogic, read (2) ).

    2) if my boolean variable control is changed to false, therefore the Exception never is thrown, the application work fine but the original Message sent it is lost, I think due the payload is not a Throwable type (I sent originally a String like payload).

    3) To solve (1) and (2). How I could do the follow.

    3.1) Has any amount of Service Activators where the output channel be free (I mean, not explicitly configure each output channel to some int:exception-type-router)

    3.2) from 3.1 if only I have detected some error, classic try/catch, I want create the ErrorMessage and it should go explicitly to some int:exception-type-router through some configuration

    Thanks in advanced
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  2. #2
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,145

    Default

    Manuel, when in doubt look at the code...

    Code:
    public class ErrorMessageExceptionTypeRouter extends AbstractMessageRouter {
    
    	@Override
    	protected List<Object> getChannelIdentifiers(Message<?> message) {
    		String channelIdentifier = null;
    		Object payload = message.getPayload();
    		if (payload != null && (payload instanceof Throwable) && this.channelIdentifierMap != null) {
    			Throwable mostSpecificCause = (Throwable) payload;
    			while (mostSpecificCause != null) {
    				String mappedChannelIdentifier = this.channelIdentifierMap.get(mostSpecificCause.getClass().getName());
    				if (mappedChannelIdentifier != null) {
    					channelIdentifier = mappedChannelIdentifier;
    				}
    				mostSpecificCause = mostSpecificCause.getCause();
    			}
    		}
    		return Collections.singletonList((Object) channelIdentifier);
    	}
    
    }
    The exception type router is really intended for use on an error flow (downstream of an error channel, e.g. on a gateway).

    As you have observed, and can see in the code, if the payload is not a Throwable, the message is not routed anywhere.

    As you can also see, we drill down to the most specific cause.

    If your inbound endpoint has an error channel, and your service, invoked by a service activator throws, say, a NullPointerException, Spring Integration will create an error message with a payload of MessagingException. The MessagingException will have two attributes - the failedMessage, and the cause (your NullPointerException). This ErrorMessage will then be sent to the error channel and you can route based on the original exception, in this case NPE.

    HTH
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  3. #3
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,806

    Default

    Hello Gary

    Thanks again for your time and reply, I really appreciate, if we following in this way, soon I owe you a truck of beer

    when in doubt look at the code...
    I forgot that, yes, you are right, but I think more valuable and how complement the English explanation of the developers

    From your code, I could conclude the follow ideas, please correct me, If I am wrong

    Code:
    protected List<Object> 
    return Collections.singletonList((Object) channelIdentifier);
    for this case it should be return a List only with a unique element, right?, it could be a List with more items in case the we work with RecipientListRouter

    Practically the method implementation checks that exists a payload and it must be of type throwable and the the Map/*List* of channels to be evaluated must exists (channelIdentifierMap).

    Within the while cycle, it goes around the hierarchy of exceptions until find one that exists like a key from the channelIdentifierMap to assign the output channel.

    The exception type router is really intended for use on an error flow (downstream of an error channel, e.g. on a gateway).
    Yes, I concluded the same, or in case if we have some endpoint and we dont want handle the exception thrown and caught (try/catch), instead, we forward this Exception within an ErrorMessage to the unique output channel with the prior knowledge that this Exception should arrive to this special kind of router, I am correct?

    Here arise again a similar question I wrote in the first post , if my previous paragraph or idea is correct I have the follow ideas and doubts

    1) We must very sure and accept the fact that we are not going to handle the Exception within the Service Activator, therefore once caught the Exception we must create an ErrorMessage and forward to the unique output channel of this Service Activator

    2) From my first post, if we have the follow situation where if the Service Activator could has the risk the Service called could throw or could not throw an Exception (duplicate PK in the DB) we are in problems about the desicion of the output channel, due the follow two cases

    2.1) If I handle the caught Exception therefore the output channel could be "nextEndPointChannel"

    2.2) If I do not handle the caught Exception therefore the output channel could be "errorChannelToSomeExceptionTypeRouterChannel"

    Practically from 2.1 and 2.2 the output channel is exclusive

    I hope you see now my point, now here arise a new question (just an idea):

    Why not each Service Activator (perhaps other endpoints) should has two output channels, one or the classic to forward to the next endpoint and a secundary dedicated to only send ErrorMessages (only if we want it)

    Recall we have by default the errorChannel, or Spring Integration could create a new MessageChannel implementation but being DataType only for Throwable objects, thus we have a strict control.

    Therefore we can have an ExceptionTypeRouter with its input channel only restricted for Throwable objects (using DataType), without care or worry about from which endpoint was sent it the ErrorMessage.

    Therefore if we have many endpoints with high risk to throw the same exception and we want a central to control and forward this Exception to an unique place to be handle, I mean one place to handle a type of Exception, we can use the ExceptionTypeRouter

    Let me know your thoughts!

    If your inbound endpoint has an error channel, and your service, invoked by a service activator throws, say, a NullPointerException
    You see, you are assuming my endpoint(Service Activator) has an error channel how its output, what happen if none Exception never is thrown?, I just only forward in peace to the next endpoint

    Spring Integration will create an error message with a payload of MessagingException.
    Yes, it is the base class about the hierarchy of Exceptions on Spring Integration, I used to receive its sub classes like MessageHandlingException, but it happen automatically breaking by complete the flow integration process

    The MessagingException will have two attributes - the failedMessage, and the cause (your NullPointerException). This ErrorMessage will then be sent to the error channel and you can route based on the original exception, in this case NPE.
    Totally agree


    My Best Regards
    Last edited by dr_pompeii; Aug 20th, 2011 at 01:41 PM.
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  4. #4
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,145

    Default

    for this case it should be return a List only with a unique element, right?
    Correct because a Map can only have one instance of the exception type as a key. However, you can route to multiple channels by using...

    Code:
    channel="channel1,channel2"
    You could also put a RLR downstream of a single channel.

    1) We must very sure and accept the fact that we are not going to handle the Exception within the Service Activator, therefore once caught the Exception we must create an ErrorMessage and forward to the unique output channel of this Service Activator
    We generally don't recommend using SI APIs directly in user code - tying your application to the framework. There is no reason your service needs to know about ErrorMessages; simply allow the exception to propagate and the framework will take care of creating the ErrorMessage.

    Why not each Service Activator (perhaps other endpoints) should has two output channels,
    There is no need for this; the exception is thrown to the closest element (usually a gateway or inbound adapter) that has an error channel and the ErrorMessage is sent there. Think of the error channel as like a java try{} block further down the stack.

    You see, you are assuming my endpoint(Service Activator) has an error channel ...
    No I am not. In my text (that you quoted), I said inbound endpoint. This is usually a gateway of some kind, or an inbound adapter; we only have error-channel configuration there. If you want to catch an exception mid-flow, you can add a service-activator that invokes a gateway (that has an error-channel).

    I hope that clears everything up.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  5. #5
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,806

    Default

    Hello Gary

    Thanks a lot for your time and reply, I really appreciate

    Correct because a Map can only have one instance of the exception type as a key.
    I referred to this code

    Code:
    protected List<Object> 
    return Collections.singletonList
    Therefore Map vs List

    Code:
    channel="channel1,channel2"
    You could also put a RLR downstream of a single channel.
    Interesting the bold part, when is wise use such approach?.

    I just did a search with Firefox with this pattern channel=" and I checked each match throughout SI documentation and none snippet code about using channels with comma appear

    We generally don't recommend using SI APIs directly in user code - tying your application to the framework. There is no reason your service needs to know about ErrorMessages;
    Totally agree, but I am creating the ErrorMessage in my Service Activator not in the Service Object, from my Service Activator I call some method offered by the Service Object, therefore if this last thrown an Exception I caught in my Service Activator

    Therefore I am keeping the "same" approach like does a Controller, in this case the endpoint

    simply allow the exception to propagate and the framework will take care of creating the ErrorMessage.
    Yes, but all the application is aborted, is the same when in a Web Controller I call some Service Object and it thrown an Exception and I didnt catch it, therefore I receive the error stack trace directly in my jsp or view

    I hope that clears everything up
    Not for the two last and most important paragraphs, I will research later these components when I arrive to such elements for my experiments, perhaps I am complicating by myself unnecessarily

    Thanks a lot for your valuable time and help

    My Best regards
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  6. #6
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,145

    Default

    Therefore Map vs List
    But the List is assembled by traversing the Map, keyed by Type so, in this case, the List will have a max of 1 element. Recall that the general router API supports a list, but not every router supports it.

    when is wise use such approach?.
    Whenever you have a router that only supports returning a single result in getChannelIdentifiers(). If the result is a string, you can use this technique in such a router to route to multiple channels.

    I looked at the code and then tested it - it probably should be documented but we need to be careful to not make the documentation too confusing for people who only have simple use cases. Maybe we need an 'advanced techniques' section.

    I am creating the ErrorMessage in my Service Activator not in the Service Object,
    A <service-activator/> invokes (activates) a Service. A <service-activator/> is part of the framework; you don't write <service-activator/>s, you write services that are activated by SI.

    The SI namespace parser generates the service activator, which is the code that invokes your service.

    Your service should throw Exceptions, you generally should not need to extend or reference framework objects.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  7. #7
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,806

    Default

    Hello Gary

    Again thanks a lot for your time

    But the List is assembled by traversing the Map, keyed by Type so, in this case, the List will have a max of 1 element. Recall that the general router API supports a list, but not every router supports it.
    Thanks for the explanation

    Whenever you have a router that only supports returning a single result in getChannelIdentifiers(). If the result is a string, you can use this technique in such a router to route to multiple channels.
    I see a trick

    I looked at the code and then tested it - it probably should be documented but we need to be careful to not make the documentation too confusing for people who only have simple use cases. Maybe we need an 'advanced techniques' section.
    Agree, it could break some basic ideas about the resolution of channels

    A <service-activator/> invokes (activates) a Service. A <service-activator/> is part of the framework;
    Totally agree, but I dont call directly the Service Object from the <service-activator/>, instead, from the <service-activator/> I call a customized Service Activator endpoint (like a @Controller) and from there I call the services

    Perhaps in my previous last reply I did a wrong explanation, sorry for the confussion

    I mean:

    Code:
    <int:service-activator id="itemArticuloServiceActivator01"
    			   input-channel="dvdChannel"
    			   output-channel="final"		
    			   method="serviceActivatorAltern"				   
    			   ref="objectServiceActivator" />
    
    @MessageEndpoint
    public class ObjectServiceActivator {
    
      private SomeServiceBo someServiceBo
    
      @Autowired 
      public void setSomeServiceBo(....)
      ...
      @ServiceActivator
      public ....... methodABC(...){
         ...
         someServiceBo.someMethod(...);
         ...
      }
    ...
    you don't write <service-activator/>s, you write services that are activated by SI.
    I coud be agree, but I prefer caught my possible expected own Exceptions (checked) to create some customized errors if some of them are thrown, something like MyDuplicatePKException, MyEmptyListEmptyException etc

    I hope you see my approach now

    Let me know your suggestions, I think my approach is correct and is practically the same used in MVC with @Controller, and even on Spring Documentation for this section B.5 Annotation Support the follow snippet code is available

    Code:
    @MessageEndpoint
    public class FooService {
    
        @ServiceActivator
        public void processMessage(Message message) {
            ...
        }
    }
    I dont think this class be a Service really, the context would be confused, I think should be FooEndPoint, because the method argument is tightly acopled related with SI

    Best Regards
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  8. #8
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,145

    Default

    You have probably detected that I have a bias towards XML configuration; I will leave it to others to comment further on your use of @MessageEndpoint and @ServiceActivator, but they are intended to replace the <service-activator/> element rather then being referenced by it.

    In essence, your ref= in your <service-activator/> is refering to it as a POJO, not as an @MessageEndpoint. The attributes are intended to be discovered by a <context:component-scan/>; @MessageEndpoint is an @Component (stereotype annotation). This eliminates the need for the XML declaration.

    Regardless, I still believe that it is not necessary for your code (service activator or service) to deal with ErrorMessages or worry about routing. Simply throw an exception and the framework will take care of it.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  9. #9
    Join Date
    Aug 2006
    Location
    Arequipa-Peru / South America
    Posts
    2,806

    Default

    Hello Gary

    You have probably detected that I have a bias towards XML configuration;
    Now yes, but I must know how to work with both approaches

    I will leave it to others to comment further on your use of @MessageEndpoint and @ServiceActivato
    OK, dont worry

    but they are intended to replace the <service-activator/> element rather then being referenced by it.
    Totally Agree, but I am using this approach due if I replace the <service-activator/> I got a confusion when I select the integration-graph tab on STS since this element not appear anymore in the flow integration. I hope you see my point now. Practically I am merging two approaches in one (xml + annotation)

    In essence, your ref= in your <service-activator/> is refering to it as a POJO, not as an @MessageEndpoint. The attributes are intended to be discovered by a <context:component-scan/>; @MessageEndpoint is an @Component (stereotype annotation). This eliminates the need for the XML declaration.
    Agree, but is more easier for me use @MessagePoint + @Autowired to declare this bean instead of the classic <bean declartion + manual injection and again due the previous sentence about the STS graphical support


    And @ServiceActivator is used in case we dont want use the method attribute on the <service-activator/> but is better use this attribute if we have many methods in some POJO and we want set explicitly what method use

    Regardless, I still believe that it is not necessary for your code (service activator or service) to deal with ErrorMessages or worry about routing. Simply throw an exception and the framework will take care of it
    I am confused, what do you mean with the bold part?, If I do that, I can see clearly the error stack trace but the application is broke, since it is not handle it

    Best Regards
    - Manuel Jordan

    Kill Your Pride, Share Your Knowledge With All
    The Fear Of The LORD Is The Beginning Of Knowledge, But Fools Despise Wisdom And Discipline. Proverbs 1:7

    Blog


    Technical Reviewer of Apress

    • Pro SpringSource dm Server
    • Spring Enterprise Recipes: A Problem-Solution Approach
    • Spring Recipes: A Problem-Solution Approach, 2nd Edition
    • Pro Spring Integration
    • Pro Spring Batch
    • Pro Spring 3
    • Pro Spring MVC: With Web Flow
    • Pro Spring Security

  10. #10
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,145

    Default

    That is a limitation of using annotations see https://issuetracker.springsource.com/browse/STS-1617.

    I am confused, what do you mean with the bold part?, If I do that, I can see clearly the error stack trace but the application is broke, since it is not handle it
    Read my earlier replies - the application does not need to create and send ErrorMessages itself. Simply throw the exception and if the inbound endpoint has an error-channel, an ErrorMessage will be sent there.

    Not having an error-channel on an inbound endpoint is like not having a try-catch block in a method; if you don't use one, the exception will be thrown to the caller.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •