001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.core;
018:
019: /**
020: * Handy class for wrapping runtime <code>Exceptions</code> with a root cause.
021: *
022: * <p>This class is <code>abstract</code> to force the programmer to extend
023: * the class. <code>getMessage</code> will include nested exception
024: * information; <code>printStackTrace</code> and other like methods will
025: * delegate to the wrapped exception, if any.
026: *
027: * <p>The similarity between this class and the {@link NestedCheckedException}
028: * class is unavoidable, as Java forces these two classes to have different
029: * superclasses (ah, the inflexibility of concrete inheritance!).
030: *
031: * @author Rod Johnson
032: * @author Juergen Hoeller
033: * @see #getMessage
034: * @see #printStackTrace
035: * @see NestedCheckedException
036: */
037: public abstract class NestedRuntimeException extends RuntimeException {
038:
039: /** Use serialVersionUID from Spring 1.2 for interoperability */
040: private static final long serialVersionUID = 5439915454935047936L;
041:
042: /**
043: * Construct a <code>NestedRuntimeException</code> with the specified detail message.
044: * @param msg the detail message
045: */
046: public NestedRuntimeException(String msg) {
047: super (msg);
048: }
049:
050: /**
051: * Construct a <code>NestedRuntimeException</code> with the specified detail message
052: * and nested exception.
053: * @param msg the detail message
054: * @param cause the nested exception
055: */
056: public NestedRuntimeException(String msg, Throwable cause) {
057: super (msg, cause);
058: }
059:
060: /**
061: * Return the detail message, including the message from the nested exception
062: * if there is one.
063: */
064: public String getMessage() {
065: return NestedExceptionUtils.buildMessage(super .getMessage(),
066: getCause());
067: }
068:
069: /**
070: * Retrieve the innermost cause of this exception, if any.
071: * @return the innermost exception, or <code>null</code> if none
072: * @since 2.0
073: */
074: public Throwable getRootCause() {
075: Throwable rootCause = null;
076: Throwable cause = getCause();
077: while (cause != null && cause != rootCause) {
078: rootCause = cause;
079: cause = cause.getCause();
080: }
081: return rootCause;
082: }
083:
084: /**
085: * Retrieve the most specific cause of this exception, that is,
086: * either the innermost cause (root cause) or this exception itself.
087: * <p>Differs from {@link #getRootCause()} in that it falls back
088: * to the present exception if there is no root cause.
089: * @return the most specific cause (never <code>null</code>)
090: * @since 2.0.3
091: */
092: public Throwable getMostSpecificCause() {
093: Throwable rootCause = getRootCause();
094: return (rootCause != null ? rootCause : this );
095: }
096:
097: /**
098: * Check whether this exception contains an exception of the given type:
099: * either it is of the given class itself or it contains a nested cause
100: * of the given type.
101: * @param exType the exception type to look for
102: * @return whether there is a nested exception of the specified type
103: */
104: public boolean contains(Class exType) {
105: if (exType == null) {
106: return false;
107: }
108: if (exType.isInstance(this )) {
109: return true;
110: }
111: Throwable cause = getCause();
112: if (cause == this ) {
113: return false;
114: }
115: if (cause instanceof NestedRuntimeException) {
116: return ((NestedRuntimeException) cause).contains(exType);
117: } else {
118: while (cause != null) {
119: if (exType.isInstance(cause)) {
120: return true;
121: }
122: if (cause.getCause() == cause) {
123: break;
124: }
125: cause = cause.getCause();
126: }
127: return false;
128: }
129: }
130:
131: }
|