View Javadoc

1   /*
2    * $Id: AbstractSelectiveRouter.java 23006 2011-09-22 05:51:15Z dirk.olmes $
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;
12  
13  import org.mule.api.AnnotatedObject;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleEvent;
16  import org.mule.api.MuleException;
17  import org.mule.api.MuleRuntimeException;
18  import org.mule.api.construct.FlowConstruct;
19  import org.mule.api.construct.FlowConstructAware;
20  import org.mule.api.context.MuleContextAware;
21  import org.mule.api.lifecycle.Disposable;
22  import org.mule.api.lifecycle.Initialisable;
23  import org.mule.api.lifecycle.InitialisationException;
24  import org.mule.api.lifecycle.Lifecycle;
25  import org.mule.api.lifecycle.Startable;
26  import org.mule.api.lifecycle.Stoppable;
27  import org.mule.api.processor.MessageProcessor;
28  import org.mule.api.routing.RoutePathNotFoundException;
29  import org.mule.api.routing.RouterResultsHandler;
30  import org.mule.api.routing.RouterStatisticsRecorder;
31  import org.mule.api.routing.SelectiveRouter;
32  import org.mule.api.routing.filter.Filter;
33  import org.mule.config.i18n.MessageFactory;
34  import org.mule.management.stats.RouterStatistics;
35  
36  import java.util.ArrayList;
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.List;
40  import java.util.Map;
41  import java.util.concurrent.ConcurrentHashMap;
42  import java.util.concurrent.atomic.AtomicBoolean;
43  
44  import javax.xml.namespace.QName;
45  
46  import org.apache.commons.collections.ListUtils;
47  
48  public abstract class AbstractSelectiveRouter
49      implements SelectiveRouter, RouterStatisticsRecorder, Lifecycle, FlowConstructAware, MuleContextAware, AnnotatedObject
50  {
51      private final List<MessageProcessorFilterPair> conditionalMessageProcessors = new ArrayList<MessageProcessorFilterPair>();
52      private MessageProcessor defaultProcessor;
53      private final RouterResultsHandler resultsHandler = new DefaultRouterResultsHandler();
54      private RouterStatistics routerStatistics;
55  
56      final AtomicBoolean initialised = new AtomicBoolean(false);
57      final AtomicBoolean starting = new AtomicBoolean(false);
58      final AtomicBoolean started = new AtomicBoolean(false);
59      private FlowConstruct flowConstruct;
60      private MuleContext muleContext;
61      private final Map<QName, Object> annotations = new ConcurrentHashMap<QName, Object>();
62  
63      public AbstractSelectiveRouter()
64      {
65          routerStatistics = new RouterStatistics(RouterStatistics.TYPE_OUTBOUND);
66      }
67  
68      public void setFlowConstruct(FlowConstruct flowConstruct)
69      {
70          this.flowConstruct = flowConstruct;
71      }
72  
73      public void setMuleContext(MuleContext context)
74      {
75          this.muleContext = context;
76      }
77  
78      public void initialise() throws InitialisationException
79      {
80          synchronized (conditionalMessageProcessors)
81          {
82              for (Object o : getLifecycleManagedObjects())
83              {
84                  if (o instanceof FlowConstructAware)
85                  {
86                      ((FlowConstructAware) o).setFlowConstruct(flowConstruct);
87                  }
88                  if (o instanceof MuleContextAware)
89                  {
90                      ((MuleContextAware) o).setMuleContext(muleContext);
91                  }
92                  if (o instanceof Initialisable)
93                  {
94                      ((Initialisable) o).initialise();
95                  }
96              }
97          }
98          initialised.set(true);
99      }
100 
101     public void start() throws MuleException
102     {
103         synchronized (conditionalMessageProcessors)
104         {
105             starting.set(true);
106             for (Object o : getLifecycleManagedObjects())
107             {
108                 if (o instanceof Startable)
109                 {
110                     ((Startable) o).start();
111                 }
112             }
113 
114             started.set(true);
115             starting.set(false);
116         }
117     }
118 
119     public void stop() throws MuleException
120     {
121         synchronized (conditionalMessageProcessors)
122         {
123             for (Object o : getLifecycleManagedObjects())
124             {
125                 if (o instanceof Stoppable)
126                 {
127                     ((Stoppable) o).stop();
128                 }
129             }
130 
131             started.set(false);
132         }
133     }
134 
135     public void dispose()
136     {
137         synchronized (conditionalMessageProcessors)
138         {
139             for (Object o : getLifecycleManagedObjects())
140             {
141                 if (o instanceof Disposable)
142                 {
143                     ((Disposable) o).dispose();
144                 }
145             }
146         }
147     }
148 
149     public void addRoute(MessageProcessor processor, Filter filter)
150     {
151         synchronized (conditionalMessageProcessors)
152         {
153             MessageProcessorFilterPair addedPair = new MessageProcessorFilterPair(processor, filter);
154             conditionalMessageProcessors.add(transitionLifecycleManagedObjectForAddition(addedPair));
155         }
156     }
157 
158     public void removeRoute(MessageProcessor processor)
159     {
160         updateRoute(processor, new RoutesUpdater()
161         {
162             public void updateAt(int index)
163             {
164                 MessageProcessorFilterPair removedPair = conditionalMessageProcessors.remove(index);
165 
166                 transitionLifecycleManagedObjectForRemoval(removedPair);
167             }
168         });
169     }
170 
171     public void updateRoute(final MessageProcessor processor, final Filter filter)
172     {
173         updateRoute(processor, new RoutesUpdater()
174         {
175             public void updateAt(int index)
176             {
177                 MessageProcessorFilterPair addedPair = new MessageProcessorFilterPair(processor, filter);
178 
179                 MessageProcessorFilterPair removedPair = conditionalMessageProcessors.set(index,
180                     transitionLifecycleManagedObjectForAddition(addedPair));
181 
182                 transitionLifecycleManagedObjectForRemoval(removedPair);
183             }
184         });
185     }
186 
187     public void setDefaultRoute(MessageProcessor processor)
188     {
189         defaultProcessor = processor;
190     }
191 
192     public MuleEvent process(MuleEvent event) throws MuleException
193     {
194         Collection<MessageProcessor> selectedProcessors = selectProcessors(event);
195 
196         if (!selectedProcessors.isEmpty())
197         {
198             return routeWithProcessors(selectedProcessors, event);
199         }
200 
201         if (defaultProcessor != null)
202         {
203             return routeWithProcessor(defaultProcessor, event);
204         }
205 
206         if (getRouterStatistics() != null  && getRouterStatistics().isEnabled())
207         {
208             getRouterStatistics().incrementNoRoutedMessage();
209         }
210 
211         throw new RoutePathNotFoundException(
212             MessageFactory.createStaticMessage("Can't process message because no route has been found matching any filter and no default route is defined"),
213             event, this);
214     }
215 
216     /**
217      * @return the processors selected according to the specific router strategy or
218      *         an empty collection (not null).
219      */
220     protected abstract Collection<MessageProcessor> selectProcessors(MuleEvent event);
221 
222     private Collection<?> getLifecycleManagedObjects()
223     {
224         if (defaultProcessor == null)
225         {
226             return conditionalMessageProcessors;
227         }
228 
229         return ListUtils.union(conditionalMessageProcessors, Collections.singletonList(defaultProcessor));
230     }
231 
232     private <O> O transitionLifecycleManagedObjectForAddition(O managedObject)
233     {
234         try
235         {
236             if ((flowConstruct != null) && (managedObject instanceof FlowConstructAware))
237             {
238                 ((FlowConstructAware) managedObject).setFlowConstruct(flowConstruct);
239             }
240 
241             if ((muleContext != null) && (managedObject instanceof MuleContextAware))
242             {
243                 ((MuleContextAware) managedObject).setMuleContext(muleContext);
244             }
245 
246             if ((initialised.get()) && (managedObject instanceof Initialisable))
247             {
248                 ((Initialisable) managedObject).initialise();
249             }
250 
251             if ((started.get()) && (managedObject instanceof Startable))
252             {
253                 ((Startable) managedObject).start();
254             }
255         }
256         catch (MuleException me)
257         {
258             throw new MuleRuntimeException(me);
259         }
260 
261         return managedObject;
262     }
263 
264     private <O> O transitionLifecycleManagedObjectForRemoval(O managedObject)
265     {
266         try
267         {
268             if (managedObject instanceof Stoppable)
269             {
270                 ((Stoppable) managedObject).stop();
271             }
272 
273             if (managedObject instanceof Disposable)
274             {
275                 ((Disposable) managedObject).dispose();
276             }
277         }
278         catch (MuleException me)
279         {
280             throw new MuleRuntimeException(me);
281         }
282 
283         return managedObject;
284     }
285 
286     private MuleEvent routeWithProcessor(MessageProcessor processor, MuleEvent event) throws MuleException
287     {
288         return routeWithProcessors(Collections.singleton(processor), event);
289     }
290 
291     private MuleEvent routeWithProcessors(Collection<MessageProcessor> processors, MuleEvent event)
292         throws MuleException
293     {
294         List<MuleEvent> results = new ArrayList<MuleEvent>();
295 
296         for (MessageProcessor processor : processors)
297         {
298             processEventWithProcessor(event, processor, results);
299         }
300 
301         return resultsHandler.aggregateResults(results, event, event.getMuleContext());
302     }
303 
304     private void processEventWithProcessor(MuleEvent event,
305                                            MessageProcessor processor,
306                                            List<MuleEvent> results) throws MuleException
307     {
308         results.add(processor.process(event));
309 
310         if (getRouterStatistics() != null && getRouterStatistics().isEnabled())
311         {
312             getRouterStatistics().incrementRoutedMessage(processor);
313         }
314     }
315 
316     public List<MessageProcessorFilterPair> getConditionalMessageProcessors()
317     {
318         return Collections.unmodifiableList(conditionalMessageProcessors);
319     }
320 
321     private interface RoutesUpdater
322     {
323         void updateAt(int index);
324     }
325 
326     private void updateRoute(MessageProcessor processor, RoutesUpdater routesUpdater)
327     {
328         synchronized (conditionalMessageProcessors)
329         {
330             for (int i = 0; i < conditionalMessageProcessors.size(); i++)
331             {
332                 if (conditionalMessageProcessors.get(i).getMessageProcessor().equals(processor))
333                 {
334                     routesUpdater.updateAt(i);
335                 }
336             }
337         }
338     }
339 
340     public RouterStatistics getRouterStatistics()
341     {
342         return routerStatistics;
343     }
344 
345     public void setRouterStatistics(RouterStatistics routerStatistics)
346     {
347         this.routerStatistics = routerStatistics;
348     }
349 
350     public final Object getAnnotation(QName name)
351     {
352         return annotations.get(name);
353     }
354 
355     public final Map<QName, Object> getAnnotations()
356     {
357         return Collections.unmodifiableMap(annotations);
358     }
359 
360     public synchronized final void setAnnotations(Map<QName, Object> newAnnotations)
361     {
362         annotations.clear();
363         annotations.putAll(newAnnotations);
364     }
365 
366     @Override
367     public String toString()
368     {
369         return String.format("%s [flow-construct=%s, started=%s]", getClass().getSimpleName(),
370             flowConstruct != null ? flowConstruct.getName() : null, started);
371     }
372 }