1
2
3
4
5
6
7
8
9
10
11 package org.mule.exception;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.RequestContext;
16 import org.mule.api.MessagingException;
17 import org.mule.api.MuleContext;
18 import org.mule.api.MuleEvent;
19 import org.mule.api.MuleEventContext;
20 import org.mule.api.MuleException;
21 import org.mule.api.MuleMessage;
22 import org.mule.api.config.MuleProperties;
23 import org.mule.api.construct.FlowConstruct;
24 import org.mule.api.endpoint.EndpointURI;
25 import org.mule.api.endpoint.ImmutableEndpoint;
26 import org.mule.api.endpoint.OutboundEndpoint;
27 import org.mule.api.lifecycle.InitialisationException;
28 import org.mule.api.processor.MessageProcessor;
29 import org.mule.api.routing.OutboundRouter;
30 import org.mule.api.service.Service;
31 import org.mule.api.transaction.Transaction;
32 import org.mule.api.transaction.TransactionException;
33 import org.mule.api.transport.DispatchException;
34 import org.mule.api.util.StreamCloserService;
35 import org.mule.config.ExceptionHelper;
36 import org.mule.config.i18n.CoreMessages;
37 import org.mule.context.notification.ExceptionNotification;
38 import org.mule.message.ExceptionMessage;
39 import org.mule.processor.AbstractMessageProcessorOwner;
40 import org.mule.routing.filters.WildcardFilter;
41 import org.mule.routing.outbound.MulticastingRouter;
42 import org.mule.session.DefaultMuleSession;
43 import org.mule.transaction.TransactionCoordination;
44 import org.mule.util.CollectionUtils;
45
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.concurrent.CopyOnWriteArrayList;
49 import java.util.concurrent.atomic.AtomicBoolean;
50
51 import org.apache.commons.logging.Log;
52 import org.apache.commons.logging.LogFactory;
53
54
55
56
57
58
59
60
61 public abstract class AbstractExceptionListener extends AbstractMessageProcessorOwner
62 {
63
64
65
66 protected transient Log logger = LogFactory.getLog(getClass());
67
68 @SuppressWarnings("unchecked")
69 protected List<MessageProcessor> messageProcessors = new CopyOnWriteArrayList();
70
71 protected AtomicBoolean initialised = new AtomicBoolean(false);
72
73 protected WildcardFilter rollbackTxFilter;
74 protected WildcardFilter commitTxFilter;
75
76 protected boolean enableNotifications = true;
77
78 public List<MessageProcessor> getMessageProcessors()
79 {
80 return messageProcessors;
81 }
82
83 public void setMessageProcessors(List<MessageProcessor> processors)
84 {
85 if (processors != null)
86 {
87 this.messageProcessors.clear();
88 this.messageProcessors.addAll(processors);
89 }
90 else
91 {
92 throw new IllegalArgumentException("List of targets = null");
93 }
94 }
95
96 public void addEndpoint(MessageProcessor processor)
97 {
98 if (processor != null)
99 {
100 messageProcessors.add(processor);
101 }
102 }
103
104 public boolean removeMessageProcessor(MessageProcessor processor)
105 {
106 return messageProcessors.remove(processor);
107 }
108
109 protected Throwable getExceptionType(Throwable t, Class exceptionType)
110 {
111 while (t != null)
112 {
113 if (exceptionType.isAssignableFrom(t.getClass()))
114 {
115 return t;
116 }
117
118 t = t.getCause();
119 }
120
121 return null;
122 }
123
124
125
126
127
128
129
130
131
132 public final synchronized void initialise() throws InitialisationException
133 {
134 super.initialise();
135 if (!initialised.get())
136 {
137 doInitialise(muleContext);
138 initialised.set(true);
139 }
140 }
141
142 protected void doInitialise(MuleContext muleContext) throws InitialisationException
143 {
144 logger.info("Initialising exception listener: " + toString());
145 }
146
147
148
149
150
151
152 protected void handleTransaction(Throwable t)
153 {
154 Transaction tx = TransactionCoordination.getInstance().getTransaction();
155
156 if (tx == null)
157 {
158 return;
159 }
160
161 t = ExceptionHelper.getRootException(t);
162
163 if (rollbackTxFilter == null && commitTxFilter == null)
164 {
165
166 rollbackTransaction();
167 }
168 else if (rollbackTxFilter != null && rollbackTxFilter.accept(t.getClass().getName()))
169 {
170
171 rollbackTransaction();
172 }
173 else if (commitTxFilter != null && !commitTxFilter.accept(t.getClass().getName()))
174 {
175
176 rollbackTransaction();
177 }
178 }
179
180 protected void rollbackTransaction()
181 {
182 Transaction tx = TransactionCoordination.getInstance().getTransaction();
183 try
184 {
185 if (tx != null)
186 {
187 tx.setRollbackOnly();
188 }
189 }
190 catch (TransactionException e)
191 {
192 logException(e);
193 }
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 protected void routeException(MuleMessage message, MessageProcessor target, Throwable t)
212 {
213 List endpoints = getMessageProcessors(t);
214 if (CollectionUtils.isNotEmpty(endpoints))
215 {
216 try
217 {
218 logger.error("Message being processed is: " + (message == null ? "null" : message.toString()));
219 MuleEventContext ctx = RequestContext.getEventContext();
220 String component = "Unknown";
221 EndpointURI endpointUri = null;
222 if (ctx != null)
223 {
224 if (ctx.getFlowConstruct() != null)
225 {
226 component = ctx.getFlowConstruct().getName();
227 }
228 endpointUri = ctx.getEndpointURI();
229 }
230 else if (target instanceof ImmutableEndpoint)
231 {
232 endpointUri = ((ImmutableEndpoint)target).getEndpointURI();
233 }
234
235 ExceptionMessage msg = new ExceptionMessage(message.getPayload(), t, component, endpointUri);
236 MuleMessage exceptionMessage;
237 if (ctx == null)
238 {
239 exceptionMessage = new DefaultMuleMessage(msg, muleContext);
240 }
241 else
242 {
243 exceptionMessage = new DefaultMuleMessage(msg, ctx.getMessage(), muleContext);
244 }
245
246 if (ctx != null && ctx.getFlowConstruct() != null && ctx.getFlowConstruct() instanceof Service)
247 {
248 OutboundRouter router = createOutboundRouter();
249 router.process(new DefaultMuleEvent(exceptionMessage, RequestContext.getEvent()));
250 }
251 else
252 {
253
254
255 customRouteExceptionMessage(exceptionMessage);
256 }
257 }
258 catch (Exception e)
259 {
260 logFatal(message, e);
261 closeStream(message);
262 }
263 }
264 else
265 {
266 handleTransaction(t);
267 closeStream(message);
268 }
269 }
270
271 private void customRouteExceptionMessage(MuleMessage exceptionMessage)
272 throws MessagingException, MuleException, DispatchException
273 {
274
275
276
277 int numProcessors = messageProcessors.size();
278 for (int i = 0; i < numProcessors; i++)
279 {
280 MessageProcessor processor = messageProcessors.get(i);
281 if (numProcessors > 1 && ((DefaultMuleMessage) exceptionMessage).isConsumable())
282 {
283 throw new MessagingException(
284 CoreMessages.cannotCopyStreamPayload(exceptionMessage.getPayload().getClass().getName()),
285 exceptionMessage);
286 }
287
288 MuleMessage clonedMessage = new DefaultMuleMessage(exceptionMessage.getPayload(),
289 exceptionMessage, muleContext);
290 MuleEvent exceptionEvent = null;
291 if (processor instanceof OutboundEndpoint)
292 {
293 exceptionEvent = new DefaultMuleEvent(clonedMessage, (OutboundEndpoint) processor,
294 new DefaultMuleSession(muleContext));
295 }
296 else
297 {
298 exceptionEvent = new DefaultMuleEvent(clonedMessage, RequestContext.getEvent().getEndpoint(),
299 new DefaultMuleSession(muleContext));
300 }
301 exceptionEvent = RequestContext.setEvent(exceptionEvent);
302
303 processor.process(exceptionEvent);
304
305 if (logger.isDebugEnabled())
306 {
307 logger.debug("routed Exception message via " + processor);
308 }
309 }
310 }
311
312 protected OutboundRouter createOutboundRouter() throws MuleException
313 {
314
315
316
317
318
319 MulticastingRouter router = new MulticastingRouter()
320 {
321 @Override
322 protected void setMessageProperties(FlowConstruct session,
323 MuleMessage message,
324 MessageProcessor target)
325 {
326
327
328 }
329 };
330 router.setRoutes(new ArrayList<MessageProcessor>(getMessageProcessors()));
331 router.setMuleContext(muleContext);
332 return router;
333 }
334
335 protected void closeStream(MuleMessage message)
336 {
337 if (muleContext == null || muleContext.isDisposing() || muleContext.isDisposed())
338 {
339 return;
340 }
341 if (message != null
342 && muleContext.getRegistry().lookupObject(MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE) != null)
343 {
344 ((StreamCloserService) muleContext.getRegistry().lookupObject(
345 MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE)).closeStream(message.getPayload());
346 }
347 }
348
349
350
351
352
353
354
355
356
357
358
359 protected List<MessageProcessor> getMessageProcessors(Throwable t)
360 {
361 if (!messageProcessors.isEmpty())
362 {
363 return messageProcessors;
364 }
365 else
366 {
367 return null;
368 }
369 }
370
371
372
373
374
375
376 protected void logException(Throwable t)
377 {
378 MuleException muleException = ExceptionHelper.getRootMuleException(t);
379 if (muleException != null)
380 {
381 logger.error(muleException.getDetailedMessage());
382 }
383 else
384 {
385 logger.error("Caught exception in Exception Strategy: " + t.getMessage(), t);
386 }
387 }
388
389
390
391
392
393
394
395
396
397 protected void logFatal(MuleMessage message, Throwable t)
398 {
399 logger.fatal(
400 "Failed to dispatch message to error queue after it failed to process. This may cause message loss."
401 + (message == null ? "" : "Logging Message here: \n" + message.toString()), t);
402 }
403
404 public boolean isInitialised()
405 {
406 return initialised.get();
407 }
408
409
410
411
412
413
414
415
416 protected void fireNotification(ExceptionNotification notification)
417 {
418 if (muleContext != null)
419 {
420 muleContext.fireNotification(notification);
421 }
422 else if (logger.isWarnEnabled())
423 {
424 logger.debug("MuleContext is not yet available for firing notifications, ignoring event: "
425 + notification);
426 }
427 }
428
429 public WildcardFilter getCommitTxFilter()
430 {
431 return commitTxFilter;
432 }
433
434 public void setCommitTxFilter(WildcardFilter commitTxFilter)
435 {
436 this.commitTxFilter = commitTxFilter;
437 }
438
439 public boolean isEnableNotifications()
440 {
441 return enableNotifications;
442 }
443
444 public void setEnableNotifications(boolean enableNotifications)
445 {
446 this.enableNotifications = enableNotifications;
447 }
448
449 public WildcardFilter getRollbackTxFilter()
450 {
451 return rollbackTxFilter;
452 }
453
454 public void setRollbackTxFilter(WildcardFilter rollbackTxFilter)
455 {
456 this.rollbackTxFilter = rollbackTxFilter;
457 }
458
459 @Override
460 protected List<MessageProcessor> getOwnedMessageProcessors()
461 {
462 return messageProcessors;
463 }
464 }