1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 package com.ivata.mask.util;
106 import java.beans.PropertyDescriptor;
107 import java.lang.reflect.InvocationTargetException;
108 import org.apache.commons.beanutils.PropertyUtils;
109 import org.apache.log4j.Logger;
110 /***
111 * <p>
112 * Routines for handling exceptions.
113 * </p>
114 * <p>
115 * Don't create an instance of this class; use the static final methods.
116 * </p>
117 *
118 * @since ivata masks 0.4 (2002-05-20)
119 * @author Colin MacLeod
120 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
121 * @version $Revision: 1.9 $
122 */
123 public final class ThrowableHandling {
124 /***
125 * <p>
126 * This array of string contains all the known methods which will return a
127 * cause exception/throwable. The order is the order they will be searched
128 * for.
129 * </p>
130 */
131 private static final String[] CAUSE_PROPERTIES = {
132 "rootCause",
133 "targetException",
134 "undeclaredThrowable",
135 "causedBy",
136 "cause"
137 };
138 /***
139 * <p>
140 * Used to identify the preprended text in embedded exceptions.
141 * </p>
142 */
143 static final String[] EMBEDDED = {
144 "Embedded Exception",
145 "SystemException is:"
146 };
147 /***
148 * <copyDoc>Refer to {@link Logger}.</copyDoc>
149 */
150 private static final Logger logger
151 = Logger.getLogger(ThrowableHandling.class);
152 /***
153 * <p>
154 * If the parameter provided is a <code>RemoteException</code>, then
155 * provide the original exception, otherwise just return this exception.
156 * </p>
157 *
158 * @param throwable
159 * throwable object to return the original exception for.
160 * @return the exception which originally was thrown.
161 */
162 public static Throwable getCause(final Throwable throwable) {
163 if (logger.isDebugEnabled()) {
164 logger.debug("getCause(Throwable throwable = " + throwable
165 + ") - start");
166 }
167
168 if (throwable == null) {
169 if (logger.isDebugEnabled()) {
170 logger.debug("getCause(Throwable) - end - return value = "
171 + null);
172 }
173 return null;
174 }
175 Throwable returnThrowable = throwable;
176 Throwable cause;
177 while (((cause = getCauseOrNull(returnThrowable)) != null)
178 && (cause != returnThrowable)) {
179 returnThrowable = cause;
180 }
181
182 if (logger.isDebugEnabled()) {
183 logger.debug("getCause(Throwable) - end - return value = "
184 + returnThrowable);
185 }
186 return returnThrowable;
187 }
188 /***
189 * <p>
190 * If the given throwable was caused by another, get that cause.
191 * </p>
192 *
193 * @param throwable
194 * the throwable to find the cause for
195 * @return cause of this throwable, or <code>null</code> if there is no
196 * original cause.
197 */
198 private static Throwable getCauseOrNull(final Throwable throwable) {
199 if (logger.isDebugEnabled()) {
200 logger.debug("getCauseOrNull(Throwable throwable = " + throwable
201 + ") - start");
202 }
203
204 if (throwable == null) {
205 if (logger.isDebugEnabled()) {
206 logger.debug("getCauseOrNull: throwable was null");
207 }
208 return null;
209 }
210 PropertyDescriptor[] descriptors = PropertyUtils
211 .getPropertyDescriptors(throwable.getClass());
212
213 String causeProperty = null;
214 outerLoop:
215 for (int j = 0; j < ThrowableHandling.CAUSE_PROPERTIES.length; j++) {
216 String property = ThrowableHandling.CAUSE_PROPERTIES[j];
217 for (int i = 0; i < descriptors.length; i++) {
218 PropertyDescriptor descriptor = descriptors[i];
219 if (logger.isDebugEnabled()) {
220 logger.debug("Comparing property '"
221 + descriptor.getName()
222 + "' to known cause property '"
223 + property
224 + "'");
225 }
226 if (property.equals(descriptor.getName())) {
227 if (logger.isDebugEnabled()) {
228 logger.debug("getCauseOrNull: using '"
229 + property
230 + "' as cause property");
231 }
232 causeProperty = property;
233 break outerLoop;
234 }
235 }
236 }
237
238
239 if (causeProperty == null) {
240 if (logger.isDebugEnabled()) {
241 logger.debug("getCauseOrNull: cause property is null");
242 }
243 return null;
244 }
245 try {
246 Throwable returnThrowable = (Throwable) PropertyUtils.getProperty(
247 throwable, causeProperty);
248 if (logger.isDebugEnabled()) {
249 logger.debug("getCauseOrNull(Throwable) - end - return value = "
250 + returnThrowable);
251 }
252 return returnThrowable;
253 } catch (IllegalAccessException e) {
254 logger.error("getCauseOrNull(Throwable)", e);
255
256 if (logger.isDebugEnabled()) {
257 logger.debug(e);
258 }
259 return null;
260 } catch (InvocationTargetException e) {
261 logger.error("getCauseOrNull(Throwable)", e);
262
263 if (logger.isDebugEnabled()) {
264 logger.debug(e);
265 }
266 return null;
267 } catch (NoSuchMethodException e) {
268 logger.error("getCauseOrNull(Throwable)", e);
269
270 if (logger.isDebugEnabled()) {
271 logger.debug(e);
272 }
273 return null;
274 }
275 }
276 /***
277 * <p>
278 * If the parameter provided is a <code>RemoteException</code>, then
279 * provide the message from the original exception, otherwise just return
280 * the message of this exception.
281 * </p>
282 *
283 * @param throwable
284 * throwable object to return the original exception message for.
285 * @return the message of the exception which originally was thrown.
286 */
287 public static String getRemoteMessage(final Throwable throwable) {
288 if (logger.isDebugEnabled()) {
289 logger.debug("getRemoteMessage(Throwable throwable = " + throwable
290 + ") - start");
291 }
292
293 Throwable remoteException = getCause(throwable);
294 String messageText = getCause(remoteException).getMessage();
295 int index, textPosition;
296
297 if (messageText == null) {
298 messageText = "An application exception occurred, "
299 + remoteException.getClass() + ".";
300 } else {
301
302 for (index = 0; index < EMBEDDED.length; ++index) {
303 if ((textPosition = messageText.indexOf(EMBEDDED[index]))
304 != -1) {
305 messageText = messageText.substring(textPosition
306 + EMBEDDED[index].length());
307 break;
308 }
309 }
310 }
311
312 if (logger.isDebugEnabled()) {
313 logger.debug("getRemoteMessage(Throwable) - end - return value = "
314 + messageText);
315 }
316 return messageText;
317 }
318 /***
319 * <p>
320 * Private default constructor ensures utility class functionality.
321 * </p>
322 */
323 private ThrowableHandling() {
324 }
325 }