001 package org.springframework.richclient.exceptionhandling.delegation; 002 003 import java.util.Collections; 004 import java.util.List; 005 006 /** 007 * A purger that looks through to a throwable chain and can select one to unwrap. 008 * 009 * @author Geoffrey De Smet 010 * @since 0.3.0 011 */ 012 public class DefaultExceptionPurger implements ExceptionPurger { 013 014 protected List<Class> includeThrowableClassList = Collections.emptyList(); 015 protected List<Class> excludeThrowableClassList = Collections.emptyList(); 016 017 public DefaultExceptionPurger() {} 018 019 public DefaultExceptionPurger(Class includeThrowableClass, Class excludeThrowableClass) { 020 if (includeThrowableClass != null) { 021 this.includeThrowableClassList = Collections.singletonList(includeThrowableClass); 022 } 023 if (excludeThrowableClass != null) { 024 this.excludeThrowableClassList = Collections.singletonList(excludeThrowableClass); 025 } 026 } 027 028 public DefaultExceptionPurger(List<Class> includeThrowableClassList, List<Class> excludeThrowableClassList) { 029 if (includeThrowableClassList != null) { 030 this.includeThrowableClassList = includeThrowableClassList; 031 } 032 if (excludeThrowableClassList != null) { 033 this.excludeThrowableClassList = excludeThrowableClassList; 034 } 035 } 036 037 /** 038 * See @{link {@link #setIncludeThrowableClassList(List)}. 039 * @param includeThrowableClass used as a singleton list for includeThrowableClassList 040 */ 041 public void setIncludeThrowableClass(Class includeThrowableClass) { 042 setIncludeThrowableClassList(Collections.singletonList(includeThrowableClass)); 043 } 044 045 /** 046 * Sets Throwables that if found, are unwrapped. 047 * These Throwables are ussually very specific exceptions, for example: LoginCredentialsExpiredException. 048 * The earliest throwable found is selected. 049 * </p> 050 * Given a chain A1->B1->C1->B2->D1: 051 * {A} returns A1; 052 * {B} returns B1; 053 * {D} returns D1; 054 * {Z) returns A1; 055 * {C, Z} returns C1; 056 * {B, D} returns B1; 057 * {D, B} return B1; 058 * </p> 059 * When combined, includeThrowableClassList takes priority over excludeThrowableClassList. 060 * @param includeThrowableClassList a list of classes 061 */ 062 public void setIncludeThrowableClassList(List<Class> includeThrowableClassList) { 063 this.includeThrowableClassList = includeThrowableClassList; 064 } 065 066 /** 067 * See @{link {@link #setExcludeThrowableClassList(List)}. 068 * @param excludeThrowableClass used as a singleton list for excludeThrowableClassList 069 */ 070 public void setExcludeThrowableClass(Class excludeThrowableClass) { 071 setExcludeThrowableClassList(Collections.singletonList(excludeThrowableClass)); 072 } 073 074 /** 075 * Sets Throwables that if found, its cause is unwrapped. 076 * These Throwables are ussually very general wrapper exceptions, for example: WrapperException. 077 * The last throwable found's cause is selected. 078 * If the cause is null, itself is selected. 079 * </p> 080 * Given a chain A1->B1->C1->B2->D1: 081 * {A} returns B1; 082 * {B} returns D1; 083 * {D} returns D1; 084 * {Z) returns A1; 085 * {C, Z} returns B2; 086 * {C, D} returns D1; 087 * {D, C} return D1; 088 * </p> 089 * When combined, includeThrowableClassList takes priority over excludeThrowableClassList. 090 * @param excludeThrowableClassList a list of classes 091 */ 092 public void setExcludeThrowableClassList(List<Class> excludeThrowableClassList) { 093 this.excludeThrowableClassList = excludeThrowableClassList; 094 } 095 096 097 public Throwable purge(Throwable root) { 098 Throwable excludedPurged = root; 099 Throwable e = root; 100 while (e != null) { 101 if (containedIn(e, includeThrowableClassList)) { 102 return e; 103 } 104 boolean excludedContained = containedIn(e, excludeThrowableClassList); 105 if (excludedContained) { 106 excludedPurged = e; // in case the cause is null 107 } 108 // get cause of e (and null at end of chain) 109 e = (e.getCause() == e) ? null : e.getCause(); 110 if (excludedContained && e != null) { 111 excludedPurged = e; // in case the cause is not null 112 } 113 } 114 return excludedPurged; 115 } 116 117 118 // public Throwable purge(Throwable root) { 119 // Throwable purged = root; 120 // Throwable e = root; 121 // while (containedIn(e, excludeThrowableClassList)) { 122 // // get cause of e (and null at end of chain) 123 // e = (e.getCause() == e) ? null : e.getCause(); 124 // if (e == null) { 125 // break; 126 // } 127 // purged = e; 128 // } 129 // return purged; 130 // } 131 132 protected boolean containedIn(Throwable e, List<Class> throwableClassList) { 133 for (Class throwableClass : throwableClassList) { 134 if (throwableClass.isInstance(e)) { 135 return true; 136 } 137 } 138 return false; 139 } 140 141 }