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