/*
 * @(#)Throwable.java	1.51 03/01/23
 *
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.lang;
import  java.io.*;

/**
 * The <code>Throwable</code> class is the superclass of all errors and
 * exceptions in the Java language. Only objects that are instances of this
 * class (or one of its subclasses) are thrown by the Java Virtual Machine or
 * can be thrown by the Java <code>throw</code> statement. Similarly, only
 * this class or one of its subclasses can be the argument type in a
 * <code>catch</code> clause.
 * 
 * <p>Instances of two subclasses, {@link java.lang.Error} and 
 * {@link java.lang.Exception}, are conventionally used to indicate 
 * that exceptional situations have occurred. Typically, these instances 
 * are freshly created in the context of the exceptional situation so 
 * as to include relevant information (such as stack trace data).
 * 
 * <p>A throwable contains a snapshot of the execution stack of its thread at
 * the time it was created. It can also contain a message string that gives
 * more information about the error. Finally, it can contain a <i>cause</i>:
 * another throwable that caused this throwable to get thrown.  The cause
 * facility is new in release 1.4.  It is also known as the <i>chained
 * exception</i> facility, as the cause can, itself, have a cause, and so on,
 * leading to a "chain" of exceptions, each caused by another.
 *
 * <p>One reason that a throwable may have a cause is that the class that
 * throws it is built atop a lower layered abstraction, and an operation on
 * the upper layer fails due to a failure in the lower layer.  It would be bad
 * design to let the throwable thrown by the lower layer propagate outward, as
 * it is generally unrelated to the abstraction provided by the upper layer.
 * Further, doing so would tie the API of the upper layer to the details of
 * its implementation, assuming the lower layer's exception was a checked
 * exception.  Throwing a "wrapped exception" (i.e., an exception containing a
 * cause) allows the upper layer to communicate the details of the failure to
 * its caller without incurring either of these shortcomings.  It preserves
 * the flexibility to change the implementation of the upper layer without
 * changing its API (in particular, the set of exceptions thrown by its
 * methods).
 *
 * <p>A second reason that a throwable may have a cause is that the method
 * that throws it must conform to a general-purpose interface that does not
 * permit the method to throw the cause directly.  For example, suppose
 * a persistent collection conforms to the {@link java.util.Collection
 * Collection} interface, and that its persistence is implemented atop
 * <tt>java.io</tt>.  Suppose the internals of the <tt>put</tt> method 
 * can throw an {@link java.io.IOException IOException}.  The implementation
 * can communicate the details of the <tt>IOException</tt> to its caller
 * while conforming to the <tt>Collection</tt> interface by wrapping the
 * <tt>IOException</tt> in an appropriate unchecked exception.  (The
 * specification for the persistent collection should indicate that it is
 * capable of throwing such exceptions.)
 *
 * <p>A cause can be associated with a throwable in two ways: via a
 * constructor that takes the cause as an argument, or via the
 * {@link #initCause(Throwable)} method.  New throwable classes that
 * wish to allow causes to be associated with them should provide constructors
 * that take a cause and delegate (perhaps indirectly) to one of the
 * <tt>Throwable</tt> constructors that takes a cause.  For example:
 * <pre>
 *     try {
 *         lowLevelOp();
 *     } catch (LowLevelException le) {
 *         throw new HighLevelException(le);  // Chaining-aware constructor
 *     }
 * </pre>
 * Because the <tt>initCause</tt> method is public, it allows a cause to be
 * associated with any throwable, even a "legacy throwable" whose
 * implementation predates the addition of the exception chaining mechanism to
 * <tt>Throwable</tt>. For example:
 * <pre>
 *     try {
 *         lowLevelOp();
 *     } catch (LowLevelException le) {
 *         throw (HighLevelException)
                 new HighLevelException().initCause(le);  // Legacy constructor
 *     }
 * </pre>
 *
 * <p>Prior to release 1.4, there were many throwables that had their own
 * non-standard exception chaining mechanisms (
 * {@link ExceptionInInitializerError}, {@link ClassNotFoundException},
 * {@link java.lang.reflect.UndeclaredThrowableException},
 * {@link java.lang.reflect.InvocationTargetException}, 
 * {@link java.io.WriteAbortedException},
 * {@link java.security.PrivilegedActionException},
 * {@link java.awt.print.PrinterIOException} and
 * {@link java.rmi.RemoteException}).
 * As of release 1.4, all of these throwables have been retrofitted to 
 * use the standard exception chaining mechanism, while continuing to
 * implement their "legacy" chaining mechanisms for compatibility.
 *
 * <p>Further, as of release 1.4, many general purpose <tt>Throwable</tt>
 * classes (for example {@link Exception}, {@link RuntimeException},
 * {@link Error}) have been retrofitted with constructors that take
 * a cause.  This was not strictly necessary, due to the existence of the
 * <tt>initCause</tt> method, but it is more convenient and expressive to
 * delegate to a constructor that takes a cause.
 * 
 * <p>By convention, class <code>Throwable</code> and its subclasses have two
 * constructors, one that takes no arguments and one that takes a
 * <code>String</code> argument that can be used to produce a detail message.
 * Further, those subclasses that might likely have a cause associated with
 * them should have two more constructors, one that takes a
 * <code>Throwable</code> (the cause), and one that takes a
 * <code>String</code> (the detail message) and a <code>Throwable</code> (the
 * cause).
 *
 * <p>Also introduced in release 1.4 is the {@link #getStackTrace()} method,
 * which allows programmatic access to the stack trace information that was
 * previously available only in text form, via the various forms of the
 * {@link #printStackTrace()} method.  This information has been added to the
 * <i>serialized representation</i> of this class so <tt>getStackTrace</tt>
 * and <tt>printStackTrace</tt> will operate properly on a throwable that
 * was obtained by deserialization.
 *
 * @author  unascribed
 * @author  Josh Bloch (Added exception chaining and programmatic access to
 *          stack trace in 1.4.)
 * @version 1.51, 01/23/03
 * @since JDK1.0
 */
