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}