View Javadoc

1   /*
2    * $Id: DefaultInboundRouterCollection.java 12111 2008-06-19 14:38:08Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.inbound;
12  
13  import org.mule.api.MessagingException;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleMessage;
17  import org.mule.api.config.MuleProperties;
18  import org.mule.api.endpoint.ImmutableEndpoint;
19  import org.mule.api.endpoint.InboundEndpoint;
20  import org.mule.api.endpoint.InvalidEndpointTypeException;
21  import org.mule.api.routing.InboundRouter;
22  import org.mule.api.routing.InboundRouterCollection;
23  import org.mule.api.routing.RoutingException;
24  import org.mule.config.i18n.CoreMessages;
25  import org.mule.management.stats.RouterStatistics;
26  import org.mule.routing.AbstractRouterCollection;
27  import org.mule.util.StringMessageUtils;
28  import org.mule.util.StringUtils;
29  
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
34  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
35  import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
36  
37  /**
38   * <code>DefaultInboundRouterCollection</code> is a collection of routers that will be
39   * invoked when an event is received. It is responsible for managing a collection of
40   * routers and also executing the routing logic. Each router must match against the
41   * current event for the event to be routed.
42   */
43  
44  public class DefaultInboundRouterCollection extends AbstractRouterCollection implements InboundRouterCollection
45  {
46      private final List endpoints = new CopyOnWriteArrayList();
47  
48      public DefaultInboundRouterCollection()
49      {
50          super(RouterStatistics.TYPE_INBOUND);
51          //default for inbound routing
52          setMatchAll(true);
53      }
54  
55      public MuleMessage route(MuleEvent event) throws MessagingException
56      {
57          // If the endpoint has a logical name, use it, otherwise use the URI.
58          String inboundEndpoint = 
59              // Endpoint identifier (deprecated)
60              event.getEndpoint().getEndpointURI().getEndpointName();
61  
62          if (StringUtils.isBlank(inboundEndpoint))
63          {
64              // Global endpoint
65              inboundEndpoint = event.getEndpoint().getName();
66          }
67          if (StringUtils.isBlank(inboundEndpoint))
68          {
69              // URI
70              inboundEndpoint = event.getEndpoint().getEndpointURI().getUri().toString();
71          }
72          event.getMessage().setProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY, inboundEndpoint);
73  
74          if (endpoints.size() > 0 && routers.size() == 0)
75          {
76              addRouter(new InboundPassThroughRouter());
77          }
78  
79          String componentName = event.getSession().getService().getName();
80  
81          ConcurrentMap eventsToRoute = new ConcurrentHashMap(2);
82          boolean noRoute = true;
83          boolean match = false;
84          InboundRouter umoInboundRouter;
85          MuleEvent lastEvent= null;
86  
87          for (Iterator iterator = getRouters().iterator(); iterator.hasNext();)
88          {
89              umoInboundRouter = (InboundRouter) iterator.next();
90  
91              if (umoInboundRouter.isMatch(event))
92              {
93                  match = true;
94                  MuleEvent[] events = umoInboundRouter.process(event);
95                  if(events!=null)
96                  {
97                      for (int i = 0; i < events.length; i++)
98                      {
99                          lastEvent = events[i];
100                         //Only add the event if it's a new event
101                         eventsToRoute.putIfAbsent(lastEvent.getId(), lastEvent);
102                     }
103                 }
104 
105                 noRoute = (events == null);
106                 if (!isMatchAll())
107                 {
108                     break;
109                 }
110             }
111         }
112 
113         // If the stopFurtherProcessing flag has been set
114         // do not route events to the service.
115         // This is the case when using a ForwardingConsumer
116         // inbound router for example.
117         if (!event.isStopFurtherProcessing())
118         {
119             if (noRoute)
120             {
121                 // Update stats
122                 if (getStatistics().isEnabled())
123                 {
124                     getStatistics().incrementNoRoutedMessage();
125                 }
126                 if (!match)
127                 {
128                     if (getCatchAllStrategy() != null)
129                     {
130                         if (logger.isDebugEnabled())
131                         {
132                             logger.debug("Message did not match any routers on: " + componentName
133                                          + " - invoking catch all strategy");
134                         }
135                         if (getStatistics().isEnabled())
136                         {
137                             getStatistics().incrementCaughtMessage();
138                         }
139                         return getCatchAllStrategy().catchMessage(event.getMessage(), event.getSession(),
140                             event.isSynchronous());
141 
142                     }
143                     else
144                     {
145                         logger.warn("Message did not match any routers on: "
146                                     + componentName
147                                     + " and there is no catch all strategy configured on this router.  Disposing message: " + event);
148                         if (logger.isDebugEnabled())
149                         {
150                             try
151                             {
152                                 logger.warn("Message fragment is: "
153                                             + StringMessageUtils.truncate(event.getMessageAsString(), 100,
154                                                 true));
155                             }
156                             catch (MuleException e)
157                             {
158                                 // ignore
159                             }
160                         }
161                     }
162                 }
163             }
164             else
165             {
166                 try
167                 {
168                     MuleMessage messageResult = null;
169                     for (Iterator iterator = eventsToRoute.values().iterator(); iterator.hasNext();)
170                     {
171                         MuleEvent eventToRoute = (MuleEvent) iterator.next();
172 
173                         // Set the originating endpoint so we'll know where this event came from further down the pipeline.
174                         if (event.getMessage().getProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY) == null)
175                         {
176                             event.getMessage().setProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY, inboundEndpoint);
177                         }
178 
179                         if (event.isSynchronous())
180                         {
181                             messageResult = send(eventToRoute);
182                         }
183                         else
184                         {
185                             dispatch(eventToRoute);
186                         }
187                         // Update stats
188                         if (getStatistics().isEnabled())
189                         {
190                             getStatistics().incrementRoutedMessage(eventToRoute.getEndpoint());
191                         }
192                     }
193                     return messageResult;
194                 }
195                 catch (MuleException e)
196                 {
197                     throw new RoutingException(event.getMessage(), event.getEndpoint(), e);
198                 }
199             }
200         }
201         if(event.isSynchronous())
202         {
203             //This is required if the Router short-circuits the service and diverts processing elsewhere
204             //The only example of this right now is the FowardingConsumer (<forwarding-router/>)
205             return (lastEvent == null ? null : lastEvent.getMessage());
206         }
207         else
208         {
209             return null;
210         }
211 
212     }
213 
214     public void dispatch(MuleEvent event) throws MuleException
215     {
216         event.getSession().dispatchEvent(event);
217     }
218 
219     public MuleMessage send(MuleEvent event) throws MuleException
220     {
221         return event.getSession().sendEvent(event);
222     }
223 
224     public void addRouter(InboundRouter router)
225     {
226         routers.add(router);
227     }
228 
229     public InboundRouter removeRouter(InboundRouter router)
230     {
231         if (routers.remove(router))
232         {
233             return router;
234         }
235         else
236         {
237             return null;
238         }
239     }
240 
241     public void addEndpoint(InboundEndpoint endpoint)
242     {
243         endpoints.add(endpoint);
244     }
245 
246     public boolean removeEndpoint(InboundEndpoint endpoint)
247     {
248         return endpoints.remove(endpoint);
249     }
250 
251     public List getEndpoints()
252     {
253         return endpoints;
254     }
255 
256     public void setEndpoints(List endpoints)
257     {
258         if (endpoints != null)
259         {
260             this.endpoints.clear();
261             // Ensure all endpoints are inbound endpoints
262             // This will go when we start dropping support for 1.4 and start using 1.5
263             for (Iterator it = endpoints.iterator(); it.hasNext();)
264             {
265                 ImmutableEndpoint endpoint = (ImmutableEndpoint) it.next();
266                 if (!(endpoint instanceof InboundEndpoint))
267                 {
268                     throw new InvalidEndpointTypeException(CoreMessages.inboundRouterMustUseInboundEndpoints(this,
269                         endpoint));
270                 }
271             }
272             this.endpoints.addAll(endpoints);
273         }
274         else
275         {
276             throw new IllegalArgumentException("List of endpoints = null");
277         }
278     }
279 
280     /**
281      * @param name the Endpoint identifier
282      * @return the Endpoint or null if the endpointUri is not registered
283      * @see org.mule.api.routing.InboundRouterCollection
284      */
285     public InboundEndpoint getEndpoint(String name)
286     {
287         InboundEndpoint endpointDescriptor;
288         for (Iterator iterator = endpoints.iterator(); iterator.hasNext();)
289         {
290             endpointDescriptor = (InboundEndpoint) iterator.next();
291             if (endpointDescriptor.getName().equals(name))
292             {
293                 return endpointDescriptor;
294             }
295         }
296         return null;
297     }
298 }