001// Copyright 2008-2013 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.commons.util; 016 017import org.apache.tapestry5.commons.services.ClassPropertyAdapter; 018import org.apache.tapestry5.commons.services.PropertyAccess; 019 020/** 021 * Contains static methods useful for manipulating exceptions. 022 */ 023public class ExceptionUtils 024{ 025 /** 026 * Locates a particular type of exception, working its way via the cause property of each exception in the exception 027 * stack. 028 * 029 * @param t the outermost exception 030 * @param type the type of exception to search for 031 * @return the first exception of the given type, if found, or null 032 */ 033 public static <T extends Throwable> T findCause(Throwable t, Class<T> type) 034 { 035 Throwable current = t; 036 037 while (current != null) 038 { 039 if (type.isInstance(current)) 040 { 041 return type.cast(current); 042 } 043 044 // Not a match, work down. 045 046 current = current.getCause(); 047 } 048 049 return null; 050 } 051 052 /** 053 * Locates a particular type of exception, working its way down via any property that returns some type of Exception. 054 * This is more expensive, but more accurate, than {@link #findCause(Throwable, Class)} as it works with older exceptions 055 * that do not properly implement the (relatively new) {@linkplain Throwable#getCause() cause property}. 056 * 057 * @param t the outermost exception 058 * @param type the type of exception to search for 059 * @param access used to access properties 060 * @return the first exception of the given type, if found, or null 061 */ 062 public static <T extends Throwable> T findCause(Throwable t, Class<T> type, PropertyAccess access) 063 { 064 Throwable current = t; 065 066 while (current != null) 067 { 068 if (type.isInstance(current)) 069 { 070 return type.cast(current); 071 } 072 073 Throwable next = null; 074 075 ClassPropertyAdapter adapter = access.getAdapter(current); 076 077 for (String name : adapter.getPropertyNames()) 078 { 079 080 Object value = adapter.getPropertyAdapter(name).get(current); 081 082 if (value != null && value != current && value instanceof Throwable) 083 { 084 next = (Throwable) value; 085 break; 086 } 087 } 088 089 current = next; 090 } 091 092 093 return null; 094 } 095 096 /** 097 * Extracts the message from an exception. If the exception's message is null, returns the exceptions class name. 098 * 099 * @param exception 100 * to extract message from 101 * @return message or class name 102 * @since 5.4 103 */ 104 public static String toMessage(Throwable exception) 105 { 106 assert exception != null; 107 108 String message = exception.getMessage(); 109 110 if (message != null) 111 return message; 112 113 return exception.getClass().getName(); 114 } 115}