1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * As per the Apache license requirements, this file has been modified
19 * from its original state.
20 *
21 * Such modifications are Copyright (C) 2010 Ben Gruver, and are released
22 * under the original license
23 */
24
25package org.jf.dexlib.Util;
26
27import java.io.PrintStream;
28import java.io.PrintWriter;
29
30/**
31 * Exception which carries around structured context.
32 */
33public class ExceptionWithContext
34        extends RuntimeException {
35    /** non-null; human-oriented context of the exception */
36    private StringBuffer context;
37
38    /**
39     * Augments the given exception with the given context, and return the
40     * result. The result is either the given exception if it was an
41     * {@link ExceptionWithContext}, or a newly-constructed exception if it
42     * was not.
43     *
44     * @param ex non-null; the exception to augment
45     * @param str non-null; context to add
46     * @return non-null; an appropriate instance
47     */
48    public static ExceptionWithContext withContext(Throwable ex, String str) {
49        ExceptionWithContext ewc;
50
51        if (ex instanceof ExceptionWithContext) {
52            ewc = (ExceptionWithContext) ex;
53        } else {
54            ewc = new ExceptionWithContext(ex);
55        }
56
57        ewc.addContext(str);
58        return ewc;
59    }
60
61    /**
62     * Constructs an instance.
63     *
64     * @param message human-oriented message
65     */
66    public ExceptionWithContext(String message) {
67        this(message, null);
68    }
69
70    /**
71     * Constructs an instance.
72     *
73     * @param cause null-ok; exception that caused this one
74     */
75    public ExceptionWithContext(Throwable cause) {
76        this(null, cause);
77    }
78
79    /**
80     * Constructs an instance.
81     *
82     * @param message human-oriented message
83     * @param cause null-ok; exception that caused this one
84     */
85    public ExceptionWithContext(String message, Throwable cause) {
86        super((message != null) ? message :
87              (cause != null) ? cause.getMessage() : null,
88              cause);
89
90        if (cause instanceof ExceptionWithContext) {
91            String ctx = ((ExceptionWithContext) cause).context.toString();
92            context = new StringBuffer(ctx.length() + 200);
93            context.append(ctx);
94        } else {
95            context = new StringBuffer(200);
96        }
97    }
98
99    /** {@inheritDoc} */
100    @Override
101    public void printStackTrace(PrintStream out) {
102        super.printStackTrace(out);
103        out.println(context);
104    }
105
106    /** {@inheritDoc} */
107    @Override
108    public void printStackTrace(PrintWriter out) {
109        super.printStackTrace(out);
110        out.println(context);
111    }
112
113    /**
114     * Adds a line of context to this instance.
115     *
116     * @param str non-null; new context
117     */
118    public void addContext(String str) {
119        if (str == null) {
120            throw new NullPointerException("str == null");
121        }
122
123        context.append(str);
124        if (!str.endsWith("\n")) {
125            context.append('\n');
126        }
127    }
128
129    /**
130     * Gets the context.
131     *
132     * @return non-null; the context
133     */
134    public String getContext() {
135        return context.toString();
136    }
137
138    /**
139     * Prints the message and context.
140     *
141     * @param out non-null; where to print to
142     */
143    public void printContext(PrintStream out) {
144        out.println(getMessage());
145        out.print(context);
146    }
147
148    /**
149     * Prints the message and context.
150     *
151     * @param out non-null; where to print to
152     */
153    public void printContext(PrintWriter out) {
154        out.println(getMessage());
155        out.print(context);
156    }
157}