public class Throwable implements Serializable {
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -3042686055658047285L;

    /**
     * Native code saves some indication of the stack backtrace in this slot.
     */
    //private transient Object backtrace; 

    /**
     * Specific details about the Throwable.  For example, for
     * <tt>FileNotFoundException</tt>, this contains the name of
     * the file that could not be found.
     *
     * @serial
     */
    private String detailMessage;

    /**
     * The throwable that caused this throwable to get thrown, or null if this
     * throwable was not caused by another throwable, or if the causative
     * throwable is unknown.  If this field is equal to this throwable itself,
     * it indicates that the cause of this throwable has not yet been
     * initialized.
     *
     * @serial
     * @since 1.4
     */
    private Throwable cause = this;

    /**
     * The stack trace, as returned by {@link #getStackTrace()}.
     *
     * @serial
     * @since 1.4
     */
    private StackTraceElement[] stackTrace;
    /*
     * This field is lazily initialized on first use or serialization and
     * nulled out when fillInStackTrace is called.
     */

    /**
     * Constructs a new throwable with <code>null</code> as its detail message.
     * The cause is not initialized, and may subsequently be initialized by a
     * call to {@link #initCause}.
     *
     * <p>The {@link #fillInStackTrace()} method is called to initialize
     * the stack trace data in the newly created throwable.
     */
    public Throwable() {
        fillInStackTrace();
    }

    /**
     * Constructs a new throwable with the specified detail message.  The
     * cause is not initialized, and may subsequently be initialized by
     * a call to {@link #initCause}.
     *
     * <p>The {@link #fillInStackTrace()} method is called to initialize
     * the stack trace data in the newly created throwable.
     *
     * @param   message   the detail message. The detail message is saved for 
     *          later retrieval by the {@link #getMessage()} method.
     */
    public Throwable(String message) {
        fillInStackTrace();
        detailMessage = message;
    }

