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

org.hibernate.exception.NestableDelegate Maven / Gradle / Ivy

There is a newer version: 3.6.0.Beta2
Show newest version
/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgement may appear in the software itself,
 *    if and wherever such third-party acknowledgements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact [email protected].
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * .
 */
package org.hibernate.exception;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 

A shared implementation of the nestable exception functionality.

*

* The code is shared between * {@link org.apache.commons.lang.exception.NestableError NestableError}, * {@link org.apache.commons.lang.exception.NestableException NestableException} and * {@link org.apache.commons.lang.exception.NestableRuntimeException NestableRuntimeException}. *

* * @author Rafal Krzewski * @author Daniel Rall * @author Kasper Nielsen * @author Steven Caswell * @author Sean C. Sullivan * @author Stephen Colebourne * @version $Id: NestableDelegate.java 4782 2004-11-21 00:11:27Z pgmjsd $ * @since 1.0 */ public class NestableDelegate implements Serializable { /** * Constructor error message. */ private static final String MUST_BE_THROWABLE = "The Nestable implementation passed to the NestableDelegate(Nestable) " + "constructor must extend java.lang.Throwable"; /** * Holds the reference to the exception or error that we're * wrapping (which must be a {@link * org.apache.commons.lang.exception.Nestable} implementation). */ private Throwable nestable = null; /** * Whether to print the stack trace top-down. * This public flag may be set by calling code, typically in initialisation. * * @since 2.0 */ private static boolean topDown = true; /** * Whether to trim the repeated stack trace. * This public flag may be set by calling code, typically in initialisation. * * @since 2.0 */ private static boolean trimStackFrames = true; /** * Constructs a new NestableDelegate instance to manage the * specified Nestable. * * @param nestable the Nestable implementation (must extend * {@link java.lang.Throwable}) * @since 2.0 */ public NestableDelegate(Nestable nestable) { if ( nestable instanceof Throwable ) { this.nestable = ( Throwable ) nestable; } else { throw new IllegalArgumentException( MUST_BE_THROWABLE ); } } /** * Returns the error message of the Throwable in the chain * of Throwables at the specified index, numbererd from 0. * * @param index the index of the Throwable in the chain of * Throwables * @return the error message, or null if the Throwable at the * specified index in the chain does not contain a message * @throws IndexOutOfBoundsException if the index argument is * negative or not less than the count of Throwables in the * chain * @since 2.0 */ public String getMessage(int index) { Throwable t = this.getThrowable( index ); if ( Nestable.class.isInstance( t ) ) { return ( ( Nestable ) t ).getMessage( 0 ); } else { return t.getMessage(); } } /** * Returns the full message contained by the Nestable * and any nested Throwables. * * @param baseMsg the base message to use when creating the full * message. Should be generally be called via * nestableHelper.getMessage( super.getMessage() ), * where super is an instance of {@link * java.lang.Throwable}. * @return The concatenated message for this and all nested * Throwables * @since 2.0 */ public String getMessage(String baseMsg) { StringBuffer msg = new StringBuffer(); if ( baseMsg != null ) { msg.append( baseMsg ); } Throwable nestedCause = ExceptionUtils.getCause( this.nestable ); if ( nestedCause != null ) { String causeMsg = nestedCause.getMessage(); if ( causeMsg != null ) { if ( baseMsg != null ) { msg.append( ": " ); } msg.append( causeMsg ); } } return ( msg.length() > 0 ? msg.toString() : null ); } /** * Returns the error message of this and any nested Throwables * in an array of Strings, one element for each message. Any * Throwable not containing a message is represented in the * array by a null. This has the effect of cause the length of the returned * array to be equal to the result of the {@link #getThrowableCount()} * operation. * * @return the error messages * @since 2.0 */ public String[] getMessages() { Throwable[] throwables = this.getThrowables(); String[] msgs = new String[throwables.length]; for ( int i = 0; i < throwables.length; i++ ) { msgs[i] = Nestable.class.isInstance( throwables[i] ) ? ( ( Nestable ) throwables[i] ).getMessage( 0 ) : throwables[i].getMessage(); } return msgs; } /** * Returns the Throwable in the chain of * Throwables at the specified index, numbererd from 0. * * @param index the index, numbered from 0, of the Throwable in * the chain of Throwables * @return the Throwable * @throws IndexOutOfBoundsException if the index argument is * negative or not less than the count of Throwables in the * chain * @since 2.0 */ public Throwable getThrowable(int index) { if ( index == 0 ) { return this.nestable; } Throwable[] throwables = this.getThrowables(); return throwables[index]; } /** * Returns the number of Throwables contained in the * Nestable contained by this delegate. * * @return the throwable count * @since 2.0 */ public int getThrowableCount() { return ExceptionUtils.getThrowableCount( this.nestable ); } /** * Returns this delegate's Nestable and any nested * Throwables in an array of Throwables, one * element for each Throwable. * * @return the Throwables * @since 2.0 */ public Throwable[] getThrowables() { return ExceptionUtils.getThrowables( this.nestable ); } /** * Returns the index, numbered from 0, of the first Throwable * that matches the specified type in the chain of Throwables * held in this delegate's Nestable with an index greater than * or equal to the specified index, or -1 if the type is not found. * * @param type Class to be found * @param fromIndex the index, numbered from 0, of the starting position in * the chain to be searched * @return index of the first occurrence of the type in the chain, or -1 if * the type is not found * @throws IndexOutOfBoundsException if the fromIndex argument * is negative or not less than the count of Throwables in the * chain * @since 2.0 */ public int indexOfThrowable(Class type, int fromIndex) { if ( fromIndex < 0 ) { throw new IndexOutOfBoundsException( "The start index was out of bounds: " + fromIndex ); } Throwable[] throwables = ExceptionUtils.getThrowables( this.nestable ); if ( fromIndex >= throwables.length ) { throw new IndexOutOfBoundsException( "The start index was out of bounds: " + fromIndex + " >= " + throwables.length ); } for ( int i = fromIndex; i < throwables.length; i++ ) { if ( throwables[i].getClass().equals( type ) ) { return i; } } return -1; } /** * Prints the stack trace of this exception the the standar error * stream. */ public void printStackTrace() { printStackTrace( System.err ); } /** * Prints the stack trace of this exception to the specified * stream. * * @param out PrintStream to use for output. * @see #printStackTrace(PrintWriter) */ public void printStackTrace(PrintStream out) { synchronized ( out ) { PrintWriter pw = new PrintWriter( out, false ); printStackTrace( pw ); // Flush the PrintWriter before it's GC'ed. pw.flush(); } } /** * Prints the stack trace of this exception to the specified * writer. If the Throwable class has a getCause * method (i.e. running on jre1.4 or higher), this method just * uses Throwable's printStackTrace() method. Otherwise, generates * the stack-trace, by taking into account the 'topDown' and * 'trimStackFrames' parameters. The topDown and trimStackFrames * are set to 'true' by default (produces jre1.4-like stack trace). * * @param out PrintWriter to use for output. */ public void printStackTrace(PrintWriter out) { Throwable throwable = this.nestable; // if running on jre1.4 or higher, use default printStackTrace if ( ExceptionUtils.isThrowableNested() ) { if ( throwable instanceof Nestable ) { ( ( Nestable ) throwable ).printPartialStackTrace( out ); } else { throwable.printStackTrace( out ); } return; } // generating the nested stack trace List stacks = new ArrayList(); while ( throwable != null ) { String[] st = getStackFrames( throwable ); stacks.add( st ); throwable = ExceptionUtils.getCause( throwable ); } // If NOT topDown, reverse the stack String separatorLine = "Caused by: "; if ( !topDown ) { separatorLine = "Rethrown as: "; Collections.reverse( stacks ); } // Remove the repeated lines in the stack if ( trimStackFrames ) trimStackFrames( stacks ); synchronized ( out ) { for ( Iterator iter = stacks.iterator(); iter.hasNext(); ) { String[] st = ( String[] ) iter.next(); for ( int i = 0, len = st.length; i < len; i++ ) { out.println( st[i] ); } if ( iter.hasNext() ) out.print( separatorLine ); } } } /** * Captures the stack trace associated with the specified * Throwable object, decomposing it into a list of * stack frames. * * @param t The Throwable. * @return An array of strings describing each stack frame. * @since 2.0 */ protected String[] getStackFrames(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter( sw, true ); // Avoid infinite loop between decompose() and printStackTrace(). if ( t instanceof Nestable ) { ( ( Nestable ) t ).printPartialStackTrace( pw ); } else { t.printStackTrace( pw ); } return ExceptionUtils.getStackFrames( sw.getBuffer().toString() ); } /** * Trims the stack frames. The first set is left untouched. The rest * of the frames are truncated from the bottom by comparing with * one just on top. * * @param stacks The list containing String[] elements * @since 2.0 */ protected void trimStackFrames(List stacks) { for ( int size = stacks.size(), i = size - 1; i > 0; i-- ) { String[] curr = ( String[] ) stacks.get( i ); String[] next = ( String[] ) stacks.get( i - 1 ); List currList = new ArrayList( Arrays.asList( curr ) ); List nextList = new ArrayList( Arrays.asList( next ) ); ExceptionUtils.removeCommonFrames( currList, nextList ); int trimmed = curr.length - currList.size(); if ( trimmed > 0 ) { currList.add( "\t... " + trimmed + " more" ); stacks.set( i, currList.toArray( new String[currList.size()] ) ); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy