Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/Nestable.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/Nestable.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/Nestable.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/Nestable.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,177 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * An interface to be implemented by [EMAIL PROTECTED] java.lang.Throwable} extensions + * which would like to be able to nest root exceptions inside themselves. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Kasper Nielsen</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Steven Caswell</a> + * @author Pete Gieser + * @version $Id: Nestable.java,v 1.11 2004/02/18 22:54:04 ggregory Exp $ + * @since 1.0 + */ +public interface Nestable +{ + + /** + * Returns the reference to the exception or error that caused the exception + * implementing the <code>Nestable</code> to be thrown. + * + * @return throwable that caused the original exception + */ + public Throwable getCause(); + + + /** + * Returns the error message of this and any nested <code>Throwable</code>. + * + * @return the error message + */ + public String getMessage(); + + + /** + * Returns the error message of the <code>Throwable</code> in the chain of + * <code>Throwable</code>s at the specified index, numbered from 0. + * + * @param index the index of the <code>Throwable</code> in the chain of + * <code>Throwable</code>s + * @return the error message, or null if the <code>Throwable</code> at the + * specified index in the chain does not contain a message + * @throws IndexOutOfBoundsException if the <code>index</code> argument is + * negative or not less than the count of + * <code>Throwable</code>s in the chain + */ + public String getMessage( int index ); + + + /** + * Returns the error message of this and any nested <code>Throwable</code>s + * in an array of Strings, one element for each message. Any + * <code>Throwable</code> 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 [EMAIL PROTECTED] #getThrowableCount()} + * operation. + * + * @return the error messages + */ + public String[] getMessages(); + + + /** + * Returns the <code>Throwable</code> in the chain of + * <code>Throwable</code>s at the specified index, numbered from 0. + * + * @param index the index, numbered from 0, of the <code>Throwable</code> in + * the chain of <code>Throwable</code>s + * @return the <code>Throwable</code> + * @throws IndexOutOfBoundsException if the <code>index</code> argument is + * negative or not less than the count of + * <code>Throwable</code>s in the chain + */ + public Throwable getThrowable( int index ); + + + /** + * Returns the number of nested <code>Throwable</code>s represented by this + * <code>Nestable</code>, including this <code>Nestable</code>. + * + * @return the throwable count + */ + public int getThrowableCount(); + + + /** + * Returns this <code>Nestable</code> and any nested <code>Throwable</code>s + * in an array of <code>Throwable</code>s, one element for each + * <code>Throwable</code>. + * + * @return the <code>Throwable</code>s + */ + public Throwable[] getThrowables(); + + + /** + * Returns the index, numbered from 0, of the first occurrence of the + * specified type in the chain of <code>Throwable</code>s, or -1 if the + * specified type is not found in the chain. + * + * @param type <code>Class</code> to be found + * @return index of the first occurrence of the type in the chain, or -1 if + * the type is not found + */ + public int indexOfThrowable( Class type ); + + + /** + * Returns the index, numbered from 0, of the first <code>Throwable</code> + * that matches the specified type in the chain of <code>Throwable</code>s + * with an index greater than or equal to the specified index, or -1 if the + * type is not found. + * + * @param type <code>Class</code> 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 <code>fromIndex</code> argument + * is negative or not less than the count + * of <code>Throwable</code>s in the + * chain + */ + public int indexOfThrowable( Class type, int fromIndex ); + + + /** + * Prints the stack trace of this exception to the specified print writer. + * Includes information from the exception, if any, which caused this + * exception. + * + * @param out <code>PrintWriter</code> to use for output. + */ + public void printStackTrace( PrintWriter out ); + + + /** + * Prints the stack trace of this exception to the specified print stream. + * Includes information from the exception, if any, which caused this + * exception. + * + * @param out <code>PrintStream</code> to use for output. + */ + public void printStackTrace( PrintStream out ); + + + /** + * Prints the stack trace for this exception only--root cause not + * included--using the provided writer. Used by [EMAIL PROTECTED] + * org.apache.commons.lang.exception.NestableDelegate} to write individual + * stack traces to a buffer. The implementation of this method should call + * <code>super.printStackTrace(out);</code> in most cases. + * + * @param out The writer to use. + */ + public void printPartialStackTrace( PrintWriter out ); + +}
Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableDelegate.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableDelegate.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableDelegate.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableDelegate.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,427 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.util.*; + + +/** + * <p>A shared implementation of the nestable exception functionality.</p> + * <p/> + * The code is shared between </p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Rafal Krzewski</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Kasper Nielsen</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Steven Caswell</a> + * @author Sean C. Sullivan + * @author Stephen Colebourne + * @version $Id: NestableDelegate.java,v 1.23 2004/02/18 22:54:04 ggregory Exp + * $ + * @since 1.0 + */ +public class NestableDelegate implements Serializable +{ + + /** + * Constructor error message. + */ + private transient 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 [EMAIL PROTECTED] 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 + */ + public 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 + */ + public static boolean trimStackFrames = true; + + + /** + * Constructs a new <code>NestableDelegate</code> instance to manage the + * specified <code>Nestable</code>. + * + * @param nestable the Nestable implementation (<i>must</i> extend [EMAIL PROTECTED] + * 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 <code>Throwable</code> in the chain of + * <code>Throwable</code>s at the specified index, numbered from 0. + * + * @param index the index of the <code>Throwable</code> in the chain of + * <code>Throwable</code>s + * @return the error message, or null if the <code>Throwable</code> at the + * specified index in the chain does not contain a message + * @throws IndexOutOfBoundsException if the <code>index</code> argument is + * negative or not less than the count of + * <code>Throwable</code>s 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 <code>Nestable</code> and any + * nested <code>Throwable</code>s. + * + * @param baseMsg the base message to use when creating the full message. + * Should be generally be called via <code>nestableHelper.getMessage(super.getMessage())</code>, + * where <code>super</code> is an instance of [EMAIL PROTECTED] + * java.lang.Throwable}. + * @return The concatenated message for this and all nested + * <code>Throwable</code>s + * @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 <code>Throwable</code>s + * in an array of Strings, one element for each message. Any + * <code>Throwable</code> 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 [EMAIL PROTECTED] #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 <code>Throwable</code> in the chain of + * <code>Throwable</code>s at the specified index, numbered from 0. + * + * @param index the index, numbered from 0, of the <code>Throwable</code> in + * the chain of <code>Throwable</code>s + * @return the <code>Throwable</code> + * @throws IndexOutOfBoundsException if the <code>index</code> argument is + * negative or not less than the count of + * <code>Throwable</code>s 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 <code>Throwable</code>s contained in the + * <code>Nestable</code> contained by this delegate. + * + * @return the throwable count + * @since 2.0 + */ + public int getThrowableCount() + { + return ExceptionUtils.getThrowableCount( this.nestable ); + } + + + /** + * Returns this delegate's <code>Nestable</code> and any nested + * <code>Throwable</code>s in an array of <code>Throwable</code>s, one + * element for each <code>Throwable</code>. + * + * @return the <code>Throwable</code>s + * @since 2.0 + */ + public Throwable[] getThrowables() + { + return ExceptionUtils.getThrowables( this.nestable ); + } + + + /** + * Returns the index, numbered from 0, of the first <code>Throwable</code> + * that matches the specified type in the chain of <code>Throwable</code>s + * held in this delegate's <code>Nestable</code> with an index greater than + * or equal to the specified index, or -1 if the type is not found. + * + * @param type <code>Class</code> 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 <code>fromIndex</code> argument + * is negative or not less than the count + * of <code>Throwable</code>s 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 <code>PrintStream</code> 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 <code>getCause</code> 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 <code>PrintWriter</code> 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 + * <code>Throwable</code> object, decomposing it into a list of stack + * frames. + * + * @param t The <code>Throwable</code>. + * @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()] ) ); + } + } + } +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableError.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableError.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableError.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableError.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,196 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * The base class of all errors which can contain other exceptions. + * + * @author <a href="mailto:[email protected]">Daniel Rall</a> + * @version $Id: NestableError.java,v 1.8 2004/02/18 22:54:04 ggregory Exp $ + * @since 1.0 + */ +public class NestableError extends Error implements Nestable +{ + + /** + * The helper instance which contains much of the code which we delegate + * to. + */ + protected NestableDelegate delegate = new NestableDelegate( this ); + + /** + * Holds the reference to the exception or error that caused this exception + * to be thrown. + */ + private Throwable cause = null; + + + /** + * Constructs a new <code>NestableError</code> without specified detail + * message. + */ + public NestableError() + { + super(); + } + + + /** + * Constructs a new <code>NestableError</code> with specified detail + * message. + * + * @param msg The error message. + */ + public NestableError( String msg ) + { + super( msg ); + } + + + /** + * Constructs a new <code>NestableError</code> with specified nested + * <code>Throwable</code>. + * + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableError( Throwable cause ) + { + super(); + this.cause = cause; + } + + + /** + * Constructs a new <code>NestableError</code> with specified detail message + * and nested <code>Throwable</code>. + * + * @param msg the error message + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableError( String msg, Throwable cause ) + { + super( msg ); + this.cause = cause; + } + + + public Throwable getCause() + { + return cause; + } + + + /** + * Returns the detail message string of this throwable. If it was created + * with a null message, returns the following: (cause==null ? null : + * cause.toString()). + */ + public String getMessage() + { + if ( super.getMessage() != null ) + { + return super.getMessage(); + } + else if ( cause != null ) + { + return cause.toString(); + } + else + { + return null; + } + } + + + public String getMessage( int index ) + { + if ( index == 0 ) + { + return super.getMessage(); + } + else + { + return delegate.getMessage( index ); + } + } + + + public String[] getMessages() + { + return delegate.getMessages(); + } + + + public Throwable getThrowable( int index ) + { + return delegate.getThrowable( index ); + } + + + public int getThrowableCount() + { + return delegate.getThrowableCount(); + } + + + public Throwable[] getThrowables() + { + return delegate.getThrowables(); + } + + + public int indexOfThrowable( Class type ) + { + return delegate.indexOfThrowable( type, 0 ); + } + + + public int indexOfThrowable( Class type, int fromIndex ) + { + return delegate.indexOfThrowable( type, fromIndex ); + } + + + public void printStackTrace() + { + delegate.printStackTrace(); + } + + + public void printStackTrace( PrintStream out ) + { + delegate.printStackTrace( out ); + } + + + public void printStackTrace( PrintWriter out ) + { + delegate.printStackTrace( out ); + } + + + public final void printPartialStackTrace( PrintWriter out ) + { + super.printStackTrace( out ); + } +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableException.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableException.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableException.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableException.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,257 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * The base class of all exceptions which can contain other exceptions. + * <p/> + * It is intended to ease the debugging by carrying on the information about the + * exception which was caught and provoked throwing the current exception. + * Catching and rethrowing may occur multiple times, and provided that all + * exceptions except the first one are descendants of <code>NestedException</code>, + * when the exception is finally printed out using any of the <code> + * printStackTrace()</code> methods, the stack trace will contain the + * information about all exceptions thrown and caught on the way. <p> Running + * the following program + * <p><blockquote><pre> + * 1 import org.apache.commons.lang.exception.NestableException; + * 2 + * 3 public class Test { + * 4 public static void main( String[] args ) { + * 5 try { + * 6 a(); + * 7 } catch(Exception e) { + * 8 e.printStackTrace(); + * 9 } + * 10 } + * 11 + * 12 public static void a() throws Exception { + * 13 try { + * 14 b(); + * 15 } catch(Exception e) { + * 16 throw new NestableException("foo", e); + * 17 } + * 18 } + * 19 + * 20 public static void b() throws Exception { + * 21 try { + * 22 c(); + * 23 } catch(Exception e) { + * 24 throw new NestableException("bar", e); + * 25 } + * 26 } + * 27 + * 28 public static void c() throws Exception { + * 29 throw new Exception("baz"); + * 30 } + * 31 } + * </pre></blockquote> + * <p>Yields the following stack trace: + * <p><blockquote><pre> + * org.apache.commons.lang.exception.NestableException: foo + * at Test.a(Test.java:16) + * at Test.main(Test.java:6) + * Caused by: org.apache.commons.lang.exception.NestableException: bar + * at Test.b(Test.java:24) + * at Test.a(Test.java:14) + * ... 1 more + * Caused by: java.lang.Exception: baz + * at Test.c(Test.java:29) + * at Test.b(Test.java:22) + * ... 2 more + * </pre></blockquote><br> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Rafal Krzewski</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Kasper Nielsen</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Steven Caswell</a> + * @version $Id: NestableException.java,v 1.12 2004/08/04 18:41:09 ggregory Exp + * $ + * @since 1.0 + */ +public class NestableException extends Exception implements Nestable +{ + + /** + * The helper instance which contains much of the code which we delegate + * to. + */ + protected NestableDelegate delegate = new NestableDelegate( this ); + + /** + * Holds the reference to the exception or error that caused this exception + * to be thrown. + */ + private Throwable cause = null; + + + /** + * Constructs a new <code>NestableException</code> without specified detail + * message. + */ + public NestableException() + { + super(); + } + + + /** + * Constructs a new <code>NestableException</code> with specified detail + * message. + * + * @param msg The error message. + */ + public NestableException( String msg ) + { + super( msg ); + } + + + /** + * Constructs a new <code>NestableException</code> with specified nested + * <code>Throwable</code>. + * + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableException( Throwable cause ) + { + super(); + this.cause = cause; + } + + + /** + * Constructs a new <code>NestableException</code> with specified detail + * message and nested <code>Throwable</code>. + * + * @param msg the error message + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableException( String msg, Throwable cause ) + { + super( msg ); + this.cause = cause; + } + + + public Throwable getCause() + { + return cause; + } + + + /** + * Returns the detail message string of this throwable. If it was created + * with a null message, returns the following: (cause==null ? null : + * cause.toString()). + */ + public String getMessage() + { + if ( super.getMessage() != null ) + { + return super.getMessage(); + } + else if ( cause != null ) + { + return cause.toString(); + } + else + { + return null; + } + } + + + public String getMessage( int index ) + { + if ( index == 0 ) + { + return super.getMessage(); + } + else + { + return delegate.getMessage( index ); + } + } + + + public String[] getMessages() + { + return delegate.getMessages(); + } + + + public Throwable getThrowable( int index ) + { + return delegate.getThrowable( index ); + } + + + public int getThrowableCount() + { + return delegate.getThrowableCount(); + } + + + public Throwable[] getThrowables() + { + return delegate.getThrowables(); + } + + + public int indexOfThrowable( Class type ) + { + return delegate.indexOfThrowable( type, 0 ); + } + + + public int indexOfThrowable( Class type, int fromIndex ) + { + return delegate.indexOfThrowable( type, fromIndex ); + } + + + public void printStackTrace() + { + delegate.printStackTrace(); + } + + + public void printStackTrace( PrintStream out ) + { + delegate.printStackTrace( out ); + } + + + public void printStackTrace( PrintWriter out ) + { + delegate.printStackTrace( out ); + } + + + public final void printPartialStackTrace( PrintWriter out ) + { + super.printStackTrace( out ); + } + +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableRuntimeException.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableRuntimeException.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableRuntimeException.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/NestableRuntimeException.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,201 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * The base class of all runtime exceptions which can contain other exceptions. + * + * @author <a href="mailto:[EMAIL PROTECTED]">Rafal Krzewski</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Kasper Nielsen</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Steven Caswell</a> + * @version $Id: NestableRuntimeException.java,v 1.10 2004/02/18 22:54:04 + * ggregory Exp $ + * @since 1.0 + */ +public class NestableRuntimeException extends RuntimeException implements Nestable +{ + + /** + * The helper instance which contains much of the code which we delegate + * to. + */ + protected NestableDelegate delegate = new NestableDelegate( this ); + + /** + * Holds the reference to the exception or error that caused this exception + * to be thrown. + */ + private Throwable cause = null; + + + /** + * Constructs a new <code>NestableRuntimeException</code> without specified + * detail message. + */ + public NestableRuntimeException() + { + super(); + } + + + /** + * Constructs a new <code>NestableRuntimeException</code> with specified + * detail message. + * + * @param msg the error message + */ + public NestableRuntimeException( String msg ) + { + super( msg ); + } + + + /** + * Constructs a new <code>NestableRuntimeException</code> with specified + * nested <code>Throwable</code>. + * + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableRuntimeException( Throwable cause ) + { + super(); + this.cause = cause; + } + + + /** + * Constructs a new <code>NestableRuntimeException</code> with specified + * detail message and nested <code>Throwable</code>. + * + * @param msg the error message + * @param cause the exception or error that caused this exception to be + * thrown + */ + public NestableRuntimeException( String msg, Throwable cause ) + { + super( msg ); + this.cause = cause; + } + + + public Throwable getCause() + { + return cause; + } + + + /** + * Returns the detail message string of this throwable. If it was created + * with a null message, returns the following: (cause==null ? null : + * cause.toString()). + */ + public String getMessage() + { + if ( super.getMessage() != null ) + { + return super.getMessage(); + } + else if ( cause != null ) + { + return cause.toString(); + } + else + { + return null; + } + } + + + public String getMessage( int index ) + { + if ( index == 0 ) + { + return super.getMessage(); + } + else + { + return delegate.getMessage( index ); + } + } + + + public String[] getMessages() + { + return delegate.getMessages(); + } + + + public Throwable getThrowable( int index ) + { + return delegate.getThrowable( index ); + } + + + public int getThrowableCount() + { + return delegate.getThrowableCount(); + } + + + public Throwable[] getThrowables() + { + return delegate.getThrowables(); + } + + + public int indexOfThrowable( Class type ) + { + return delegate.indexOfThrowable( type, 0 ); + } + + + public int indexOfThrowable( Class type, int fromIndex ) + { + return delegate.indexOfThrowable( type, fromIndex ); + } + + + public void printStackTrace() + { + delegate.printStackTrace(); + } + + + public void printStackTrace( PrintStream out ) + { + delegate.printStackTrace( out ); + } + + + public void printStackTrace( PrintWriter out ) + { + delegate.printStackTrace( out ); + } + + + public final void printPartialStackTrace( PrintWriter out ) + { + super.printStackTrace( out ); + } + +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ObjectUtils.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ObjectUtils.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ObjectUtils.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ObjectUtils.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,305 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.io.Serializable; + + +/** + * <p>Operations on <code>Object</code>.</p> + * <p/> + * <p>This class tries to handle <code>null</code> input gracefully. An + * exception will generally not be thrown for a <code>null</code> input. Each + * method documents its behaviour in more detail.</p> + * + * @author <a href="mailto:[EMAIL PROTECTED]">Nissim Karpenstein</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Janek Bogucki</a> + * @author <a href="mailto:[email protected]">Daniel Rall</a> + * @author Stephen Colebourne + * @author Gary Gregory + * @author Mario Winterer + * @version $Id: ObjectUtils.java,v 1.24 2004/06/01 21:08:48 scolebourne Exp $ + * @since 1.0 + */ +public class ObjectUtils +{ + + /** + * <p>Singleton used as a <code>null</code> placeholder where + * <code>null</code> has another meaning.</p> + * <p/> + * <p>For example, in a <code>HashMap</code> the [EMAIL PROTECTED] + * java.util.HashMap#get(java.lang.Object)} method returns <code>null</code> + * if the <code>Map</code> contains <code>null</code> or if there is no + * matching key. The <code>Null</code> placeholder can be used to + * distinguish between these two cases.</p> + * <p/> + * <p>Another example is <code>Hashtable</code>, where <code>null</code> + * cannot be stored.</p> + * <p/> + * <p>This instance is Serializable.</p> + */ + public static final Null NULL = new Null(); + + + /** + * <p><code>ObjectUtils</code> instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * <code>ObjectUtils.defaultIfNull("a","b");</code>.</p> + * <p/> + * <p>This constructor is public to permit tools that require a JavaBean + * instance to operate.</p> + */ + public ObjectUtils() + { + } + + // Defaulting + //----------------------------------------------------------------------- + /** + * <p>Returns a default value if the object passed is + * <code>null</code>.</p> + * <p/> + * <pre> + * ObjectUtils.defaultIfNull(null, null) = null + * ObjectUtils.defaultIfNull(null, "") = "" + * ObjectUtils.defaultIfNull(null, "zz") = "zz" + * ObjectUtils.defaultIfNull("abc", *) = "abc" + * ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE + * </pre> + * + * @param object the <code>Object</code> to test, may be + * <code>null</code> + * @param defaultValue the default value to return, may be <code>null</code> + * @return <code>object</code> if it is not <code>null</code>, defaultValue + * otherwise + */ + public static Object defaultIfNull( Object object, Object defaultValue ) + { + return ( object != null ? object : defaultValue ); + } + + + /** + * <p>Compares two objects for equality, where either one or both objects + * may be <code>null</code>.</p> + * <p/> + * <pre> + * ObjectUtils.equals(null, null) = true + * ObjectUtils.equals(null, "") = false + * ObjectUtils.equals("", null) = false + * ObjectUtils.equals("", "") = true + * ObjectUtils.equals(Boolean.TRUE, null) = false + * ObjectUtils.equals(Boolean.TRUE, "true") = false + * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true + * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false + * </pre> + * + * @param object1 the first object, may be <code>null</code> + * @param object2 the second object, may be <code>null</code> + * @return <code>true</code> if the values of both objects are the same + */ + public static boolean equals( Object object1, Object object2 ) + { + if ( object1 == object2 ) + { + return true; + } + if ( ( object1 == null ) || ( object2 == null ) ) + { + return false; + } + return object1.equals( object2 ); + } + + + /** + * <p>Gets the hash code of an object returning zero when the object is + * <code>null</code>.</p> + * <p/> + * <pre> + * ObjectUtils.hashCode(null) = 0 + * ObjectUtils.hashCode(obj) = obj.hashCode() + * </pre> + * + * @param obj the object to obtain the hash code of, may be + * <code>null</code> + * @return the hash code of the object, or zero if null + * @since 2.1 + */ + public static int hashCode( Object obj ) + { + return ( ( obj == null ) ? 0 : obj.hashCode() ); + } + + // Identity ToString + //----------------------------------------------------------------------- + /** + * <p>Gets the toString that would be produced by <code>Object</code> if a + * class did not override toString itself. <code>null</code> will return + * <code>null</code>.</p> + * <p/> + * <pre> + * ObjectUtils.identityToString(null) = null + * ObjectUtils.identityToString("") = "[EMAIL PROTECTED]" + * ObjectUtils.identityToString(Boolean.TRUE) = "[EMAIL PROTECTED]" + * </pre> + * + * @param object the object to create a toString for, may be + * <code>null</code> + * @return the default toString text, or <code>null</code> if + * <code>null</code> passed in + */ + public static String identityToString( Object object ) + { + if ( object == null ) + { + return null; + } + return appendIdentityToString( null, object ).toString(); + } + + + /** + * <p>Appends the toString that would be produced by <code>Object</code> if + * a class did not override toString itself. <code>null</code> will return + * <code>null</code>.</p> + * <p/> + * <pre> + * ObjectUtils.appendIdentityToString(*, null) = null + * ObjectUtils.appendIdentityToString(null, "") = + * "[EMAIL PROTECTED]" + * ObjectUtils.appendIdentityToString(null, Boolean.TRUE) = + * "[EMAIL PROTECTED]" + * ObjectUtils.appendIdentityToString(buf, Boolean.TRUE) = + * buf.append("[EMAIL PROTECTED]") + * </pre> + * + * @param buffer the buffer to append to, may be <code>null</code> + * @param object the object to create a toString for, may be + * <code>null</code> + * @return the default toString text, or <code>null</code> if + * <code>null</code> passed in + * @since 2.0 + */ + public static StringBuffer appendIdentityToString( StringBuffer buffer, Object object ) + { + if ( object == null ) + { + return null; + } + if ( buffer == null ) + { + buffer = new StringBuffer(); + } + return buffer + .append( object.getClass().getName() ) + .append( '@' ) + .append( Integer.toHexString( System.identityHashCode( object ) ) ); + } + + // ToString + //----------------------------------------------------------------------- + /** + * <p>Gets the <code>toString</code> of an <code>Object</code> returning an + * empty string ("") if <code>null</code> input.</p> + * <p/> + * <pre> + * ObjectUtils.toString(null) = "" + * ObjectUtils.toString("") = "" + * ObjectUtils.toString("bat") = "bat" + * ObjectUtils.toString(Boolean.TRUE) = "true" + * </pre> + * + * @param obj the Object to <code>toString</code>, may be null + * @return the passed in Object's toString, or nullStr if <code>null</code> + * input + * @see String#valueOf(Object) + * @since 2.0 + */ + public static String toString( Object obj ) + { + return ( obj == null ? "" : obj.toString() ); + } + + + /** + * <p>Gets the <code>toString</code> of an <code>Object</code> returning a + * specified text if <code>null</code> input.</p> + * <p/> + * <pre> + * ObjectUtils.toString(null, null) = null + * ObjectUtils.toString(null, "null") = "null" + * ObjectUtils.toString("", "null") = "" + * ObjectUtils.toString("bat", "null") = "bat" + * ObjectUtils.toString(Boolean.TRUE, "null") = "true" + * </pre> + * + * @param obj the Object to <code>toString</code>, may be null + * @param nullStr the String to return if <code>null</code> input, may be + * null + * @return the passed in Object's toString, or nullStr if <code>null</code> + * input + * @see String#valueOf(Object) + * @since 2.0 + */ + public static String toString( Object obj, String nullStr ) + { + return ( obj == null ? nullStr : obj.toString() ); + } + + // Null + //----------------------------------------------------------------------- + /** + * <p>Class used as a null placeholder where <code>null</code> has another + * meaning.</p> + * <p/> + * <p>For example, in a <code>HashMap</code> the [EMAIL PROTECTED] + * java.util.HashMap#get(java.lang.Object)} method returns <code>null</code> + * if the <code>Map</code> contains <code>null</code> or if there is no + * matching key. The <code>Null</code> placeholder can be used to + * distinguish between these two cases.</p> + * <p/> + * <p>Another example is <code>Hashtable</code>, where <code>null</code> + * cannot be stored.</p> + */ + public static class Null implements Serializable + { + // declare serialization compatibility with Commons Lang 1.0 + private static final long serialVersionUID = 7092611880189329093L; + + + /** + * Restricted constructor - singleton. + */ + Null() + { + } + + + /** + * <p>Ensure singleton.</p> + * + * @return the singleton value + */ + private Object readResolve() + { + return ObjectUtils.NULL; + } + } + +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/RandomStringUtils.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/RandomStringUtils.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/RandomStringUtils.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/RandomStringUtils.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,334 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.util.Random; + + +/** + * <p>Operations for random <code>String</code>s.</p> + * + * @author GenerationJava Core library + * @author <a href="mailto:[EMAIL PROTECTED]">Henri Yandell</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Steven Caswell</a> + * @author Stephen Colebourne + * @author Gary Gregory + * @author Phil Steitz + * @version $Id: RandomStringUtils.java,v 1.27 2004/02/18 22:59:49 ggregory Exp + * $ + * @since 1.0 + */ +public class RandomStringUtils +{ + + /** + * <p>Random object used by random method. This has to be not local to the + * random method so as to not return the same value in the same + * millisecond.</p> + */ + private static final Random RANDOM = new Random(); + + + /** + * <p><code>RandomStringUtils</code> instances should NOT be constructed in + * standard programming. Instead, the class should be used as + * <code>RandomStringUtils.random(5);</code>.</p> + * <p/> + * <p>This constructor is public to permit tools that require a JavaBean + * instance to operate.</p> + */ + public RandomStringUtils() + { + } + + // Random + //----------------------------------------------------------------------- + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of all characters.</p> + * + * @param count the length of random string to create + * @return the random string + */ + public static String random( int count ) + { + return random( count, false, false ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of characters whose ASCII value + * is between <code>32</code> and <code>126</code> (inclusive).</p> + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAscii( int count ) + { + return random( count, 32, 127, false, false ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of alphabetic characters.</p> + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAlphabetic( int count ) + { + return random( count, true, false ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of alpha-numeric + * characters.</p> + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomAlphanumeric( int count ) + { + return random( count, true, true ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of numeric characters.</p> + * + * @param count the length of random string to create + * @return the random string + */ + public static String randomNumeric( int count ) + { + return random( count, false, true ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of alpha-numeric characters as + * indicated by the arguments.</p> + * + * @param count the length of random string to create + * @param letters if <code>true</code>, generated string will include + * alphabetic characters + * @param numbers if <code>true</code>, generated string will include + * numeric characters + * @return the random string + */ + public static String random( int count, boolean letters, boolean numbers ) + { + return random( count, 0, 0, letters, numbers ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of alpha-numeric characters as + * indicated by the arguments.</p> + * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if <code>true</code>, generated string will include + * alphabetic characters + * @param numbers if <code>true</code>, generated string will include + * numeric characters + * @return the random string + */ + public static String random( int count, int start, int end, boolean letters, boolean numbers ) + { + return random( count, start, end, letters, numbers, null, RANDOM ); + } + + + /** + * <p>Creates a random string based on a variety of options, using default + * source of randomness.</p> + * <p/> + * <p>This method has exactly the same semantics as [EMAIL PROTECTED] + * #random(int,int,int,boolean,boolean,char[],Random)}, but instead of using + * an externally supplied source of randomness, it uses the internal static + * [EMAIL PROTECTED] Random} instance.</p> + * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters only allow letters? + * @param numbers only allow numbers? + * @param chars the set of chars to choose randoms from. If + * <code>null</code>, then it will use the set of all chars. + * @return the random string + * @throws ArrayIndexOutOfBoundsException if there are not <code>(end - + * start) + 1</code> characters in + * the set array. + */ + public static String random( int count, int start, int end, boolean letters, boolean numbers, char[] chars ) + { + return random( count, start, end, letters, numbers, chars, RANDOM ); + } + + + /** + * <p>Creates a random string based on a variety of options, using supplied + * source of randomness.</p> + * <p/> + * <p>If start and end are both <code>0</code>, start and end are set to + * <code>' '</code> and <code>'z'</code>, the ASCII printable characters, + * will be used, unless letters and numbers are both <code>false</code>, in + * which case, start and end are set to <code>0</code> and + * <code>Integer.MAX_VALUE</code>. + * <p/> + * <p>If set is not <code>null</code>, characters between start and end are + * chosen.</p> + * <p/> + * <p>This method accepts a user-supplied [EMAIL PROTECTED] Random} instance to use as + * a source of randomness. By seeding a single [EMAIL PROTECTED] Random} instance with + * a fixed seed and using it for each call, the same random sequence of + * strings can be generated repeatedly and predictably.</p> + * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters only allow letters? + * @param numbers only allow numbers? + * @param chars the set of chars to choose randoms from. If + * <code>null</code>, then it will use the set of all chars. + * @param random a source of randomness. + * @return the random string + * @throws ArrayIndexOutOfBoundsException if there are not <code>(end - + * start) + 1</code> characters in + * the set array. + * @throws IllegalArgumentException if <code>count</code> < 0. + * @since 2.0 + */ + public static String random( int count, int start, int end, boolean letters, boolean numbers, + char[] chars, Random random ) + { + if ( count == 0 ) + { + return ""; + } + else if ( count < 0 ) + { + throw new IllegalArgumentException( "Requested random string length " + count + " is less than 0." ); + } + if ( ( start == 0 ) && ( end == 0 ) ) + { + end = 'z' + 1; + start = ' '; + if ( !letters && !numbers ) + { + start = 0; + end = Integer.MAX_VALUE; + } + } + + StringBuffer buffer = new StringBuffer(); + int gap = end - start; + + while ( count-- != 0 ) + { + char ch; + if ( chars == null ) + { + ch = ( char ) ( random.nextInt( gap ) + start ); + } + else + { + ch = chars[random.nextInt( gap ) + start]; + } + if ( ( letters && numbers && Character.isLetterOrDigit( ch ) ) + || ( letters && Character.isLetter( ch ) ) + || ( numbers && Character.isDigit( ch ) ) + || ( !letters && !numbers ) ) + { + buffer.append( ch ); + } + else + { + count++; + } + } + return buffer.toString(); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of characters specified.</p> + * + * @param count the length of random string to create + * @param chars the String containing the set of characters to use, may be + * null + * @return the random string + * @throws IllegalArgumentException if <code>count</code> < 0. + */ + public static String random( int count, String chars ) + { + if ( chars == null ) + { + return random( count, 0, 0, false, false, null, RANDOM ); + } + return random( count, chars.toCharArray() ); + } + + + /** + * <p>Creates a random string whose length is the number of characters + * specified.</p> + * <p/> + * <p>Characters will be chosen from the set of characters specified.</p> + * + * @param count the length of random string to create + * @param chars the character array containing the set of characters to use, + * may be null + * @return the random string + * @throws IllegalArgumentException if <code>count</code> < 0. + */ + public static String random( int count, char[] chars ) + { + if ( chars == null ) + { + return random( count, 0, 0, false, false, null, RANDOM ); + } + return random( count, 0, chars.length, false, false, chars, RANDOM ); + } + +} Added: incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ReflectionToStringBuilder.java URL: http://svn.apache.org/viewcvs/incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ReflectionToStringBuilder.java?view=auto&rev=151131 ============================================================================== --- incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ReflectionToStringBuilder.java (added) +++ incubator/directory/asn1/branches/rewrite/ber/src/java/org/apache/asn1/util/ReflectionToStringBuilder.java Wed Feb 2 23:18:42 2005 @@ -0,0 +1,729 @@ +/* + * Copyright 2002-2004 The Apache Software Foundation. + * + * 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. + */ +package org.apache.asn1.util; + + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; + + +/** + * <p/> + * Assists in implementing [EMAIL PROTECTED] Object#toString()}methods using reflection. + * </p> + * <p/> + * <p/> + * This class uses reflection to determine the fields to append. Because these + * fields are usually private, the class uses [EMAIL PROTECTED] java.lang.reflect.AccessibleObject#setAccessible(java.lang.reflect.AccessibleObject[], + * boolean)} to change the visibility of the fields. This will fail under a + * security manager, unless the appropriate permissions are set up correctly. + * </p> + * <p/> + * <p/> + * A typical invocation for this method would look like: </p> + * <p/> + * <pre> + * public String toString() { + * return ReflectionToStringBuilder.toString(this); + * }</pre> + * <p/> + * <p/> + * <p/> + * <p/> + * You can also use the builder to debug 3rd party objects: </p> + * <p/> + * <pre> + * System.out.println("An object: " + ReflectionToStringBuilder.toString(anObject));</pre> + * <p/> + * <p/> + * <p/> + * <p/> + * A subclass can control field output by overriding the methods: <ul> + * <li>[EMAIL PROTECTED] #accept(java.lang.reflect.Field)}</li> <li>[EMAIL PROTECTED] + * #getValue(java.lang.reflect.Field)}</li> </ul> </p> + * <p/> + * For example, this method does <i>not</i> include the <code>password</code> + * field in the returned <code>String</code>: </p> + * <p/> + * <pre> + * public String toString() { + * return (new ReflectionToStringBuilder(this) { + * protected boolean accept(Field f) { + * return super.accept(f) && !f.getName().equals("password"); + * } + * }).toString(); + * }</pre> + * <p/> + * <p/> + * <p/> + * <p/> + * The exact format of the <code>toString</code> is determined by the [EMAIL PROTECTED] + * ToStringStyle} passed into the constructor. </p> + * + * @author Gary Gregory + * @author Stephen Colebourne + * @author Pete Gieser + * @version $Id: ReflectionToStringBuilder.java,v 1.15 2003/12/02 19:11:58 + * ggregory Exp $ + * @since 2.0 + */ +public class ReflectionToStringBuilder extends ToStringBuilder +{ + /** + * <p/> + * A registry of objects used by <code>reflectionToString</code> methods to + * detect cyclical object references and avoid infinite loops. </p> + */ + private static ThreadLocal registry = new ThreadLocal() + { + protected synchronized Object initialValue() + { + // The HashSet implementation is not synchronized, + // which is just what we need here. + return new HashSet(); + } + }; + + + /** + * <p/> + * Returns the registry of objects being traversed by the + * <code>reflectionToString</code> methods in the current thread. </p> + * + * @return Set the registry of objects being traversed + */ + static Set getRegistry() + { + return ( Set ) registry.get(); + } + + + /** + * <p/> + * Returns <code>true</code> if the registry contains the given object. Used + * by the reflection methods to avoid infinite loops. </p> + * + * @param value The object to lookup in the registry. + * @return boolean <code>true</code> if the registry contains the given + * object. + */ + static boolean isRegistered( Object value ) + { + return getRegistry().contains( value ); + } + + + /** + * <p/> + * Registers the given object. Used by the reflection methods to avoid + * infinite loops. </p> + * + * @param value The object to register. + */ + static void register( Object value ) + { + getRegistry().add( value ); + } + + + /** + * <p/> + * This method uses reflection to build a suitable <code>toString</code> + * using the default <code>ToStringStyle</code>. + * <p/> + * <p/> + * It uses <code>AccessibleObject.setAccessible</code> to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. </p> + * <p/> + * <p/> + * Transient members will be not be included, as they are likely derived. + * Static fields will not be included. Superclass fields will be appended. + * </p> + * + * @param object the Object to be output + * @return the String result + * @throws IllegalArgumentException if the Object is <code>null</code> + */ + public static String toString( Object object ) + { + return toString( object, null, false, false, null ); + } + + + /** + * <p/> + * This method uses reflection to build a suitable <code>toString</code>. + * </p> + * <p/> + * <p/> + * It uses <code>AccessibleObject.setAccessible</code> to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. </p> + * <p/> + * <p/> + * Transient members will be not be included, as they are likely derived. + * Static fields will not be included. Superclass fields will be appended. + * </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default <code>ToStringStyle</code> + * is used. </p> + * + * @param object the Object to be output + * @param style the style of the <code>toString</code> to create, may be + * <code>null</code> + * @return the String result + * @throws IllegalArgumentException if the Object or <code>ToStringStyle</code> + * is <code>null</code> + */ + public static String toString( Object object, ToStringStyle style ) + { + return toString( object, style, false, false, null ); + } + + + /** + * <p/> + * This method uses reflection to build a suitable <code>toString</code>. + * </p> + * <p/> + * <p/> + * It uses <code>AccessibleObject.setAccessible</code> to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. </p> + * <p/> + * <p/> + * If the <code>outputTransients</code> is <code>true</code>, transient + * members will be output, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. </p> + * <p/> + * <p/> + * Static fields will not be included. Superclass fields will be appended. + * </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default <code>ToStringStyle</code> + * is used. </p> + * + * @param object the Object to be output + * @param style the style of the <code>toString</code> to create, + * may be <code>null</code> + * @param outputTransients whether to include transient fields + * @return the String result + * @throws IllegalArgumentException if the Object is <code>null</code> + */ + public static String toString( Object object, ToStringStyle style, boolean outputTransients ) + { + return toString( object, style, outputTransients, false, null ); + } + + + /** + * <p/> + * This method uses reflection to build a suitable <code>toString</code>. + * </p> + * <p/> + * <p/> + * It uses <code>AccessibleObject.setAccessible</code> to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. </p> + * <p/> + * <p/> + * If the <code>outputTransients</code> is <code>true</code>, transient + * fields will be output, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. </p> + * <p/> + * <p/> + * If the <code>outputStatics</code> is <code>true</code>, static fields + * will be output, otherwise they are ignored. </p> + * <p/> + * <p/> + * Static fields will not be included. Superclass fields will be appended. + * </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default <code>ToStringStyle</code> + * is used. </p> + * + * @param object the Object to be output + * @param style the style of the <code>toString</code> to create, + * may be <code>null</code> + * @param outputTransients whether to include transient fields + * @param outputStatics whether to include transient fields + * @return the String result + * @throws IllegalArgumentException if the Object is <code>null</code> + */ + public static String toString( Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics ) + { + return toString( object, style, outputTransients, outputStatics, null ); + } + + + /** + * <p/> + * This method uses reflection to build a suitable <code>toString</code>. + * </p> + * <p/> + * <p/> + * It uses <code>AccessibleObject.setAccessible</code> to gain access to + * private fields. This means that it will throw a security exception if run + * under a security manager, if the permissions are not set up correctly. It + * is also not as efficient as testing explicitly. </p> + * <p/> + * <p/> + * If the <code>outputTransients</code> is <code>true</code>, transient + * fields will be output, otherwise they are ignored, as they are likely + * derived fields, and not part of the value of the Object. </p> + * <p/> + * <p/> + * If the <code>outputStatics</code> is <code>true</code>, static fields + * will be output, otherwise they are ignored. </p> + * <p/> + * <p/> + * Superclass fields will be appended up to and including the specified + * superclass. A null superclass is treated as <code>java.lang.Object</code>. + * </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default <code>ToStringStyle</code> + * is used. </p> + * + * @param object the Object to be output + * @param style the style of the <code>toString</code> to create, + * may be <code>null</code> + * @param outputTransients whether to include transient fields + * @param outputStatics whether to include static fields + * @param reflectUpToClass the superclass to reflect up to (inclusive), may + * be <code>null</code> + * @return the String result + * @throws IllegalArgumentException if the Object is <code>null</code> + */ + public static String toString( Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics, + Class reflectUpToClass ) + { + return new ReflectionToStringBuilder( object, style, null, reflectUpToClass, outputTransients, outputStatics ) + .toString(); + } + + + /** + * <p/> + * Unregisters the given object. </p> + * <p/> + * <p/> + * Used by the reflection methods to avoid infinite loops. </p> + * + * @param value The object to unregister. + */ + static void unregister( Object value ) + { + getRegistry().remove( value ); + } + + + /** + * Whether or not to append static fields. + */ + private boolean appendStatics = false; + + /** + * Whether or not to append transient fields. + */ + private boolean appendTransients = false; + + /** + * The last super class to stop appending fields for. + */ + private Class upToClass = null; + + + /** + * <p/> + * Constructor. </p> + * <p/> + * <p/> + * This constructor outputs using the default style set with + * <code>setDefaultStyle</code>. </p> + * + * @param object the Object to build a <code>toString</code> for, must not + * be <code>null</code> + * @throws IllegalArgumentException if the Object passed in is <code>null</code> + */ + public ReflectionToStringBuilder( Object object ) + { + super( object ); + } + + + /** + * <p/> + * Constructor. </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default style is used. </p> + * + * @param object the Object to build a <code>toString</code> for, must not + * be <code>null</code> + * @param style the style of the <code>toString</code> to create, may be + * <code>null</code> + * @throws IllegalArgumentException if the Object passed in is <code>null</code> + */ + public ReflectionToStringBuilder( Object object, ToStringStyle style ) + { + super( object, style ); + } + + + /** + * <p/> + * Constructor. </p> + * <p/> + * <p/> + * If the style is <code>null</code>, the default style is used. </p> + * <p/> + * <p/> + * If the buffer is <code>null</code>, a new one is created. </p> + * + * @param object the Object to build a <code>toString</code> for + * @param style the style of the <code>toString</code> to create, may be + * <code>null</code> + * @param buffer the <code>StringBuffer</code> to populate, may be + * <code>null</code> + * @throws IllegalArgumentException if the Object passed in is <code>null</code> + */ + public ReflectionToStringBuilder( Object object, ToStringStyle style, StringBuffer buffer ) + { + super( object, style, buffer ); + } + + + /** + * Constructor. + * + * @param object the Object to build a <code>toString</code> for + * @param style the style of the <code>toString</code> to create, + * may be <code>null</code> + * @param buffer the <code>StringBuffer</code> to populate, may be + * <code>null</code> + * @param reflectUpToClass the superclass to reflect up to (inclusive), may + * be <code>null</code> + * @param outputTransients whether to include transient fields + * @deprecated Use [EMAIL PROTECTED] #ReflectionToStringBuilder(Object,ToStringStyle,StringBuffer,Class,boolean,boolean)}. + */ + public ReflectionToStringBuilder( Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass, + boolean outputTransients ) + { + super( object, style, buffer ); + this.setUpToClass( reflectUpToClass ); + this.setAppendTransients( outputTransients ); + } + + + /** + * Constructor. + * + * @param object the Object to build a <code>toString</code> for + * @param style the style of the <code>toString</code> to create, + * may be <code>null</code> + * @param buffer the <code>StringBuffer</code> to populate, may be + * <code>null</code> + * @param reflectUpToClass the superclass to reflect up to (inclusive), may + * be <code>null</code> + * @param outputTransients whether to include transient fields + * @param outputStatics whether to include static fields + */ + public ReflectionToStringBuilder( Object object, ToStringStyle style, StringBuffer buffer, Class reflectUpToClass, + boolean outputTransients, boolean outputStatics ) + { + super( object, style, buffer ); + this.setUpToClass( reflectUpToClass ); + this.setAppendTransients( outputTransients ); + this.setAppendStatics( outputStatics ); + } + + + /** + * Returns whether or not to append the given <code>Field</code>. <ul> + * <li>Transient fields are appended only if [EMAIL PROTECTED] #isAppendTransients()} + * returns <code>true</code>. <li>Static fields are appended only if [EMAIL PROTECTED] + * #isAppendStatics()} returns <code>true</code>. <li>Inner class fields are + * not appened.</li> </ul> + * + * @param field The Field to test. + * @return Whether or not to append the given <code>Field</code>. + */ + protected boolean accept( Field field ) + { + if ( field.getName().indexOf( '$' ) != -1 ) + { + // Reject field from inner class. + return false; + } + if ( Modifier.isTransient( field.getModifiers() ) && !this.isAppendTransients() ) + { + // transients. + return false; + } + if ( Modifier.isStatic( field.getModifiers() ) && !this.isAppendStatics() ) + { + // transients. + return false; + } + return true; + } + + + /** + * <p/> + * Appends the fields and values defined by the given object of the given + * Class. </p> + * <p/> + * <p/> + * If a cycle is detected as an object is "toString()'ed", such an + * object is rendered as if <code>Object.toString()</code> had been called + * and not implemented by the object. </p> + * + * @param clazz The class of object parameter + */ + protected void appendFieldsIn( Class clazz ) + { + if ( isRegistered( this.getObject() ) ) + { + // The object has already been appended, therefore we have an + // object cycle. + // Append a simple Object.toString style string. The field name is + // already appended at this point. + this.appendAsObjectToString( this.getObject() ); + return; + } + try + { + this.registerObject(); + if ( clazz.isArray() ) + { + this.reflectionAppendArray( this.getObject() ); + return; + } + Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible( fields, true ); + for ( int i = 0; i < fields.length; i++ ) + { + Field field = fields[i]; + String fieldName = field.getName(); + if ( this.accept( field ) ) + { + try + { + // Warning: Field.get(Object) creates wrappers objects + // for primitive types. + Object fieldValue = this.getValue( field ); + if ( isRegistered( fieldValue ) && !field.getType().isPrimitive() ) + { + // A known field value has already been appended, + // therefore we have an object cycle, + // append a simple Object.toString style string. + this.getStyle().appendFieldStart( this.getStringBuffer(), fieldName ); + this.appendAsObjectToString( fieldValue ); + // The recursion out of + // builder.append(fieldName, fieldValue); + // below will append the field + // end marker. + } + else + { + try + { + this.registerObject(); + this.append( fieldName, fieldValue ); + } + finally + { + this.unregisterObject(); + } + } + } + catch ( IllegalAccessException ex ) + { + //this can't happen. Would get a Security exception + // instead + //throw a runtime exception in case the impossible + // happens. + throw new InternalError( "Unexpected IllegalAccessException: " + ex.getMessage() ); + } + } + } + } + finally + { + this.unregisterObject(); + } + } + + + /** + * <p/> + * Gets the last super class to stop appending fields for. </p> + * + * @return The last super class to stop appending fields for. + */ + public Class getUpToClass() + { + return this.upToClass; + } + + + /** + * <p/> + * Calls <code>java.lang.reflect.Field.get(Object)</code>. </p> + * + * @param field The Field to query. + * @return The Object from the given Field. + * @throws IllegalArgumentException see [EMAIL PROTECTED] java.lang.reflect.Field#get(Object)} + * @throws IllegalAccessException see [EMAIL PROTECTED] java.lang.reflect.Field#get(Object)} + * @see java.lang.reflect.Field#get(Object) + */ + protected Object getValue( Field field ) throws IllegalArgumentException, IllegalAccessException + { + return field.get( this.getObject() ); + } + + + /** + * <p/> + * Gets whether or not to append static fields. </p> + * + * @return Whether or not to append static fields. + */ + public boolean isAppendStatics() + { + return this.appendStatics; + } + + + /** + * <p/> + * Gets whether or not to append transient fields. </p> + * + * @return Whether or not to append transient fields. + */ + public boolean isAppendTransients() + { + return this.appendTransients; + } + + + /** + * <p/> + * Append to the <code>toString</code> an <code>Object</code> array. </p> + * + * @param array the array to add to the <code>toString</code> + * @return this + */ + public ToStringBuilder reflectionAppendArray( Object array ) + { + this.getStyle().reflectionAppendArrayDetail( this.getStringBuffer(), null, array ); + return this; + } + + + /** + * <p/> + * Registers this builder's source object to avoid infinite loops when + * processing circular object references. </p> + */ + void registerObject() + { + register( this.getObject() ); + } + + + /** + * <p/> + * Sets whether or not to append static fields. </p> + * + * @param appendStatics Whether or not to append static fields. + */ + public void setAppendStatics( boolean appendStatics ) + { + this.appendStatics = appendStatics; + } + + + /** + * <p/> + * Sets whether or not to append transient fields. </p> + * + * @param appendTransients Whether or not to append transient fields. + */ + public void setAppendTransients( boolean appendTransients ) + { + this.appendTransients = appendTransients; + } + + + /** + * <p/> + * Sets the last super class to stop appending fields for. </p> + * + * @param clazz The last super class to stop appending fields for. + */ + public void setUpToClass( Class clazz ) + { + this.upToClass = clazz; + } + + + /** + * <p/> + * Gets the String built by this builder. </p> + * + * @return the built string + */ + public String toString() + { + if ( this.getObject() == null ) + { + return this.getStyle().getNullText(); + } + Class clazz = this.getObject().getClass(); + this.appendFieldsIn( clazz ); + while ( clazz.getSuperclass() != null && clazz != this.getUpToClass() ) + { + clazz = clazz.getSuperclass(); + this.appendFieldsIn( clazz ); + } + return super.toString(); + } + + + /** + * <p/> + * Unregisters this builder's source object to avoid infinite loops when + * processing circular object references. </p> + */ + void unregisterObject() + { + unregister( this.getObject() ); + } +}
