001/* 002 * Copyright 2012 Christopher Pheby 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 */ 016package org.jadira.cdt.exception; 017 018/** 019 * Class for constructing runtime Exceptions with a given root cause. 020 */ 021public abstract class WrappedRuntimeException extends RuntimeException { 022 023 private static final long serialVersionUID = 2370572498972367128L; 024 025 /** 026 * Construct a WrappedRuntimeException with the specified 027 * message. 028 * @param message the specific message 029 */ 030 public WrappedRuntimeException(String message) { 031 super(message); 032 } 033 034 /** 035 * Construct a WrappedRuntimeException with the specified 036 * message and wrapped exception. 037 * @param message the specific message 038 * @param cause the wrapped exception 039 */ 040 public WrappedRuntimeException(String message, Throwable cause) { 041 super(message, cause); 042 } 043 044 /** 045 * Return the detail message, including the message from the wrapped 046 * exception if there is one. 047 * @return The message 048 */ 049 @Override 050 public String getMessage() { 051 return constructMessage(super.getMessage(), getCause()); 052 } 053 054 /** 055 * Constructs an exception String with the given message and incorporating the 056 * causing exception 057 * @param message The message 058 * @param cause The causing exception 059 * @return The exception String 060 */ 061 protected String constructMessage(String message, Throwable cause) { 062 063 if (cause != null) { 064 065 StringBuilder strBuilder = new StringBuilder(); 066 067 if (message != null) { 068 strBuilder.append(message).append(": "); 069 } 070 071 strBuilder.append("Wrapped exception is {").append(cause); 072 strBuilder.append("}"); 073 074 return strBuilder.toString(); 075 076 } else { 077 return message; 078 } 079 } 080 081 /** 082 * Retrieves the ultimate root cause for this exception, or null 083 * @return The root cause 084 */ 085 public Throwable getRootCause() { 086 087 Throwable rootCause = null; 088 Throwable nextCause = getCause(); 089 090 while (nextCause != null && !nextCause.equals(rootCause)) { 091 rootCause = nextCause; 092 nextCause = nextCause.getCause(); 093 } 094 095 return rootCause; 096 } 097 098 /** 099 * 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}