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 }