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 checked Exceptions with a given root cause. 020 */ 021public abstract class WrappedCheckedException extends Exception { 022 023 private static final long serialVersionUID = 615855181745250021L; 024 025 /** 026 * Construct a WrappedCheckedException with the specified 027 * message. 028 * @param message the specific message 029 */ 030 public WrappedCheckedException(String message) { 031 super(message); 032 } 033 034 /** 035 * Construct a WrappedCheckedException with the specified 036 * message and wrapped exception. 037 * @param message the specific message 038 * @param cause the wrapped exception 039 */ 040 public WrappedCheckedException(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 */ 048 @Override 049 public String getMessage() { 050 return constructMessage(super.getMessage(), getCause()); 051 } 052 053 /** 054 * Constructs an exception String with the given message and incorporating the 055 * causing exception 056 * @param message The specific message 057 * @param cause The causing exception 058 * @return The exception String 059 */ 060 protected String constructMessage(String message, Throwable cause) { 061 062 if (cause != null) { 063 064 StringBuilder strBuilder = new StringBuilder(); 065 066 if (message != null) { 067 strBuilder.append(message).append(": "); 068 } 069 070 strBuilder.append("Wrapped exception is {").append(cause); 071 strBuilder.append("}"); 072 073 return strBuilder.toString(); 074 075 } else { 076 return message; 077 } 078 } 079 080 /** 081 * Retrieves the ultimate root cause for this exception, or null 082 * @return The root cause 083 */ 084 public Throwable getRootCause() { 085 086 Throwable rootCause = null; 087 Throwable nextCause = getCause(); 088 089 while (nextCause != null && !nextCause.equals(rootCause)) { 090 rootCause = nextCause; 091 nextCause = nextCause.getCause(); 092 } 093 094 return rootCause; 095 } 096 097 /** 098 * Returns the next parent exception of the given type, or null 099 * @param exceptionType the exception type to match 100 * @param <E> The Exception type 101 * @return The matched exception of the target type, or null 102 */ 103 public <E extends Exception> E findWrapped(Class<E> exceptionType) { 104 105 if (exceptionType == null) { 106 return null; 107 } 108 109 Throwable cause = getCause(); 110 111 while (true) { 112 113 if (cause == null) { 114 return null; 115 } 116 117 if (exceptionType.isInstance(cause)) { 118 119 @SuppressWarnings("unchecked") E matchedCause = (E) cause; 120 return matchedCause; 121 } 122 123 if (cause.getCause() == cause) { 124 return null; 125 } 126 127 if (cause instanceof WrappedRuntimeException) { 128 return ((WrappedRuntimeException) cause).findWrapped(exceptionType); 129 } 130 if (cause instanceof WrappedCheckedException) { 131 return ((WrappedCheckedException) cause).findWrapped(exceptionType); 132 } 133 134 cause = cause.getCause(); 135 } 136 } 137}