    /**
     * Constructs a new throwable with the specified detail message and
     * cause.  <p>Note that the detail message associated with
     * <code>cause</code> is <i>not</i> automatically incorporated in
     * this throwable's detail message.
     *
     * <p>The {@link #fillInStackTrace()} method is called to initialize
     * the stack trace data in the newly created throwable.
     *
     * @param  message the detail message (which is saved for later retrieval
     *         by the {@link #getMessage()} method).
     * @param  cause the cause (which is saved for later retrieval by the
     *         {@link #getCause()} method).  (A <tt>null</tt> value is
     *         permitted, and indicates that the cause is nonexistent or
     *         unknown.)
     * @since  1.4
     */
    public Throwable(String message, Throwable cause) {
        fillInStackTrace();
        detailMessage = message;
        this.cause = cause;
    }

    /**
     * Constructs a new throwable with the specified cause and a detail
     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
     * typically contains the class and detail message of <tt>cause</tt>).
     * This constructor is useful for throwables that are little more than
     * wrappers for other throwables (for example, {@link
     * java.security.PrivilegedActionException}).
     *
     * <p>The {@link #fillInStackTrace()} method is called to initialize
     * the stack trace data in the newly created throwable.
     *
     * @param  cause the cause (which is saved for later retrieval by the
     *         {@link #getCause()} method).  (A <tt>null</tt> value is
     *         permitted, and indicates that the cause is nonexistent or
     *         unknown.)
     * @since  1.4
     */
    public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }

    /**
     * Returns the detail message string of this throwable.
     *
     * @return  the detail message string of this <tt>Throwable</tt> instance
     *          (which may be <tt>null</tt>).
     */
    public String getMessage() {
    	/**
    	 * @j2sNative
    	 * if (typeof this.message != "undefined") {
    	 * 	return this.message;
    	 * }
    	 */{}
        return detailMessage;
    }

    /**
     * Creates a localized description of this throwable.
     * Subclasses may override this method in order to produce a
     * locale-specific message.  For subclasses that do not override this
     * method, the default implementation returns the same result as
     * <code>getMessage()</code>.
     *
     * @return  The localized description of this throwable.
     * @since   JDK1.1
     */
    public String getLocalizedMessage() {
        return getMessage();
    }

    /**
     * Returns the cause of this throwable or <code>null</code> if the
     * cause is nonexistent or unknown.  (The cause is the throwable that
     * caused this throwable to get thrown.)
     *
     * <p>This implementation returns the cause that was supplied via one of
     * the constructors requiring a <tt>Throwable</tt>, or that was set after
     * creation with the {@link #initCause(Throwable)} method.  While it is
     * typically unnecessary to override this method, a subclass can override
     * it to return a cause set by some other means.  This is appropriate for
     * a "legacy chained throwable" that predates the addition of chained
     * exceptions to <tt>Throwable</tt>.  Note that it is <i>not</i>
     * necessary to override any of the <tt>PrintStackTrace</tt> methods,
     * all of which invoke the <tt>getCause</tt> method to determine the
     * cause of a throwable.
     *
     * @return  the cause of this throwable or <code>null</code> if the
     *          cause is nonexistent or unknown.
     * @since 1.4
     */
    public Throwable getCause() {
        return (cause==this ? null : cause);
    }

    /**
     * Initializes the <i>cause</i> of this throwable to the specified value.
     * (The cause is the throwable that caused this throwable to get thrown.) 
     *
     * <p>This method can be called at most once.  It is generally called from 
     * within the constructor, or immediately after creating the
     * throwable.  If this throwable was created
     * with {@link #Throwable(Throwable)} or
     * {@link #Throwable(String,Throwable)}, this method cannot be called
     * even once.
     *
     * @param  cause the cause (which is saved for later retrieval by the
     *         {@link #getCause()} method).  (A <tt>null</tt> value is
     *         permitted, and indicates that the cause is nonexistent or
     *         unknown.)
     * @return  a reference to this <code>Throwable</code> instance.
     * @throws IllegalArgumentException if <code>cause</code> is this
     *         throwable.  (A throwable cannot be its own cause.)
     * @throws IllegalStateException if this throwable was
     *         created with {@link #Throwable(Throwable)} or
     *         {@link #Throwable(String,Throwable)}, or this method has already
     *         been called on this throwable.
     * @since  1.4
     */
    public synchronized Throwable initCause(Throwable cause) {
        if (this.cause != this)
            throw new IllegalStateException("Can't overwrite cause");
        if (cause == this)
            throw new IllegalArgumentException("Self-causation not permitted");
        this.cause = cause;
        return this;
    }

    /**
     * Returns a short description of this throwable.
     * If this <code>Throwable</code> object was created with a non-null detail
     * message string, then the result is the concatenation of three strings: 
     * <ul>
     * <li>The name of the actual class of this object 
     * <li>": " (a colon and a space)
     * <li>The result of the {@link #getMessage} method for this object 
     * </ul>
     * If this <code>Throwable</code> object was created with a <tt>null</tt>
     * detail message string, then the name of the actual class of this object
     * is returned. 
     *
     * @return a string representation of this throwable.
     */
    public String toString() {
        String s = getClass().getName();
        String message = getLocalizedMessage();
        return (message != null) ? (s + ": " + message) : s;
    }

    /**
     * Prints this throwable and its backtrace to the 
     * standard error stream. This method prints a stack trace for this 
     * <code>Throwable</code> object on the error output stream that is 
     * the value of the field <code>System.err</code>. The first line of 
     * output contains the result of the {@link #toString()} method for 
     * this object.  Remaining lines represent data previously recorded by 
     * the method {@link #fillInStackTrace()}. The format of this 
     * information depends on the implementation, but the following 
     * example may be regarded as typical: 
     * <blockquote><pre>
     * java.lang.NullPointerException
     *         at MyClass.mash(MyClass.java:9)
     *         at MyClass.crunch(MyClass.java:6)
     *         at MyClass.main(MyClass.java:3)
     * </pre></blockquote>
     * This example was produced by running the program: 
     * <pre>
     * class MyClass {
     *     public static void main(String[] args) {
     *         crunch(null);
     *     }
     *     static void crunch(int[] a) {
     *         mash(a);
     *     }
     *     static void mash(int[] b) {
     *         System.out.println(b[0]);
     *     }
     * }
     * </pre>
     * The backtrace for a throwable with an initialized, non-null cause
     * should generally include the backtrace for the cause.  The format
     * of this information depends on the implementation, but the following
     * example may be regarded as typical:
     * <pre>
     * HighLevelException: MidLevelException: LowLevelException
     *         at Junk.a(Junk.java:13)
     *         at Junk.main(Junk.java:4)
     * Caused by: MidLevelException: LowLevelException
     *         at Junk.c(Junk.java:23)
     *         at Junk.b(Junk.java:17)
     *         at Junk.a(Junk.java:11)
     *         ... 1 more
     * Caused by: LowLevelException
     *         at Junk.e(Junk.java:30)
     *         at Junk.d(Junk.java:27)
     *         at Junk.c(Junk.java:21)
     *         ... 3 more
     * </pre>
     * Note the presence of lines containing the characters <tt>"..."</tt>.
     * These lines indicate that the remainder of the stack trace for this
     * exception matches the indicated number of frames from the bottom of the
     * stack trace of the exception that was caused by this exception (the
     * "enclosing" exception).  This shorthand can greatly reduce the length
     * of the output in the common case where a wrapped exception is thrown
     * from same method as the "causative exception" is caught.  The above
     * example was produced by running the program:
     * <pre>
     * public class Junk {
     *     public static void main(String args[]) { 
     *         try {
     *             a();
     *         } catch(HighLevelException e) {
     *             e.printStackTrace();
     *         }
     *     }
     *     static void a() throws HighLevelException {
     *         try {
     *             b();
     *         } catch(MidLevelException e) {
     *             throw new HighLevelException(e);
     *         }
     *     }
     *     static void b() throws MidLevelException {
     *         c();
     *     }   
     *     static void c() throws MidLevelException {
     *         try {
     *             d();
     *         } catch(LowLevelException e) {
     *             throw new MidLevelException(e);
     *         }
     *     }
     *     static void d() throws LowLevelException { 
     *        e();
     *     }
     *     static void e() throws LowLevelException {
     *         throw new LowLevelException();
     *     }
     * }
     *
     * class HighLevelException extends Exception {
     *     HighLevelException(Throwable cause) { super(cause); }
     * }
     *
     * class MidLevelException extends Exception {
     *     MidLevelException(Throwable cause)  { super(cause); }
     * }
     * 
     * class LowLevelException extends Exception {
     * }
     * </pre>
     */
    public void printStackTrace() { 
        //printStackTrace(System.err);
    	System.err.println(this);
    	for (int i = 0; i < stackTrace.length; i++)
    	/**
    	 * @j2sNativeSrc
var t = this.stackTrace[i];
var x = t.methodName.indexOf ("(");
var n = t.methodName.substring (0, x).replace (/\s+/g, "");
if (n != "construct" || t.nativeClazz == null
		|| Clazz.getInheritedLevel (t.nativeClazz, Throwable) < 0) {
	System.err.println (t);
}
    	 * @j2sNative
var t = this.c[i];
var x = t.e.indexOf ("(");
var n = t.e.substring (0, x).replace (/\s+/g, "");
if (n != "construct" || t.z == null
		|| Clazz.getInheritedLevel (t.z, Throwable) < 0) {
	System.err.println (t);
}
    	 */
    	{
    		System.err.println(stackTrace[i]);
		}
    }

    /**
     * Prints this throwable and its backtrace to the specified print stream.
     *
     * @param s <code>PrintStream</code> to use for output
     * @j2sNative
     * this.printStackTrace ();
     */
    public void printStackTrace(PrintStream s) {
        synchronized (s) {
            s.println(this);
            StackTraceElement[] trace = getOurStackTrace();
            for (int i=0; i < trace.length; i++)
                s.println("\tat " + trace[i]);

            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printStackTraceAsCause(s, trace);
        }
    }

    /**
     * Print our stack trace as a cause for the specified stack trace.
     * @j2sIgnore
     */
    private void printStackTraceAsCause(PrintStream s,
                                        StackTraceElement[] causedTrace)
    {
        // assert Thread.holdsLock(s);

        // Compute number of frames in common between this and caused
        StackTraceElement[] trace = getOurStackTrace();
        int m = trace.length-1, n = causedTrace.length-1;
        while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
            m--; n--;
        }
        int framesInCommon = trace.length - 1 - m;

        s.println("Caused by: " + this);
        for (int i=0; i <= m; i++)
            s.println("\tat " + trace[i]);
        if (framesInCommon != 0)
            s.println("\t... " + framesInCommon + " more");

        // Recurse if we have a cause
        Throwable ourCause = getCause();
        if (ourCause != null)
            ourCause.printStackTraceAsCause(s, trace);
    }

    /**
     * Prints this throwable and its backtrace to the specified
     * print writer.
     *
     * @param s <code>PrintWriter</code> to use for output
     * @since   JDK1.1
     * @j2sNative
     * this.printStackTrace ();
     */
    public void printStackTrace(PrintWriter s) { 
        synchronized (s) {
            s.println(this);
            StackTraceElement[] trace = getOurStackTrace();
            for (int i=0; i < trace.length; i++)
                s.println("\tat " + trace[i]);

            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printStackTraceAsCause(s, trace);
        }
    }

    /**
     * Print our stack trace as a cause for the specified stack trace.
     * @j2sIgnore
     */
    private void printStackTraceAsCause(PrintWriter s,
                                        StackTraceElement[] causedTrace)
    {
        // assert Thread.holdsLock(s);

        // Compute number of frames in common between this and caused
        StackTraceElement[] trace = getOurStackTrace();
        int m = trace.length-1, n = causedTrace.length-1;
        while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
            m--; n--;
        }
        int framesInCommon = trace.length - 1 - m;

        s.println("Caused by: " + this);
        for (int i=0; i <= m; i++)
            s.println("\tat " + trace[i]);
        if (framesInCommon != 0)
            s.println("\t... " + framesInCommon + " more");

        // Recurse if we have a cause
        Throwable ourCause = getCause();
        if (ourCause != null)
            ourCause.printStackTraceAsCause(s, trace);
    }

    /**
     * Fills in the execution stack trace. This method records within this 
     * <code>Throwable</code> object information about the current state of 
     * the stack frames for the current thread.
     *
     * @return  a reference to this <code>Throwable</code> instance.
     * @see     java.lang.Throwable#printStackTrace()
     * @j2sNativeSrc
this.stackTrace = new Array ();
var caller = arguments.callee.caller;
var superCaller = null;
var callerList = new Array ();
var index = Clazz.callingStackTraces.length - 1;
var noLooping = true;
while (index > -1 || caller != null) {
	var clazzName = null;
	var nativeClazz = null;
	if (!noLooping || caller == Clazz.tryToSearchAndExecute || caller == Clazz.superCall || caller == null) {
		if (index < 0) {
			break;
		}
		noLooping = true;
		superCaller = Clazz.callingStackTraces[index].caller;
		nativeClazz = Clazz.callingStackTraces[index].owner;
		index--;
	} else {
		superCaller = caller;
		if (superCaller.claxxOwner != null) {
			nativeClazz = superCaller.claxxOwner;
		} else if (superCaller.exClazz != null) {
			nativeClazz = superCaller.exClazz;
		}
	}

	var st = new StackTraceElement (
			((nativeClazz != null && nativeClazz.__CLASS_NAME__.length != 0) ?
					nativeClazz.__CLASS_NAME__ : "anonymous"), 
			((superCaller.exName == null) ? "anonymous" : superCaller.exName) 
					+ " (" + Clazz.getParamsType (superCaller.arguments) + ")",
			null, -1);
	st.nativeClazz = nativeClazz;
	this.stackTrace[this.stackTrace.length] = st;
	for (var i = 0; i < callerList.length; i++) {
		if (callerList[i] == superCaller) {
			// ... stack information lost as recursive invocation existed ...
			var st = new StackTraceElement ("lost", "missing", null, -3);
			st.nativeClazz = null;
			this.stackTrace[this.stackTrace.length] = st;
 
			noLooping = false;
			//break;
		}
	}
	if (superCaller != null) {
		callerList[callerList.length] = superCaller;
	}
	caller = superCaller.arguments.callee.caller;
}
Clazz.initializingException = false;
return this;
     * @j2sNative
this.c = new Array ();
var r = arguments.callee.caller;
var s = null;
var l = new Array ();
var q = Clazz.callingStackTraces;
var x = q.length - 1;
var p = true;
while (x > -1 || r != null) {
	var clazzName = null;
	var z = null;
	if (!p || r == Clazz.tryToSearchAndExecute || r == Clazz.superCall || r == null) {
		if (x < 0) {
			break;
		}
		p = true;
		s = q[x].caller;
		z = q[x].owner;
		x--;
	} else {
		s = r;
		if (s.claxxOwner != null) {
			z = s.claxxOwner;
		} else if (s.exClazz != null) {
			z = s.exClazz;
		}
	}

	var st = new StackTraceElement (
			((z != null && z.__CLASS_NAME__.length != 0) ? 
					z.__CLASS_NAME__ : "anonymous"),
			((s.exName == null) ? "anonymous" : s.exName) 
					+ " (" + Clazz.getParamsType (s.arguments) + ")",
			null, -1);
	st.z = z;
	this.c[this.c.length] = st;
	for (var i = 0; i < l.length; i++) {
		if (l[i] == s) {
			// ... stack information lost as recursive invocation existed ...
			var st = new StackTraceElement ("lost", "missing", null, -3);
			st.z = null;
			this.c[this.c.length] = st;
 
			p = false;
			//break;
		}
	}
	if (s != null) {
		l[l.length] = s;
	}
	r = s.arguments.callee.caller;
}
Clazz.initializingException = false;
return this;
     */
    public synchronized native Throwable fillInStackTrace();

    /**
     * Provides programmatic access to the stack trace information printed by
     * {@link #printStackTrace()}.  Returns an array of stack trace elements,
     * each representing one stack frame.  The zeroth element of the array
     * (assuming the array's length is non-zero) represents the top of the
     * stack, which is the last method invocation in the sequence.  Typically,
     * this is the point at which this throwable was created and thrown.
     * The last element of the array (assuming the array's length is non-zero)
     * represents the bottom of the stack, which is the first method invocation
     * in the sequence.
     *
     * <p>Some virtual machines may, under some circumstances, omit one
     * or more stack frames from the stack trace.  In the extreme case,
     * a virtual machine that has no stack trace information concerning
     * this throwable is permitted to return a zero-length array from this
     * method.  Generally speaking, the array returned by this method will
     * contain one element for every frame that would be printed by
     * <tt>printStackTrace</tt>.
     *
     * @return an array of stack trace elements representing the stack trace
     *         pertaining to this throwable.
     * @since  1.4
     * @j2sIgnore
     */
    public StackTraceElement[] getStackTrace() {
        return (StackTraceElement[]) getOurStackTrace().clone();
    }

    /**
     * @return
     * @j2sIgnore
     */
    private synchronized StackTraceElement[] getOurStackTrace() {
        // Initialize stack trace if this is the first call to this method
        if (stackTrace == null) {
            int depth = getStackTraceDepth();
            stackTrace = new StackTraceElement[depth];
            for (int i=0; i < depth; i++)
                stackTrace[i] = getStackTraceElement(i);
        }
        return stackTrace;
    }

    /**
     * Sets the stack trace elements that will be returned by
     * {@link #getStackTrace()} and printed by {@link #printStackTrace()}
     * and related methods.
     *
     * This method, which is designed for use by RPC frameworks and other
     * advanced systems, allows the client to override the default
     * stack trace that is either generated by {@link #fillInStackTrace()}
     * when a throwable is constructed or deserialized when a throwable is
     * read from a serialization stream.
     *
     * @param   stackTrace the stack trace elements to be associated with
     * this <code>Throwable</code>.  The specified array is copied by this
     * call; changes in the specified array after the method invocation
     * returns will have no affect on this <code>Throwable</code>'s stack
     * trace.
     *
     * @throws NullPointerException if <code>stackTrace</code> is
     *         <code>null</code>, or if any of the elements of
     *         <code>stackTrace</code> are <code>null</code>
     *
     * @since  1.4
     */
    public void setStackTrace(StackTraceElement[] stackTrace) {
        StackTraceElement[] defensiveCopy =
            (StackTraceElement[]) stackTrace.clone();
        for (int i = 0; i < defensiveCopy.length; i++)
            if (defensiveCopy[i] == null)
                throw new NullPointerException("stackTrace[" + i + "]");

        this.stackTrace = defensiveCopy;
    }

    /**
     * Returns the number of elements in the stack trace (or 0 if the stack
     * trace is unavailable).
     */
    private native int getStackTraceDepth();

    /**
     * Returns the specified element of the stack trace.
     *
     * @param index index of the element to return.
     * @throws IndexOutOfBoundsException if <tt>index %lt; 0 ||
     *         index &gt;= getStackTraceDepth() </tt>
     */
    private native StackTraceElement getStackTraceElement(int index);

    /**
     * @param s
     * @throws IOException
     * @j2sIgnore
     */
    private synchronized void writeObject(java.io.ObjectOutputStream s)
        throws IOException
    {
        getOurStackTrace();  // Ensure that stackTrace field is initialized.
        s.defaultWriteObject();
    }
}
