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