All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.beangle.security.web.util.ThrowableAnalyzer Maven / Gradle / Ivy

There is a newer version: 4.0.7
Show newest version
/*
 * Beangle, Agile Java/Scala Development Scaffold and Toolkit
 *
 * Copyright (c) 2005-2012, Beangle Software.
 *
 * Beangle is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Beangle is distributed in the hope that it will be useful.
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Beangle.  If not, see .
 */
package org.beangle.security.web.util;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Handler for analyzing {@link Throwable} instances. Can be subclassed to
 * customize its behavior.
 * 
 * @author chaostone
 * @since 2.0
 * @version $Id: ThrowableAnalyzer.java 2559 2008-01-30 16:15:02Z $
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ThrowableAnalyzer {

  /**
   * Default extractor for {@link Throwable} instances.
   * 
   * @see Throwable#getCause()
   */
  public static final ThrowableCauseExtractor DEFAULT_EXTRACTOR = new ThrowableCauseExtractor() {
    public Throwable extractCause(Throwable throwable) {
      return throwable.getCause();
    }
  };

  /**
   * Default extractor for {@link InvocationTargetException} instances.
   * 
   * @see InvocationTargetException#getTargetException()
   */
  public static final ThrowableCauseExtractor INVOCATIONTARGET_EXTRACTOR = new ThrowableCauseExtractor() {
    public Throwable extractCause(Throwable throwable) {
      verifyThrowableHierarchy(throwable, InvocationTargetException.class);
      return ((InvocationTargetException) throwable).getTargetException();
    }
  };

  /**
   * Comparator to order classes ascending according to their hierarchy
   * relation. If two classes have a hierarchical relation, the "higher" class
   * is considered to be greater by this comparator.
* For hierarchically unrelated classes their fully qualified name will be * compared. */ private static final Comparator CLASS_HIERARCHY_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { Class class1 = (Class) o1; Class class2 = (Class) o2; if (class1.isAssignableFrom(class2)) { return 1; } else if (class2.isAssignableFrom(class1)) { return -1; } else { return class1.getName().compareTo(class2.getName()); } } }; /** * Map of registered cause extractors. key: Class; value: * ThrowableCauseExctractor */ private final Map extractorMap; /** * Creates a new ThrowableAnalyzer instance. */ public ThrowableAnalyzer() { this.extractorMap = new TreeMap(CLASS_HIERARCHY_COMPARATOR); initExtractorMap(); } /** * Registers a ThrowableCauseExtractor for the specified type. * Can be used in subclasses overriding {@link #initExtractorMap()}. * * @param throwableType * the type (has to be a subclass of Throwable) * @param extractor * the associated ThrowableCauseExtractor (not null) * @throws IllegalArgumentException * if one of the arguments is invalid */ protected final void registerExtractor(Class throwableType, ThrowableCauseExtractor extractor) { verifyThrowableType(throwableType); if (extractor == null) { throw new IllegalArgumentException("Invalid extractor: null"); } this.extractorMap.put(throwableType, extractor); } /** * Initializes associations between Throwables and * ThrowableCauseExtractors. The default implementation * performs the following registrations:
  • {@link #DEFAULT_EXTRACTOR} for {@link Throwable}
  • *
  • {@link #INVOCATIONTARGET_EXTRACTOR} for {@link InvocationTargetException}

  • * Subclasses overriding this method are encouraged to invoke the super * method to perform the default registrations. They can register additional * extractors as required. *

    * Note: An extractor registered for a specific type is applicable for that type and all * subtypes thereof. However, extractors registered to more specific types are guaranteed to * be resolved first. So in the default case InvocationTargetExceptions will be handled by * {@link #INVOCATIONTARGET_EXTRACTOR} while all other throwables are handled by * {@link #DEFAULT_EXTRACTOR}. * * @see #registerExtractor(Class, ThrowableCauseExtractor) */ protected void initExtractorMap() { registerExtractor(InvocationTargetException.class, INVOCATIONTARGET_EXTRACTOR); registerExtractor(Throwable.class, DEFAULT_EXTRACTOR); } /** * Returns an array containing the classes for which extractors are * registered. The order of the classes is the order in which comparisons * will occur for resolving a matching extractor. * * @return the types for which extractors are registered */ final Class[] getRegisteredTypes() { List typeList = new ArrayList(this.extractorMap.keySet()); return (Class[]) typeList.toArray(new Class[typeList.size()]); } /** * Determines the cause chain of the provided Throwable. The * returned array contains all throwables extracted from the stacktrace, * using the registered {@link ThrowableCauseExtractor extractors}. The * elements of the array are ordered: The first element is the passed in * throwable itself. The following elements appear in their order downward * the stacktrace. *

    * Note: If no {@link ThrowableCauseExtractor} is registered for this instance then the returned * array will always only contain the passed in throwable. * * @param throwable * the Throwable to analyze * @return an array of all determined throwables from the stacktrace * @throws IllegalArgumentException * if the throwable is null * @see #initExtractorMap() */ public final Throwable[] determineCauseChain(Throwable throwable) { if (throwable == null) { throw new IllegalArgumentException("Invalid throwable: null"); } List chain = new ArrayList(); Throwable currentThrowable = throwable; while (currentThrowable != null) { chain.add(currentThrowable); currentThrowable = extractCause(currentThrowable); } return (Throwable[]) chain.toArray(new Throwable[chain.size()]); } /** * Extracts the cause of the given throwable using an appropriate extractor. * * @param throwable * the Throwable (not null * @return the cause, may be null if none could be resolved */ private Throwable extractCause(Throwable throwable) { for (Iterator iter = this.extractorMap.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); Class throwableType = (Class) entry.getKey(); if (throwableType.isInstance(throwable)) { ThrowableCauseExtractor extractor = (ThrowableCauseExtractor) entry.getValue(); return extractor.extractCause(throwable); } } return null; } /** * Returns the first throwable from the passed in array that is assignable * to the provided type. A returned instance is safe to be cast to the * specified type. *

    * If the passed in array is null or empty this method returns null. * * @param throwableType * the type to look for * @param chain * the array (will be processed in element order) * @return the found Throwable, null if not found * @throws IllegalArgumentException * if the provided type is null or no subclass of Throwable */ public final Throwable getFirstThrowableOfType(Class throwableType, Throwable[] chain) { verifyThrowableType(throwableType); if (chain != null) { for (int i = 0; i < chain.length; ++i) { Throwable t = chain[i]; if ((t != null) && throwableType.isInstance(t)) { return t; } } } return null; } /** * Convenience method for verifying that the passed in class refers to a * valid subclass of Throwable. * * @param throwableType * the type to check * @throws IllegalArgumentException * if typeToCheck is either null or * not assignable to expectedBaseType */ private static void verifyThrowableType(Class throwableType) { if (throwableType == null) { throw new IllegalArgumentException("Invalid type: null"); } if (!Throwable.class.isAssignableFrom(throwableType)) { throw new IllegalArgumentException( "Invalid type: '" + throwableType.getName() + "'. Has to be a subclass of '" + Throwable.class.getName() + "'"); } } /** * Verifies that the provided throwable is a valid subclass of the provided * type (or of the type itself). If expectdBaseType is null, no check * will be performed. *

    * Can be used for verification purposes in implementations of {@link ThrowableCauseExtractor * extractors}. * * @param throwable * the Throwable to check * @param expectedBaseType * the type to check against * @throws IllegalArgumentException * if throwable is either null or its * type is not assignable to expectedBaseType */ public static final void verifyThrowableHierarchy(Throwable throwable, Class expectedBaseType) { if (expectedBaseType == null) { return; } if (throwable == null) { throw new IllegalArgumentException("Invalid throwable: null"); } Class throwableType = throwable.getClass(); if (!expectedBaseType.isAssignableFrom(throwableType)) { throw new IllegalArgumentException( "Invalid type: '" + throwableType.getName() + "'. Has to be a subclass of '" + expectedBaseType.getName() + "'"); } } }





    © 2015 - 2024 Weber Informatics LLC | Privacy Policy