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 }