1
2
3
4
5
6
7
8
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
218
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 }