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    }