001    package org.springframework.richclient.exceptionhandling.delegation;
002    
003    import java.lang.Thread.UncaughtExceptionHandler;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    /**
008     * Checks the exception chain to determine if it wants to handle it.
009     * In most cases this class is overkill and SimpleExceptionHandlerDelegate with a purger will suffice.
010     * Think about it: just purging out MySpecificLoginException suffices most of the time,
011     * it doesn't really matter that it's wrapped in MyWrapperException.
012     * 
013     * @see SimpleExceptionHandlerDelegate
014     * @see DefaultExceptionPurger
015     * @author Geoffrey De Smet
016     * @since 0.3.0
017     */
018    public class ChainInspectingExceptionHandlerDelegate extends AbstractExceptionHandlerDelegate {
019        
020        private List<ChainPart> chainPartList;
021    
022        public ChainInspectingExceptionHandlerDelegate() {
023        }
024        
025        public ChainInspectingExceptionHandlerDelegate(List<ChainPart> chainPartList,
026                UncaughtExceptionHandler exceptionHandler) {
027            super(exceptionHandler);
028            this.chainPartList = chainPartList;
029        }
030    
031        public void setChainPartList(List<ChainPart> chainPartList) {
032            this.chainPartList = chainPartList;
033        }
034    
035        @Override
036        public boolean hasAppropriateHandlerPurged(Throwable root) {
037            Throwable e = root;
038            boolean check = true;
039            Iterator<ChainPart> it = chainPartList.iterator();
040            while (check && it.hasNext()) {
041                ChainPart chainPart = it.next();
042                e = findChainPartThrowable(chainPart, e);
043                if (e == null) {
044                    check = false;
045                } else {
046                    // get cause of e (and null at end of chain)
047                    e = (e.getCause() == e) ? null : e.getCause();
048                    if (e == null) {
049                        check = check && !it.hasNext();
050                    }
051                }
052            }
053            return check;
054        }
055    
056    //  public boolean hasAppropriateHandlerPurgedAlternativeImplementation(Throwable root) {
057    //      Throwable e = root;
058    //      for (ChainPart chainPart : chainPartList) {
059    //          if (e == null) {
060    //              return false; // nothing left to check
061    //          }
062    //          e = findChainPartThrowable(chainPart, e);
063    //          if (e == null) {
064    //              return false; // not found
065    //          }
066    //          // get cause of e (and null at end of chain)
067    //          e = (e.getCause() == e) ? null : e.getCause();
068    //      }
069    //      return true;
070    //  }
071        
072        public Throwable findChainPartThrowable(ChainPart chainPart, Throwable firstThrowable) {
073            Throwable e = firstThrowable;
074            int relativeDepth = 0;
075            int minimumRelativeDepth = chainPart.getMinimumRelativeDepth();
076            int maximumRelativeDepth = chainPart.getMaximumRelativeDepth();
077            while (!chainPart.getThrowableClass().isInstance(e)
078                    || (relativeDepth < minimumRelativeDepth)) {
079                relativeDepth++;
080                Throwable cause = e.getCause();
081                if (cause == null || cause == e) {
082                    return null; // Chain is to short to find the chainPart
083                } else {
084                    e = cause;
085                }
086                if ((maximumRelativeDepth >= 0)
087                        && (relativeDepth > maximumRelativeDepth)) {
088                    return null; // We did not find the chainPart early enough
089                }
090            }
091            return e;
092        }
093        
094    
095        @Override
096        public void uncaughtExceptionPurged(Thread thread, Throwable throwable) {
097            exceptionHandler.uncaughtException(thread, throwable);
098        }
099        
100        public static class ChainPart {
101            
102            private Class throwableClass = Throwable.class;
103            private int minimumRelativeDepth = 0;
104            private int maximumRelativeDepth = -1;
105            
106            public ChainPart() {}
107            
108            public ChainPart(Class throwableClass) {
109                this.throwableClass = throwableClass;
110            }
111            
112            public ChainPart(Class throwableClass, int relativeDepth) {
113                this(throwableClass, relativeDepth, relativeDepth);
114            }
115            
116            public ChainPart(Class throwableClass, int minimumRelativeDepth, int maximumRelativeDepth) {
117                this.throwableClass = throwableClass;
118                this.minimumRelativeDepth = minimumRelativeDepth;
119                this.maximumRelativeDepth = maximumRelativeDepth;
120            }
121    
122            public Class getThrowableClass() {
123                return throwableClass;
124            }
125            
126            public void setThrowableClass(Class throwableClass) {
127                this.throwableClass = throwableClass;
128            }
129            
130            public void setRelativeDepth(int relativeDepth) {
131                setMinimumRelativeDepth(relativeDepth);
132                setMaximumRelativeDepth(relativeDepth);
133            }
134            
135            public int getMinimumRelativeDepth() {
136                return minimumRelativeDepth;
137            }
138            
139            public void setMinimumRelativeDepth(int minimumRelativeDepth) {
140                this.minimumRelativeDepth = minimumRelativeDepth;
141            }
142            
143            public int getMaximumRelativeDepth() {
144                return maximumRelativeDepth;
145            }
146            
147            public void setMaximumRelativeDepth(int maximumRelativeDepth) {
148                this.maximumRelativeDepth = maximumRelativeDepth;
149            }
150            
151        }
152        
153    }