KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mule > impl > AbstractExceptionListener


1 /*
2  * $Id: AbstractExceptionListener.java 3798 2006-11-04 04:07:14Z aperepel $
3  * --------------------------------------------------------------------------------------
4  * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
5  *
6  * The software in this package is published under the terms of the MuleSource MPL
7  * license, a copy of which has been included with this distribution in the
8  * LICENSE.txt file.
9  */

10
11 package org.mule.impl;
12
13 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
14 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17 import org.mule.config.ExceptionHelper;
18 import org.mule.impl.message.ExceptionMessage;
19 import org.mule.transaction.TransactionCoordination;
20 import org.mule.umo.MessagingException;
21 import org.mule.umo.TransactionException;
22 import org.mule.umo.UMOEvent;
23 import org.mule.umo.UMOEventContext;
24 import org.mule.umo.UMOException;
25 import org.mule.umo.UMOMessage;
26 import org.mule.umo.UMOTransaction;
27 import org.mule.umo.endpoint.UMOEndpoint;
28 import org.mule.umo.endpoint.UMOEndpointURI;
29 import org.mule.umo.endpoint.UMOImmutableEndpoint;
30 import org.mule.umo.lifecycle.Initialisable;
31 import org.mule.umo.lifecycle.InitialisationException;
32 import org.mule.umo.lifecycle.LifecycleException;
33 import org.mule.umo.routing.RoutingException;
34 import org.mule.providers.NullPayload;
35
36 import java.beans.ExceptionListener JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.List JavaDoc;
39
40 /**
41  * <code>AbstractExceptionListener</code> is a base implementation that custom
42  * Exception Listeners can override. It provides template methods for handling the
43  * for base types of exceptions plus allows multimple endpoints to be associated with
44  * this exception listener and provides an implementaiton for dispatching exception
45  * events from this Listener.
46  *
47  * @author <a HREF="mailto:ross.mason@symphonysoft.com">Ross Mason</a>
48  * @version $Revision: 3798 $
49  */

