1 /*
2 * Copyright 2012 Christopher Pheby
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.jadira.cdt.exception;
17
18 /**
19 * Class for constructing runtime Exceptions with a given root cause.
20 */
21 public abstract class WrappedRuntimeException extends RuntimeException {
22
23 private static final long serialVersionUID = 2370572498972367128L;
24
25 /**
26 * Construct a WrappedRuntimeException with the specified
27 * message.
28 * @param message the specific message
29 */
30 public WrappedRuntimeException(String message) {
31 super(message);
32 }
33
34 /**
35 * Construct a WrappedRuntimeException with the specified
36 * message and wrapped exception.
37 * @param message the specific message
38 * @param cause the wrapped exception
39 */
40 public WrappedRuntimeException(String message, Throwable cause) {
41 super(message, cause);
42 }
43
44 /**
45 * Return the detail message, including the message from the wrapped
46 * exception if there is one.
47 * @return The message
48 */
49 @Override
50 public String getMessage() {
51 return constructMessage(super.getMessage(), getCause());
52 }
53
54 /**
55 * Constructs an exception String with the given message and incorporating the
56 * causing exception
57 * @param message The message
58 * @param cause The causing exception
59 * @return The exception String
60 */
61 protected String constructMessage(String message, Throwable cause) {
62
63 if (cause != null) {
64
65 StringBuilder strBuilder = new StringBuilder();
66
67 if (message != null) {
68 strBuilder.append(message).append(": ");
69 }
70
71 strBuilder.append("Wrapped exception is {").append(cause);
72 strBuilder.append("}");
73
74 return strBuilder.toString();
75
76 } else {
77 return message;
78 }
79 }
80
81 /**
82 * Retrieves the ultimate root cause for this exception, or null
83 * @return The root cause
84 */
85 public Throwable getRootCause() {
86
87 Throwable rootCause = null;
88 Throwable nextCause = getCause();
89
90 while (nextCause != null && !nextCause.equals(rootCause)) {
91 rootCause = nextCause;
92 nextCause = nextCause.getCause();
93 }
94
95 return rootCause;
96 }
97
98 /**
99 * Returns the next parent exception of the given type, or null
100 * @param exceptionType the exception type to match
101 * @param <E> The exception type
102 * @return The matched exception of the target type, or null
103 */
104 public <E extends Exception> E findWrapped(Class<E> exceptionType) {
105
106 if (exceptionType == null) {
107 return null;
108 }
109
110 Throwable cause = getCause();
111
112 while (true) {
113
114 if (cause == null) {
115 return null;
116 }
117
118 if (exceptionType.isInstance(cause)) {
119
120 @SuppressWarnings("unchecked") E matchedCause = (E) cause;
121 return matchedCause;
122 }
123
124 if (cause.getCause() == cause) {
125 return null;
126 }
127
128 if (cause instanceof WrappedRuntimeException) {
129 return ((WrappedRuntimeException) cause).findWrapped(exceptionType);
130 }
131 if (cause instanceof WrappedCheckedException) {
132 return ((WrappedCheckedException) cause).findWrapped(exceptionType);
133 }
134
135 cause = cause.getCause();
136 }
137 }
138 }