001 package org.springframework.richclient.exceptionhandling.delegation;
002
003 import org.apache.commons.logging.Log;
004 import org.apache.commons.logging.LogFactory;
005 import org.springframework.beans.factory.InitializingBean;
006 import org.springframework.richclient.exceptionhandling.AbstractRegisterableExceptionHandler;
007 import org.springframework.util.Assert;
008
009 import java.util.List;
010
011 /**
012 * An exception handler that selects an appropriate exception handler from a list
013 * based on the thrown exception and delegates the handling of the exception to it.
014 * <p/>
015 * This class works very similar to catch statements:
016 * the first delegate which can handle the exception will handle it.
017 * For example, consider 3 simple delegates for the following classes in this order:
018 * NullPointerException (1), RuntimeException (2), IllegalArgumentException (3).
019 * A thrown IllegalArgumentException will be handled by the (2) handler. The (3) handler is useless.
020 *
021 * @see ExceptionHandlerDelegate
022 * @see SimpleExceptionHandlerDelegate
023 * @author Geoffrey De Smet
024 * @since 0.3.0
025 */
026 public class DelegatingExceptionHandler extends AbstractRegisterableExceptionHandler implements InitializingBean {
027
028 protected final transient Log logger = LogFactory.getLog(getClass());
029
030 protected List<ExceptionHandlerDelegate> delegateList;
031 protected ExceptionPurger exceptionPurger = null;
032
033 /**
034 * Sets the list of delegates.
035 * This is not a map because the order is important
036 * and delegate selection is not a simple key based selector.
037 * @param delegateList a list of DelegatingExceptionHandlerDelegate
038 */
039 public void setDelegateList(List<ExceptionHandlerDelegate> delegateList) {
040 this.delegateList = delegateList;
041 }
042
043 /**
044 * If set the throwable will first be purged before handling it.
045 * @param exceptionPurger
046 */
047 public void setExceptionPurger(ExceptionPurger exceptionPurger) {
048 this.exceptionPurger = exceptionPurger;
049 }
050
051 public void afterPropertiesSet() throws Exception {
052 Assert.notEmpty(delegateList, "The delegate list must contains at least one entry.");
053 }
054
055 /**
056 * Delegates the throwable to the appropriate delegate exception handler.
057 * @param thread the thread in which the throwable occurred
058 * @param throwable the thrown throwable
059 */
060 public void uncaughtException(Thread thread, Throwable throwable) {
061 if (exceptionPurger != null) {
062 throwable = exceptionPurger.purge(throwable);
063 }
064 for (ExceptionHandlerDelegate delegate : delegateList) {
065 if (delegate.hasAppropriateHandler(throwable)) {
066 delegate.uncaughtException(thread, throwable);
067 return;
068 }
069 }
070 // A silent exception handler should be configured if it needs to be silent
071 logger.error("No exception handler found for throwable", throwable);
072 }
073
074 }