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