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.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, Object... formatArgs) {
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(String.format(str, formatArgs));
58        return ewc;
59    }
60
61    /**
62     * Constructs an instance.
63     *
64     * @param message human-oriented message
65     */
66    public ExceptionWithContext(String message, Object... formatArgs) {
67        this(null, message, formatArgs);
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(cause, null);
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(Throwable cause, String message, Object... formatArgs) {
86        super((message != null) ? formatMessage(message, formatArgs) :
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    private static String formatMessage(String message, Object... formatArgs) {
100        if (message == null) {
101            return null;
102        }
103        return String.format(message, formatArgs);
104    }
105
106    /** {@inheritDoc} */
107    @Override
108    public void printStackTrace(PrintStream out) {
109        super.printStackTrace(out);
110        out.println(context);
111    }
112
113    /** {@inheritDoc} */
114    @Override
115    public void printStackTrace(PrintWriter out) {
116        super.printStackTrace(out);
117        out.println(context);
118    }
119
120    /**
121     * Adds a line of context to this instance.
122     *
123     * @param str non-null; new context
124     */
125    public void addContext(String str) {
126        if (str == null) {
127            throw new NullPointerException("str == null");
128        }
129
130        context.append(str);
131        if (!str.endsWith("\n")) {
132            context.append('\n');
133        }
134    }
135
136    /**
137     * Gets the context.
138     *
139     * @return non-null; the context
140     */
141    public String getContext() {
142        return context.toString();
143    }
144
145    /**
146     * Prints the message and context.
147     *
148     * @param out non-null; where to print to
149     */
150    public void printContext(PrintStream out) {
151        out.println(getMessage());
152        out.print(context);
153    }
154
155    /**
156     * Prints the message and context.
157     *
158     * @param out non-null; where to print to
159     */
160    public void printContext(PrintWriter out) {
161        out.println(getMessage());
162        out.print(context);
163    }
164}