com.gemstone.gemfire.management.internal.cli.util.CauseFinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
SnappyData store based off Pivotal GemFireXD
The newest version!
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you
* may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.management.internal.cli.util;
/**
* Helper class to navigate through the nested causes of an exception.
* Provides method to
*
* - find index of an Exception of a specific type
*
- find Root Cause of the Exception
*
- retrieve a nested cause at a specific index/depth
*
- find a cause by specific type
*
*
* @author Abhishek Chaudhari
* @since 7.0
*/
public class CauseFinder {
private static final int START_INDEX = 0;
/**
* Returns the index of a first nested cause which is of the given Throwable
* type or its sub-type depending on isSubtypeOk
value.
* NOTE: It looks for the "nested" causes & doesn't try to match the
* causeClass
of the parent
.
*
* Returns -1 if a cause with the given Throwable type is not found.
*
* @param parent
* parent Throwable instance
* @param causeClass
* type of the nested Throwable cause
* @param isSubtypeOk
* whether any matching sub-type is required or exact match is
* required
* @return index/depth of the cause starting from the 'top most' Throwable in
* the stack. -1 if can't find it.
*/
public static int indexOfCause(Throwable parent, Class causeClass, final boolean isSubtypeOk) {
return indexOfCause(parent, causeClass, START_INDEX, isSubtypeOk);
}
/**
* Returns the index of a first nested cause which is of the given Throwable
* type or its sub-type depending on isSubtypeOk
value.
* NOTE: It looks for the "nested" causes & doesn't try to match the
* causeClass
of the parent
.
*
* Returns -1 if a cause with the given Throwable type is not found.
*
* @param parent
* parent Throwable instance
* @param causeClass
* type of the nested Throwable cause
* @param cindex
* variable to store current index/depth of the cause
* @param isSubtypeOk
* whether any matching sub-type is required or exact match is
* required
* @return index/depth of the cause starting from the 'top most' Throwable
* in the stack. -1 if can't find it.
*/
private static int indexOfCause(Throwable parent, Class causeClass, final int cindex, final boolean isSubtypeOk) {
int resultIndex = cindex;
Throwable cause = parent.getCause();
//(cause is not null & cause is not of type causeClass)
if (cause != null && !isMatching(cause, causeClass, isSubtypeOk)) {
//recurse deeper
resultIndex = indexOfCause(cause, causeClass, cindex + 1, isSubtypeOk);
} else if (cause != null && isMatching(cause, causeClass, isSubtypeOk)) {
resultIndex = cindex != -1 ? cindex + 1 : cindex;
} else if (cause == null) {
resultIndex = -1;
}
return resultIndex;
}
/**
* Returns whether the given cause
is assignable or has same
* type as that of causeClass
depending on
* isSubtypeOk
value.
*
* @param cause
* parent Throwable instance
* @param causeClass
* type of the nested Throwable cause
* @param isSubtypeOk
* whether any matching sub-type is required or exact match is
* required
* @return true if cause
is assignable or has same type as that
* of causeClass
. false otherwise
*/
//Note: No not null check on 'Throwable cause' - currently called after null check
private static boolean isMatching(Throwable cause, Class causeClass, final boolean isSubtypeOk) {
return isSubtypeOk ? causeClass.isInstance(cause) : causeClass == cause.getClass();
}
/**
* Returns nested 'root' cause of the given parent Throwable. Will return the
* same Throwable if it has no 'cause'.
*
* @param parent
* Throwable whose root cause is to be found
* @return nested root cause.
* @throws IllegalArgumentException
* when parent is null
*/
public static Throwable getRootCause(Throwable parent) {
return getRootCause(parent, 0);
}
/**
* Returns nested 'root' cause of the given parent Throwable. Will return the
* same Throwable if it has no 'cause'. If depth
is 0, does a
* null
check on the given parent Throwable
& if
* parent
is null
, throws
* {@link IllegalArgumentException}.
*
* @param parent
* Throwable whose root cause is to be found
* @param depth
* recurse depth indicator
* @return nested root cause.
* @throws IllegalArgumentException
* when parent is null
at depth = 0
*/
//Note: private method
private static Throwable getRootCause(Throwable parent, int depth) {
if (depth == 0) {
if (parent == null) {
throw new IllegalArgumentException("Given parent Throwable is null.");
}
}
Throwable theCause = parent.getCause();
if (theCause != null) {
//recurse deeper
return getRootCause(theCause, depth + 1);
}
return parent;
}
/**
* Returns cause at the specified depth/index starting from the 'top most'
* Throwable parent
in the stack. Returns null
if
* it can't find it.
*
* @param parent
* Throwable to use to find the cause at given index/depth
* @param requiredIndex
* index/depth of nesting the cause
* @return cause at the specified index starting from the 'top most'
* Throwable in the stack. null
if it can't find it.
*/
public static Throwable causeAt(Throwable parent, final int requiredIndex) {
//
// TODO:
// NEED TO CHECK WHETHER RIGHT PARENT CAUSE RETRUNED
//
if (parent != null && requiredIndex > 0) {
//recurse deeper
return causeAt(parent.getCause(), requiredIndex - 1);
}
//when there isn't required depth
if (requiredIndex > 0) {
return null;
}
return parent;
}
/**
* Returns the first occurrence of nested cause of parent
which
* matches the specified causeType
or its sub-type depending on
* isSubtypeOk
value.
*
* @param parent
* Throwable to use to find the cause of given type
* @param causeType
* type of the nested Throwable cause
* @param isSubtypeOk
* whether any matching sub-type is required or exact match is
* required
* @return the first occurrence of nested cause which matches the specified
* causeType
or its sub-type. null
if it
* can't find it.
*/
public static Throwable causeByType(Throwable parent, Class causeType, boolean isSubtypeOk) {
Throwable cause = null;
int foundAtIndex = indexOfCause(parent, causeType, isSubtypeOk);
if (foundAtIndex != -1) {
cause = causeAt(parent, foundAtIndex);
}
return cause;
}
}