50 public abstract class AbstractExceptionListener implements ExceptionListener JavaDoc, Initialisable
51 {
52     /**
53      * logger used by this class
54      */

55     protected transient Log logger = LogFactory.getLog(getClass());
56
57     protected List endpoints = new CopyOnWriteArrayList();
58
59     protected AtomicBoolean initialised = new AtomicBoolean(false);
60
61     public List getEndpoints()
62     {
63         return endpoints;
64     }
65
66     public void setEndpoints(List endpoints)
67     {
68         for (Iterator JavaDoc iterator = endpoints.iterator(); iterator.hasNext();)
69         {
70             addEndpoint((UMOEndpoint)iterator.next());
71         }
72     }
73
74     public void addEndpoint(UMOEndpoint endpoint)
75     {
76         if (endpoint != null)
77         {
78             endpoint.setType(UMOEndpoint.ENDPOINT_TYPE_SENDER);
79             endpoints.add(endpoint);
80         }
81     }
82
83     public boolean removeEndpoint(UMOEndpoint endpoint)
84     {
85         return endpoints.remove(endpoint);
86     }
87
88     public void exceptionThrown(Exception JavaDoc e)
89     {
90         Throwable JavaDoc t = getExceptionType(e, RoutingException.class);
91         if (t != null)
92         {
93             RoutingException re = (RoutingException)t;
94             handleRoutingException(re.getUmoMessage(), re.getEndpoint(), e);
95             return;
96         }
97
98         t = getExceptionType(e, MessagingException.class);
99         if (t != null)
100         {
101             MessagingException me = (MessagingException)t;
102             handleMessagingException(me.getUmoMessage(), e);
103             return;
104         }
105
106         t = getExceptionType(e, LifecycleException.class);
107         if (t != null)
108         {
109             LifecycleException le = (LifecycleException)t;
110             handleLifecycleException(le.getComponent(), e);
111             if (RequestContext.getEventContext() != null)
112             {
113                 handleMessagingException(RequestContext.getEventContext().getMessage(), e);
114             }
115             else
116             {
117                 logger.info("There is no current event available, routing Null message with the exception");
118                 handleMessagingException(new MuleMessage(new NullPayload()), e);
119             }
120             return;
121         }
122
123         handleStandardException(e);
124     }
125
126     protected Throwable JavaDoc getExceptionType(Exception JavaDoc e, Class JavaDoc exceptionType)
127     {
128         Throwable JavaDoc current = e;
129         while (current != null)
130         {
131             if (exceptionType.isAssignableFrom(e.getClass()))
132             {
133                 return current;
134             }
135             current = current.getCause();
136         }
137         return null;
138     }
139
140     /**
141      * The initialise method is call every time the Exception stategy is assigned to
142      * a component or connector. This implementation ensures that initialise is
143      * called only once. The actual initialisation code is contained in the
144      * <code>doInitialise()</code> method.
145      *
146      * @throws InitialisationException
147      */

148     public synchronized final void initialise() throws InitialisationException
149     {
150         if (!initialised.get())
151         {
152             doInitialise();
153             initialised.set(true);
154         }
155     }
156
157     protected void doInitialise() throws InitialisationException
158     {
159         logger.info("Initialising exception listener: " + toString());
160         for (Iterator JavaDoc iterator = endpoints.iterator(); iterator.hasNext();)
161         {
162             UMOEndpoint umoEndpoint = (UMOEndpoint)iterator.next();
163             umoEndpoint.initialise();
164         }
165     }
166
167     /**
168      * If there is a current transaction this method will mark it for rollback This
169      * method should not be called if an event is routed from this exception handler
170      * to an endpoint that should take part in the current transaction
171      */

172     protected void markTransactionForRollback()
173     {
174         UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
175         try
176         {
177             if (tx != null)
178             {
179                 tx.setRollbackOnly();
180             }
181         }
182         catch (TransactionException e)
183         {
184             logException(e);
185         }
186     }
187
188     /**
189      * Routes the current exception to an error endpoint such as a Dead Letter Queue
190      * (jms) This method is only invoked if there is a UMOMessage available to
191      * dispatch. The message dispatched from this method will be an
192      * <code>ExceptionMessage</code> which contains the exception thrown the
193      * UMOMessage and any context information.
194      *
195      * @param message the UMOMessage being processed when the exception occurred
196      * @param failedEndpoint optional; the endpoint being dispatched or received on
197      * when the error occurred. This is NOT the endpoint that the message
198      * will be disptched on and is only supplied to this method for
199      * logging purposes
200      * @param t the exception thrown. This will be sent with the ExceptionMessage
201      * @see ExceptionMessage
202      */

203     protected void routeException(UMOMessage message, UMOImmutableEndpoint failedEndpoint, Throwable JavaDoc t)
204     {
205         UMOEndpoint endpoint = getEndpoint(t);
206         if (endpoint != null)
207         {
208             try
209             {
210                 logger.error("Message being processed is: " + (message == null ? "null" : message.toString()));
211                 UMOEventContext ctx = RequestContext.getEventContext();
212                 String JavaDoc component = "Unknown";
213                 UMOEndpointURI endpointUri = null;
214                 if (ctx != null)
215                 {
216                     if (ctx.getComponentDescriptor() != null)
217                     {
218                         component = ctx.getComponentDescriptor().getName();
219                     }
220                     endpointUri = ctx.getEndpointURI();
221                 }
222                 else if (failedEndpoint != null)
223                 {
224                     endpointUri = failedEndpoint.getEndpointURI();
225                 }
226                 ExceptionMessage msg;
227                 msg = new ExceptionMessage(getErrorMessagePayload(message), t, component, endpointUri);
228
229                 UMOMessage exceptionMessage;
230                 if (ctx == null)
231                 {
232                     exceptionMessage = new MuleMessage(msg);
233                 }
234                 else
235                 {
236                     exceptionMessage = new MuleMessage(msg, ctx.getMessage());
237                 }
238                 UMOEvent exceptionEvent = new MuleEvent(exceptionMessage, endpoint, new MuleSession(
239                     exceptionMessage, new MuleSessionHandler()), true);
240                 RequestContext.setEvent(exceptionEvent);
241                 endpoint.getConnector().getDispatcher(endpoint).send(exceptionEvent);
242
243                 if (logger.isDebugEnabled())
244                 {
245                     logger.debug("routed Exception message via " + endpoint);
246                 }
247
248             }
249             catch (UMOException e)
250             {
251                 logFatal(message, e);
252             }
253         }
254         else
255         {
256             markTransactionForRollback();
257         }
258     }
259
260     protected Object JavaDoc getErrorMessagePayload(UMOMessage message)
261     {
262         try
263         {
264             return message.getPayloadAsString();
265         }
266         catch (Exception JavaDoc e)
267         {
268             logException(e);
269             logger.info("Failed to read message payload as string, using raw payload");
270             return message.getPayload();
271         }
272     }
273
274     /**
275      * Returns an endpoint for the given exception. ExceptionListeners can have
276      * multiple endpoints registered on them. This methods allows custom
277      * implementations to control which endpoint is used based on the exception
278      * thrown. This implementation simply returns the first endpoint in the list.
279      *
280      * @param t the exception thrown
281      * @return The endpoint used to dispatch an exception message on or null if there
282      * are no endpoints registered
283      */

284     protected UMOEndpoint getEndpoint(Throwable JavaDoc t)
285     {
286         if (endpoints.size() > 0)
287         {
288             return (UMOEndpoint)endpoints.get(0);
289         }
290         else
291         {
292             return null;
293         }
294     }
295
296     /**
297      * Used to log the error passed into this Exception Listener
298      *
299      * @param t the exception thrown
300      */

301     protected void logException(Throwable JavaDoc t)
302     {
303         UMOException umoe = ExceptionHelper.getRootMuleException(t);
304         if (umoe != null)
305         {
306             logger.error(umoe.getDetailedMessage());
307         }
308         else
309         {
310             logger.error("Caught exception in Exception Strategy: " + t.getMessage(), t);
311         }
312     }
313
314     /**
315      * Logs a fatal error message to the logging system. This should be used mostly
316      * if an error occurs in the exception listener itself. This implementation logs
317      * the the message itself to the logs if it is not null
318      *
319      * @param message The UMOMessage currently being processed
320      * @param t the fatal exception to log
321      */

322     protected void logFatal(UMOMessage message, Throwable JavaDoc t)
323     {
324         logger.fatal(
325             "Failed to dispatch message to error queue after it failed to process. This may cause message loss."
326                             + (message == null ? "" : "Logging Message here: \n" + message.toString()), t);
327     }
328
329     public boolean isInitialised()
330     {
331         return initialised.get();
332     }
333
334     /**
335      * A messaging exception is thrown when an excpetion occurs during normal message
336      * processing. A <code>MessagingException</code> holds a reference to the
337      * current message that is passed into this method
338      *
339      * @param message the current message being processed
340      * @param e the top level exception thrown. This may be a Messaging exception or
341      * some wrapper exception
342      * @see MessagingException
343      */

344     public abstract void handleMessagingException(UMOMessage message, Throwable JavaDoc e);
345
346     /**
347      * A routing exception is thrown when an excpetion occurs during normal message
348      * processing A <code>RoutingException</code> holds a reference to the current
349      * message and te endpoint being routing to or from when the error occurred. Both
350      * are passed into this method
351      *
352      * @param message the current message being processed
353      * @param endpoint the endpoint being dispatched to or received from when the
354      * error occurred
355      * @param e the top level exception thrown. This may be a Messaging exception or
356      * some wrapper exception
357      * @see RoutingException
358      */

359     public abstract void handleRoutingException(UMOMessage message, UMOImmutableEndpoint endpoint, Throwable JavaDoc e);
360
361     /**
362      * Lifecycle exceptions are thrown when an error occurs during an object's
363      * lifecycle call such as start, stop or initialise. The exception contains a
364      * reference to the object that failed which can be used for more informative
365      * logging.
366      *
367      * @param component the object that failed during a lifecycle call
368      * @param e the top level exception thrown. This may or may not be the
369      * <code>LifecycleException</code> but a lifecycle exception will be
370      * present in the exception stack.
371      * @see LifecycleException
372      */

373     public abstract void handleLifecycleException(Object JavaDoc component, Throwable JavaDoc e);
374
375     /**
376      * A handler for all other exceptions
377      *
378      * @param e the top level exception thrown
379      */

380     public abstract void handleStandardException(Throwable JavaDoc e);
381 }
382
Popular Tags