1
2
3
4
5
6
7 package org.mule.exception;
8
9 import org.mule.DefaultMuleEvent;
10 import org.mule.DefaultMuleMessage;
11 import org.mule.api.MuleContext;
12 import org.mule.api.MuleEvent;
13 import org.mule.api.MuleException;
14 import org.mule.api.MuleMessage;
15 import org.mule.api.config.MuleProperties;
16 import org.mule.api.construct.FlowConstruct;
17 import org.mule.api.endpoint.EndpointURI;
18 import org.mule.api.lifecycle.InitialisationException;
19 import org.mule.api.processor.MessageProcessor;
20 import org.mule.api.transaction.Transaction;
21 import org.mule.api.transaction.TransactionException;
22 import org.mule.api.util.StreamCloserService;
23 import org.mule.config.ExceptionHelper;
24 import org.mule.context.notification.ExceptionNotification;
25 import org.mule.message.ExceptionMessage;
26 import org.mule.processor.AbstractMessageProcessorOwner;
27 import org.mule.routing.filters.WildcardFilter;
28 import org.mule.routing.outbound.MulticastingRouter;
29 import org.mule.transaction.TransactionCoordination;
30
31 import java.util.List;
32 import java.util.concurrent.CopyOnWriteArrayList;
33 import java.util.concurrent.atomic.AtomicBoolean;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38
39
40
41
42
43
44
45 public abstract class AbstractExceptionListener extends AbstractMessageProcessorOwner
46 {
47
48
49
50 protected transient Log logger = LogFactory.getLog(getClass());
51
52 @SuppressWarnings("unchecked")
53 protected List<MessageProcessor> messageProcessors = new CopyOnWriteArrayList();
54
55 protected AtomicBoolean initialised = new AtomicBoolean(false);
56
57 protected WildcardFilter rollbackTxFilter;
58 protected WildcardFilter commitTxFilter;
59
60 protected boolean enableNotifications = true;
61
62 public List<MessageProcessor> getMessageProcessors()
63 {
64 return messageProcessors;
65 }
66
67 public void setMessageProcessors(List<MessageProcessor> processors)
68 {
69 if (processors != null)
70 {
71 this.messageProcessors.clear();
72 this.messageProcessors.addAll(processors);
73 }
74 else
75 {
76 throw new IllegalArgumentException("List of targets = null");
77 }
78 }
79
80 public void addEndpoint(MessageProcessor processor)
81 {
82 if (processor != null)
83 {
84 messageProcessors.add(processor);
85 }
86 }
87
88 public boolean removeMessageProcessor(MessageProcessor processor)
89 {
90 return messageProcessors.remove(processor);
91 }
92
93 protected Throwable getExceptionType(Throwable t, Class exceptionType)
94 {
95 while (t != null)
96 {
97 if (exceptionType.isAssignableFrom(t.getClass()))
98 {
99 return t;
100 }
101
102 t = t.getCause();
103 }
104
105 return null;
106 }
107
108
109
110
111
112
113
114
115
116 public final synchronized void initialise() throws InitialisationException
117 {
118 super.initialise();
119 if (!initialised.get())
120 {
121 doInitialise(muleContext);
122 initialised.set(true);
123 }
124 }
125
126 protected void doInitialise(MuleContext muleContext) throws InitialisationException
127 {
128 logger.info("Initialising exception listener: " + toString());
129 }
130
131
132
133
134
135
136 protected void handleTransaction(Throwable t)
137 {
138 Transaction tx = TransactionCoordination.getInstance().getTransaction();
139
140 if (tx == null)
141 {
142 return;
143 }
144
145 t = ExceptionHelper.getRootException(t);
146
147 if (rollbackTxFilter == null && commitTxFilter == null)
148 {
149
150 rollbackTransaction();
151 }
152 else if (rollbackTxFilter != null && rollbackTxFilter.accept(t.getClass().getName()))
153 {
154
155 rollbackTransaction();
156 }
157 else if (commitTxFilter != null && !commitTxFilter.accept(t.getClass().getName()))
158 {
159
160 rollbackTransaction();
161 }
162 }
163
164 protected boolean isRollback(Throwable t)
165 {
166
167 t = ExceptionHelper.getRootException(t);
168 if (rollbackTxFilter == null && commitTxFilter == null)
169 {
170 return true;
171 }
172 else
173 {
174 return (rollbackTxFilter != null && rollbackTxFilter.accept(t.getClass().getName()))
175 || (commitTxFilter != null && !commitTxFilter.accept(t.getClass().getName()));
176 }
177 }
178
179 protected void rollbackTransaction()
180 {
181 Transaction tx = TransactionCoordination.getInstance().getTransaction();
182 try
183 {
184 if (tx != null)
185 {
186 tx.rollback();
187 }
188 }
189 catch (TransactionException e)
190 {
191 logException(e);
192 }
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210 protected void routeException(MuleEvent event, MessageProcessor target, Throwable t)
211 {
212 if (!messageProcessors.isEmpty())
213 {
214 try
215 {
216 logger.error("Message being processed is: " + (event.getMessage().getPayloadForLogging()));
217 String component = "Unknown";
218 if (event.getFlowConstruct() != null)
219 {
220 component = event.getFlowConstruct().getName();
221 }
222 EndpointURI endpointUri = event.getEndpoint().getEndpointURI();
223
224
225 ExceptionMessage msg = new ExceptionMessage(event, t, component, endpointUri);
226 MuleMessage exceptionMessage = new DefaultMuleMessage(msg, event.getMessage(), muleContext);
227
228
229 MulticastingRouter router = new MulticastingRouter()
230 {
231 @Override
232 protected void setMessageProperties(FlowConstruct session, MuleMessage message, MessageProcessor target)
233 {
234
235 }
236 };
237 router.setRoutes(getMessageProcessors());
238 router.setMuleContext(muleContext);
239
240
241 router.process(new DefaultMuleEvent(exceptionMessage, event));
242 }
243 catch (Exception e)
244 {
245 logFatal(event, e);
246 }
247 }
248 }
249
250 protected void closeStream(MuleMessage message)
251 {
252 if (muleContext == null || muleContext.isDisposing() || muleContext.isDisposed())
253 {
254 return;
255 }
256 if (message != null
257 && muleContext.getRegistry().lookupObject(MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE) != null)
258 {
259 ((StreamCloserService) muleContext.getRegistry().lookupObject(
260 MuleProperties.OBJECT_MULE_STREAM_CLOSER_SERVICE)).closeStream(message.getPayload());
261 }
262 }
263
264
265
266
267
268
269 protected void logException(Throwable t)
270 {
271 MuleException muleException = ExceptionHelper.getRootMuleException(t);
272 if (muleException != null)
273 {
274 logger.error(muleException.getDetailedMessage());
275 }
276 else
277 {
278 logger.error("Caught exception in Exception Strategy: " + t.getMessage(), t);
279 }
280 }
281
282
283
284
285
286
287
288
289
290 protected void logFatal(MuleEvent event, Throwable t)
291 {
292 logger.fatal(
293 "Failed to dispatch message to error queue after it failed to process. This may cause message loss."
294 + (event.getMessage() == null ? "" : "Logging Message here: \n" + event.getMessage().toString()), t);
295 }
296
297 public boolean isInitialised()
298 {
299 return initialised.get();
300 }
301
302
303
304
305
306
307
308
309 protected void fireNotification(ExceptionNotification notification)
310 {
311 if (muleContext != null)
312 {
313 muleContext.fireNotification(notification);
314 }
315 else if (logger.isWarnEnabled())
316 {
317 logger.debug("MuleContext is not yet available for firing notifications, ignoring event: "
318 + notification);
319 }
320 }
321
322 public WildcardFilter getCommitTxFilter()
323 {
324 return commitTxFilter;
325 }
326
327 public void setCommitTxFilter(WildcardFilter commitTxFilter)
328 {
329 this.commitTxFilter = commitTxFilter;
330 }
331
332 public boolean isEnableNotifications()
333 {
334 return enableNotifications;
335 }
336
337 public void setEnableNotifications(boolean enableNotifications)
338 {
339 this.enableNotifications = enableNotifications;
340 }
341
342 public WildcardFilter getRollbackTxFilter()
343 {
344 return rollbackTxFilter;
345 }
346
347 public void setRollbackTxFilter(WildcardFilter rollbackTxFilter)
348 {
349 this.rollbackTxFilter = rollbackTxFilter;
350 }
351
352 @Override
353 protected List<MessageProcessor> getOwnedMessageProcessors()
354 {
355 return messageProcessors;
356 }
357 }