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.outbound;
8   
9   import org.mule.DefaultMuleMessage;
10  import org.mule.api.MessagingException;
11  import org.mule.api.MuleContext;
12  import org.mule.api.MuleEvent;
13  import org.mule.api.MuleMessage;
14  import org.mule.api.MuleSession;
15  import org.mule.api.lifecycle.Disposable;
16  import org.mule.api.lifecycle.Initialisable;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.routing.MatchableMessageProcessor;
19  import org.mule.api.routing.OutboundRouter;
20  import org.mule.api.routing.OutboundRouterCatchAllStrategy;
21  import org.mule.api.routing.OutboundRouterCollection;
22  import org.mule.api.routing.RouterStatisticsRecorder;
23  import org.mule.api.routing.RoutingException;
24  import org.mule.api.routing.TransformingMatchable;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.management.stats.RouterStatistics;
27  import org.mule.routing.AbstractCatchAllStrategy;
28  import org.mule.util.ObjectUtils;
29  
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /**
39   * <code>DefaultOutboundRouterCollection</code> is a container of routers. An
40   * DefaultOutboundRouterCollection must have atleast one router. By default the first
41   * matching router is used to route an event though it is possible to match on all
42   * routers meaning that the message will get sent over all matching routers.
43   */
44  
45  public class DefaultOutboundRouterCollection implements OutboundRouterCollection
46  {
47  
48      /**
49       * logger used by this class
50       */
51      protected final transient Log logger = LogFactory.getLog(getClass());
52  
53      @SuppressWarnings("unchecked")
54      protected List<MatchableMessageProcessor> routers = new CopyOnWriteArrayList();
55      protected boolean matchAll = false;
56      private OutboundRouterCatchAllStrategy catchAllStrategy;
57  
58      protected RouterStatistics statistics = new RouterStatistics(RouterStatistics.TYPE_OUTBOUND);
59      protected MuleContext muleContext;
60  
61      public MuleEvent process(final MuleEvent event) throws MessagingException
62      {
63          MuleMessage message = event.getMessage();
64          MuleSession session = event.getSession();
65          MuleEvent result;
66          boolean matchfound = false;
67  
68          for (Iterator<MatchableMessageProcessor> iterator = getRoutes().iterator(); iterator.hasNext();)
69          {
70              OutboundRouter outboundRouter = (OutboundRouter) iterator.next();
71  
72              final MuleMessage outboundRouterMessage;
73              // Create copy of message for router 1..n-1 if matchAll="true" or if
74              // routers require copy because it may mutate payload before match is
75              // chosen
76              if (iterator.hasNext()
77                  && (isMatchAll() || ((outboundRouter instanceof TransformingMatchable) && ((TransformingMatchable) outboundRouter).isTransformBeforeMatch())))
78              {
79                  if (((DefaultMuleMessage) message).isConsumable())
80                  {
81                      throw new MessagingException(CoreMessages.cannotCopyStreamPayload(message.getPayload()
82                          .getClass()
83                          .getName()), event);
84                  }
85                  outboundRouterMessage = new DefaultMuleMessage(message.getPayload(), message, muleContext);
86              }
87              else
88              {
89                  outboundRouterMessage = message;
90              }
91  
92              try
93              {
94                  if (outboundRouter.isMatch(outboundRouterMessage))
95                  {
96                      matchfound = true;
97                      // Manage outbound only transactions here
98                      final OutboundRouter router = outboundRouter;
99      
100                     result = router.process(event);
101     
102                     if (!isMatchAll())
103                     {
104                         return result;
105                     }
106                 }
107             }
108             catch (MessagingException e)
109             {
110                 throw e;
111             }
112             catch (Exception e)
113             {
114                 throw new RoutingException(event, outboundRouter, e);
115             }
116         }
117 
118         if (!matchfound && getCatchAllStrategy() != null)
119         {
120             if (logger.isDebugEnabled())
121             {
122                 logger.debug("Message did not match any routers on: " + session.getFlowConstruct().getName()
123                              + " invoking catch all strategy");
124             }
125             return catchAll(event);
126         }
127         else if (!matchfound)
128         {
129             logger.warn("Message did not match any routers on: "
130                         + session.getFlowConstruct().getName()
131                         + " and there is no catch all strategy configured on this router.  Disposing message "
132                         + message);
133         }
134         return event;
135     }
136 
137     protected MuleEvent catchAll(MuleEvent event) throws RoutingException
138     {
139         if (getRouterStatistics().isEnabled())
140         {
141             getRouterStatistics().incrementCaughtMessage();
142         }
143 
144         return getCatchAllStrategy().process(event);
145     }
146 
147     public void initialise() throws InitialisationException
148     {
149         for (MatchableMessageProcessor router : routers)
150         {
151             if (router instanceof Initialisable)
152             {
153                 ((Initialisable) router).initialise();
154             }
155         }
156     }
157 
158     public void dispose()
159     {
160         for (MatchableMessageProcessor router : routers)
161         {
162             if (router instanceof Disposable)
163             {
164                 ((Disposable) router).dispose();
165             }
166         }
167     }
168     
169     // TODO Use spring factory bean
170     @Deprecated
171     public void setMessageProcessors(List<MatchableMessageProcessor> routers)
172     {
173         for (MatchableMessageProcessor router : routers)
174         {
175             addRoute(router);
176         }
177     }
178     
179     public void addRoute(MatchableMessageProcessor router)
180     {
181         if (router instanceof RouterStatisticsRecorder)
182         {
183             ((RouterStatisticsRecorder) router).setRouterStatistics(getRouterStatistics());
184         }
185         routers.add(router);
186     }
187 
188     public void removeRoute(MatchableMessageProcessor router)
189     {
190         routers.remove(router);
191     }
192 
193     public List<MatchableMessageProcessor> getRoutes()
194     {
195         return routers;
196     }
197 
198     public OutboundRouterCatchAllStrategy getCatchAllStrategy()
199     {
200         return catchAllStrategy;
201     }
202 
203     public void setCatchAllStrategy(OutboundRouterCatchAllStrategy catchAllStrategy)
204     {
205         this.catchAllStrategy = catchAllStrategy;
206         if (this.catchAllStrategy != null && catchAllStrategy instanceof AbstractCatchAllStrategy)
207         {
208             ((AbstractCatchAllStrategy) this.catchAllStrategy).setRouterStatistics(statistics);
209         }
210     }
211 
212     public boolean isMatchAll()
213     {
214         return matchAll;
215     }
216 
217     public void setMatchAll(boolean matchAll)
218     {
219         this.matchAll = matchAll;
220     }
221 
222     public RouterStatistics getRouterStatistics()
223     {
224         return statistics;
225     }
226 
227     public void setRouterStatistics(RouterStatistics stat)
228     {
229         this.statistics = stat;
230     }
231 
232     public void setMuleContext(MuleContext context)
233     {
234         this.muleContext = context;
235     }
236 
237     public boolean hasEndpoints()
238     {
239         for (Iterator iterator = routers.iterator(); iterator.hasNext();)
240         {
241             OutboundRouter router = (OutboundRouter) iterator.next();
242             if (router.getRoutes().size() > 0 || router.isDynamicRoutes())
243             {
244                 return true;
245             }
246         }
247         return false;
248     }
249 
250     @Override
251     public String toString()
252     {
253         return ObjectUtils.toString(this);
254     }
255 }