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 }