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    }