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