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