    001    // Copyright 2008, 2011 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
    015    package org.apache.tapestry5.ioc.util;
    016
    017    import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
    018    import org.apache.tapestry5.ioc.services.PropertyAccess;
    019
    020    /**
    021     * Contains static methods useful for manipulating exceptions.
    022     */
    023    public 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    }