001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.lang;
018
019/**
020 * 
021 * @author igor.vaynberg
022 */
023public class Exceptions
024{
025        private Exceptions()
026        {
027        }
028
029        /**
030         * Gets root cause of the throwable
031         * 
032         * @param throwable
033         * @return root cause
034         */
035        public Throwable getRootCause(final Throwable throwable)
036        {
037                Throwable cursor = throwable;
038                while (cursor.getCause() != null)
039                {
040                        cursor = cursor.getCause();
041                }
042                return cursor;
043        }
044
045        /**
046         * Looks for a cause of the specified type in throwable's chain
047         * 
048         * @param <T>
049         * @param throwable
050         * @param causeType
051         * @return matched {@link Throwable} in the chain or {@code null} if none
052         */
053        public static <T extends Throwable> T findCause(final Throwable throwable,
054                final Class<T> causeType)
055        {
056                return visit(throwable, new IThrowableVisitor<T>()
057                {
058                        @Override
059                        @SuppressWarnings("unchecked")
060                        public void visit(final Throwable throwable, final Visit<T> visit)
061                        {
062                                if (causeType.isAssignableFrom(throwable.getClass()))
063                                {
064                                        visit.stop((T)throwable);
065                                }
066
067                        }
068                });
069        }
070
071        /**
072         * Represents a visit
073         * 
074         * @author igor
075         * @param <T>
076         */
077        public static class Visit<T>
078        {
079                private T result;
080                private boolean stopped;
081
082                /**
083                 * Stops visit with specified resut
084                 * 
085                 * @param result
086                 */
087                public void stop(final T result)
088                {
089                        this.result = result;
090                        stop();
091                }
092
093                /**
094                 * Stops visit
095                 */
096                public void stop()
097                {
098                        stopped = true;
099                }
100        }
101
102        /**
103         * Visitor used to visit {@link Throwable} chains
104         * 
105         * @param <T>
106         */
107        public static interface IThrowableVisitor<T>
108        {
109                /**
110                 * Visit a throwable
111                 * 
112                 * @param throwable
113                 * @param visit
114                 */
115                void visit(Throwable throwable, Visit<T> visit);
116        }
117
118        /**
119         * Visits the {@link Throwable}'s chain
120         * 
121         * @param <T>
122         * @param throwable
123         * @param visitor
124         * @return result set on visitor or {@code null} if none
125         */
126        public static <T> T visit(final Throwable throwable, final IThrowableVisitor<T> visitor)
127        {
128                Visit<T> visit = new Visit<>();
129                Throwable cursor = throwable;
130                while (cursor != null)
131                {
132                        visitor.visit(cursor, visit);
133                        if (visit.stopped)
134                        {
135                                return visit.result;
136                        }
137                        cursor = cursor.getCause();
138                }
139                return null;
140        }
141}