View Javadoc

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