1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.lang;
19
20import java.io.IOException;
21import java.io.ObjectInputStream;
22import java.io.ObjectOutputStream;
23import java.io.PrintStream;
24import java.io.PrintWriter;
25import java.util.ArrayList;
26import java.util.Collections;
27import java.util.List;
28import libcore.util.EmptyArray;
29
30/**
31 * The superclass of all classes which can be thrown by the VM. The
32 * two direct subclasses are recoverable exceptions ({@code Exception}) and
33 * unrecoverable errors ({@code Error}). This class provides common methods for
34 * accessing a string message which provides extra information about the
35 * circumstances in which the {@code Throwable} was created (basically an error
36 * message in most cases), and for saving a stack trace (that is, a record of
37 * the call stack at a particular point in time) which can be printed later.
38 * <p>
39 * A {@code Throwable} can also include a cause, which is a nested {@code
40 * Throwable} that represents the original problem that led to this {@code
41 * Throwable}. It is often used for wrapping various types of errors into a
42 * common {@code Throwable} without losing the detailed original error
43 * information. When printing the stack trace, the trace of the cause is
44 * included.
45 *
46 * @see Error
47 * @see Exception
48 * @see RuntimeException
49 */
50public class Throwable implements java.io.Serializable {
51    private static final long serialVersionUID = -3042686055658047285L;
52
53    /**
54     * The message provided when the exception was created.
55     */
56    private String detailMessage;
57
58    /**
59     * The cause of this Throwable. Null when there is no cause.
60     */
61    private Throwable cause = this;
62
63    /**
64     * Throwables suppressed by this throwable. Null when suppressed exceptions
65     * are disabled.
66     */
67    private List<Throwable> suppressedExceptions = Collections.emptyList();
68
69    /**
70     * An intermediate representation of the stack trace.  This field may
71     * be accessed by the VM; do not rename.
72     */
73    private transient volatile Object stackState;
74
75    /**
76     * A fully-expanded representation of the stack trace.
77     */
78    private StackTraceElement[] stackTrace;
79
80    /**
81     * Constructs a new {@code Throwable} that includes the current stack trace.
82     */
83    public Throwable() {
84        fillInStackTrace();
85    }
86
87    /**
88     * Constructs a new {@code Throwable} with the current stack trace and the
89     * specified detail message.
90     *
91     * @param detailMessage
92     *            the detail message for this {@code Throwable}.
93     */
94    public Throwable(String detailMessage) {
95        this();
96        this.detailMessage = detailMessage;
97    }
98
99    /**
100     * Constructs a new {@code Throwable} with the current stack trace, the
101     * specified detail message and the specified cause.
102     *
103     * @param detailMessage
104     *            the detail message for this {@code Throwable}.
105     * @param throwable
106     *            the cause of this {@code Throwable}.
107     */
108    public Throwable(String detailMessage, Throwable throwable) {
109        this();
110        this.detailMessage = detailMessage;
111        cause = throwable;
112    }
113
114    /**
115     * Constructs a new {@code Throwable} with the current stack trace and the
116     * specified cause.
117     *
118     * @param throwable
119     *            the cause of this {@code Throwable}.
120     */
121    public Throwable(Throwable throwable) {
122        this();
123        this.detailMessage = throwable == null ? null : throwable.toString();
124        cause = throwable;
125    }
126
127    /**
128     * Constructs a new {@code Throwable} with the current stack trace, the
129     * specified detail message and the specified cause.
130     *
131     * @param enableSuppression if false, throwables passed to {@link
132     *     #addSuppressed(Throwable)} will be silently discarded.
133     * @since 1.7
134     * @hide 1.7
135     */
136    protected Throwable(String detailMessage, Throwable throwable, boolean enableSuppression) {
137        this(detailMessage, throwable);
138        if (!enableSuppression) {
139            this.suppressedExceptions = null;
140        }
141    }
142
143    /**
144     * Records the stack trace from the point where this method has been called
145     * to this {@code Throwable}. This method is invoked by the {@code Throwable} constructors.
146     *
147     * <p>This method is public so that code (such as an RPC system) which catches
148     * a {@code Throwable} and then re-throws it can replace the construction-time stack trace
149     * with a stack trace from the location where the exception was re-thrown, by <i>calling</i>
150     * {@code fillInStackTrace}.
151     *
152     * <p>This method is non-final so that non-Java language implementations can disable VM stack
153     * traces for their language. Filling in the stack trace is relatively expensive.
154     * <i>Overriding</i> this method in the root of a language's exception hierarchy allows the
155     * language to avoid paying for something it doesn't need.
156     *
157     * @return this {@code Throwable} instance.
158     */
159    public Throwable fillInStackTrace() {
160        // Fill in the intermediate representation
161        stackState = nativeFillInStackTrace();
162        // Mark the full representation as empty
163        stackTrace = null;
164        return this;
165    }
166
167    /**
168     * Returns the extra information message which was provided when this
169     * {@code Throwable} was created. Returns {@code null} if no message was
170     * provided at creation time.
171     *
172     * @return this {@code Throwable}'s detail message.
173     */
174    public String getMessage() {
175        return detailMessage;
176    }
177
178    /**
179     * Returns the extra information message which was provided when this
180     * {@code Throwable} was created. Returns {@code null} if no message was
181     * provided at creation time. Subclasses may override this method to return
182     * localized text for the message. Android returns the regular detail message.
183     *
184     * @return this {@code Throwable}'s localized detail message.
185     */
186    public String getLocalizedMessage() {
187        return getMessage();
188    }
189
190    /**
191     * Returns the array of stack trace elements of this {@code Throwable}. Each
192     * {@code StackTraceElement} represents an entry in the call stack. The
193     * element at position 0 is the top of the stack, that is, the stack frame
194     * where this {@code Throwable} is thrown.
195     *
196     * @return a copy of the array of {@code StackTraceElement}s representing
197     *         the call stack. Changes in the array obtained from this call will
198     *         not change the call stack stored in this {@code Throwable}.
199     * @see #printStackTrace()
200     */
201    public StackTraceElement[] getStackTrace() {
202        return getInternalStackTrace().clone();
203    }
204
205    /**
206     * Sets the array of stack trace elements. Each {@code StackTraceElement}
207     * represents an entry in the call stack. A copy of the specified array is
208     * stored in this {@code Throwable}. will be returned by {@code
209     * getStackTrace()} and printed by {@code printStackTrace()}.
210     *
211     * @param trace
212     *            the new array of {@code StackTraceElement}s. A copy of the
213     *            array is stored in this {@code Throwable}, so subsequent
214     *            changes to {@code trace} will not change the call stack stored
215     *            in this {@code Throwable}.
216     * @throws NullPointerException
217     *             if any element in {@code trace} is {@code null}.
218     * @see #printStackTrace()
219     */
220    public void setStackTrace(StackTraceElement[] trace) {
221        StackTraceElement[] newTrace = trace.clone();
222        for (int i = 0; i < newTrace.length; i++) {
223            if (newTrace[i] == null) {
224                throw new NullPointerException("trace[" + i + "] == null");
225            }
226        }
227        stackTrace = newTrace;
228    }
229
230    /**
231     * Writes a printable representation of this {@code Throwable}'s stack trace
232     * to the {@code System.err} stream.
233     *
234     */
235    public void printStackTrace() {
236        printStackTrace(System.err);
237    }
238
239    /**
240     * Counts the number of duplicate stack frames, starting from the
241     * end of the stack.
242     *
243     * @param currentStack a stack to compare
244     * @param parentStack a stack to compare
245     *
246     * @return the number of duplicate stack frames.
247     */
248    private static int countDuplicates(StackTraceElement[] currentStack,
249            StackTraceElement[] parentStack) {
250        int duplicates = 0;
251        int parentIndex = parentStack.length;
252        for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
253            StackTraceElement parentFrame = parentStack[parentIndex];
254            if (parentFrame.equals(currentStack[i])) {
255                duplicates++;
256            } else {
257                break;
258            }
259        }
260        return duplicates;
261    }
262
263    /**
264     * Returns an array of StackTraceElement. Each StackTraceElement
265     * represents a entry on the stack.
266     *
267     * @return an array of StackTraceElement representing the stack
268     */
269    private StackTraceElement[] getInternalStackTrace() {
270        if (stackTrace == null) {
271            stackTrace = nativeGetStackTrace(stackState);
272            stackState = null; // Clean up intermediate representation
273        }
274        return stackTrace;
275    }
276
277    /**
278     * Writes a printable representation of this {@code Throwable}'s stack trace
279     * to the specified print stream. If the {@code Throwable} contains a
280     * {@link #getCause() cause}, the method will be invoked recursively for
281     * the nested {@code Throwable}.
282     *
283     * @param err
284     *            the stream to write the stack trace on.
285     */
286    public void printStackTrace(PrintStream err) {
287        try {
288            printStackTrace(err, "", null);
289        } catch (IOException e) {
290            // Appendable.append throws IOException but PrintStream.append doesn't.
291            throw new AssertionError();
292        }
293    }
294
295    /**
296     * Writes a printable representation of this {@code Throwable}'s stack trace
297     * to the specified print writer. If the {@code Throwable} contains a
298     * {@link #getCause() cause}, the method will be invoked recursively for the
299     * nested {@code Throwable}.
300     *
301     * @param err
302     *            the writer to write the stack trace on.
303     */
304    public void printStackTrace(PrintWriter err) {
305        try {
306            printStackTrace(err, "", null);
307        } catch (IOException e) {
308            // Appendable.append throws IOException, but PrintWriter.append doesn't.
309            throw new AssertionError();
310        }
311    }
312
313    /**
314     * @param indent additional indentation on each line of the stack trace.
315     *     This is the empty string for all but suppressed throwables.
316     * @param parentStack the parent stack trace to suppress duplicates from, or
317     *     null if this stack trace has no parent.
318     */
319    private void printStackTrace(Appendable err, String indent, StackTraceElement[] parentStack)
320            throws IOException {
321        err.append(toString());
322        err.append("\n");
323
324        StackTraceElement[] stack = getInternalStackTrace();
325        if (stack != null) {
326            int duplicates = parentStack != null ? countDuplicates(stack, parentStack) : 0;
327            for (int i = 0; i < stack.length - duplicates; i++) {
328                err.append(indent);
329                err.append("\tat ");
330                err.append(stack[i].toString());
331                err.append("\n");
332            }
333
334            if (duplicates > 0) {
335                err.append(indent);
336                err.append("\t... ");
337                err.append(Integer.toString(duplicates));
338                err.append(" more\n");
339            }
340        }
341
342        // Print suppressed exceptions indented one level deeper.
343        if (suppressedExceptions != null) {
344            for (Throwable throwable : suppressedExceptions) {
345                err.append(indent);
346                err.append("\tSuppressed: ");
347                throwable.printStackTrace(err, indent + "\t", stack);
348            }
349        }
350
351        Throwable cause = getCause();
352        if (cause != null) {
353            err.append(indent);
354            err.append("Caused by: ");
355            cause.printStackTrace(err, indent, stack);
356        }
357    }
358
359    @Override
360    public String toString() {
361        String msg = getLocalizedMessage();
362        String name = getClass().getName();
363        if (msg == null) {
364            return name;
365        }
366        return name + ": " + msg;
367    }
368
369    /**
370     * Initializes the cause of this {@code Throwable}. The cause can only be
371     * initialized once.
372     *
373     * @param throwable
374     *            the cause of this {@code Throwable}.
375     * @return this {@code Throwable} instance.
376     * @throws IllegalArgumentException
377     *             if {@code Throwable} is this object.
378     * @throws IllegalStateException
379     *             if the cause has already been initialized.
380     */
381    public Throwable initCause(Throwable throwable) {
382        if (cause != this) {
383            throw new IllegalStateException("Cause already initialized");
384        }
385        if (throwable == this) {
386            throw new IllegalArgumentException("throwable == this");
387        }
388        cause = throwable;
389        return this;
390    }
391
392    /**
393     * Returns the cause of this {@code Throwable}, or {@code null} if there is
394     * no cause.
395     *
396     * @return Throwable this {@code Throwable}'s cause.
397     */
398    public Throwable getCause() {
399        if (cause == this) {
400            return null;
401        }
402        return cause;
403    }
404
405    /**
406     * Adds {@code throwable} to the list of throwables suppressed by this. The
407     * throwable will included when this exception's stack trace is printed.
408     *
409     * @throws IllegalArgumentException if {@code throwable == this}.
410     * @throws NullPointerException if {@code throwable == null}.
411     * @since 1.7
412     * @hide 1.7
413     */
414    public final void addSuppressed(Throwable throwable) {
415        if (throwable == this) {
416            throw new IllegalArgumentException("throwable == this");
417        }
418        if (throwable == null) {
419            throw new NullPointerException("throwable == null");
420        }
421        if (suppressedExceptions != null) {
422            // suppressed exceptions are enabled
423            if (suppressedExceptions.isEmpty()) {
424                // ensure we have somewhere to place suppressed exceptions
425                suppressedExceptions = new ArrayList<Throwable>(1);
426            }
427            suppressedExceptions.add(throwable);
428        }
429    }
430
431    /**
432     * Returns the throwables suppressed by this.
433     *
434     * @since 1.7
435     * @hide 1.7
436     */
437    public final Throwable[] getSuppressed() {
438        return (suppressedExceptions != null && !suppressedExceptions.isEmpty())
439                ? suppressedExceptions.toArray(new Throwable[suppressedExceptions.size()])
440                : EmptyArray.THROWABLE;
441    }
442
443    private void writeObject(ObjectOutputStream out) throws IOException {
444        // ensure the stackTrace field is initialized
445        getInternalStackTrace();
446        out.defaultWriteObject();
447    }
448
449    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
450        in.defaultReadObject();
451
452        if (suppressedExceptions != null) {
453            // the deserialized list may be unmodifiable, so just create a mutable copy
454            suppressedExceptions = new ArrayList<Throwable>(suppressedExceptions);
455        }
456    }
457
458    /*
459     * Creates a compact, VM-specific collection of goodies, suitable for
460     * storing in the "stackState" field, based on the current thread's
461     * call stack.
462     */
463    private static native Object nativeFillInStackTrace();
464
465    /*
466     * Creates an array of StackTraceElement objects from the data held
467     * in "stackState".
468     */
469    private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
470}
471