View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.routing;
8   
9   import org.mule.api.MessagingException;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleException;
12  import org.mule.api.MuleMessage;
13  import org.mule.api.config.MuleProperties;
14  import org.mule.api.lifecycle.InitialisationException;
15  import org.mule.api.processor.MessageProcessor;
16  import org.mule.api.routing.CouldNotRouteOutboundMessageException;
17  import org.mule.api.transport.PropertyScope;
18  import org.mule.routing.filters.ExpressionFilter;
19  import org.mule.routing.outbound.AbstractOutboundRouter;
20  
21  /**
22   * FirstSuccessful routes an event to the first target route that can accept it
23   * without throwing or returning an exception. If no such route can be found, an
24   * exception is thrown. Note that this works more reliable with synchronous targets,
25   * but no such restriction is imposed.
26   */
27  public class FirstSuccessful extends AbstractOutboundRouter
28  {
29  
30      protected String failureExpression;
31      protected ExpressionFilter failureExpressionFilter;
32  
33      @Override
34      public void initialise() throws InitialisationException
35      {
36          super.initialise();
37          if (failureExpression != null)
38          {
39              failureExpressionFilter = new ExpressionFilter(failureExpression);
40          }
41          else
42          {
43              failureExpressionFilter = new ExpressionFilter("exception-type:");
44          }
45          failureExpressionFilter.setMuleContext(muleContext);
46      }
47  
48      /**
49       * Route the given event to one of our targets
50       */
51      @Override
52      public MuleEvent route(MuleEvent event) throws MessagingException
53      {
54          MuleEvent returnEvent = null;
55  
56          boolean failed = true;
57          Exception failExceptionCause = null;
58          for (MessageProcessor mp : routes)
59          {
60              try
61              {
62                  MuleEvent toProcess = cloneEventForRouting(event, mp);
63                  returnEvent = mp.process(toProcess);
64  
65                  if (returnEvent == null)
66                  {
67                      failed = false;
68                  }
69                  else
70                  {
71                      MuleMessage msg = returnEvent.getMessage();
72                      failed = msg == null || failureExpressionFilter.accept(msg);
73                  }
74              }
75              catch (Exception ex)
76              {
77                  failed = true;
78                  failExceptionCause = ex;
79              }
80              if (!failed)
81              {
82                  break;
83              }
84          }
85  
86          if (failed)
87          {
88              if (failExceptionCause != null)
89              {
90                  throw new CouldNotRouteOutboundMessageException(event, this, failExceptionCause);
91              }
92              else
93              {
94                  throw new CouldNotRouteOutboundMessageException(event, this);
95              }
96          }
97  
98          return returnEvent;
99      }
100 
101     protected MuleEvent cloneEventForRouting(MuleEvent event, MessageProcessor mp) throws MessagingException
102     {
103         MuleMessage clonedMessage = cloneMessage(event, event.getMessage());
104         MuleEvent toProcess = createEventToRoute(event, clonedMessage, mp);
105 
106         // force processing the event to route in the same thread so that we can catch exceptions
107         // that may happen during processing here and try sending to the next endpoint.
108         clonedMessage.setProperty(MuleProperties.MULE_FORCE_SYNC_PROPERTY, Boolean.TRUE, PropertyScope.INBOUND);
109 
110         return toProcess;
111     }
112 
113     public boolean isMatch(MuleMessage message) throws MuleException
114     {
115         return true;
116     }
117 
118     /**
119      * Specifies an expression that when evaluated as determines if the processing of
120      * one a route was a failure or not.
121      *
122      * @param failureExpression
123      * @see ExpressionFilter
124      */
125     public void setFailureExpression(String failureExpression)
126     {
127         this.failureExpression = failureExpression;
128     }
129 }