    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}