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 package com.android.dex.util;
18 
19 import java.io.PrintStream;
20 import java.io.PrintWriter;
21 
22 /**
23  * Exception which carries around structured context.
24  */
25 public class ExceptionWithContext extends RuntimeException {
26     /** {@code non-null;} human-oriented context of the exception */
27     private StringBuffer context;
28 
29     /**
30      * Augments the given exception with the given context, and return the
31      * result. The result is either the given exception if it was an
32      * {@link ExceptionWithContext}, or a newly-constructed exception if it
33      * was not.
34      *
35      * @param ex {@code non-null;} the exception to augment
36      * @param str {@code non-null;} context to add
37      * @return {@code non-null;} an appropriate instance
38      */
withContext(Throwable ex, String str)39     public static ExceptionWithContext withContext(Throwable ex, String str) {
40         ExceptionWithContext ewc;
41 
42         if (ex instanceof ExceptionWithContext) {
43             ewc = (ExceptionWithContext) ex;
44         } else {
45             ewc = new ExceptionWithContext(ex);
46         }
47 
48         ewc.addContext(str);
49         return ewc;
50     }
51 
52     /**
53      * Constructs an instance.
54      *
55      * @param message human-oriented message
56      */
ExceptionWithContext(String message)57     public ExceptionWithContext(String message) {
58         this(message, null);
59     }
60 
61     /**
62      * Constructs an instance.
63      *
64      * @param cause {@code null-ok;} exception that caused this one
65      */
ExceptionWithContext(Throwable cause)66     public ExceptionWithContext(Throwable cause) {
67         this(null, cause);
68     }
69 
70     /**
71      * Constructs an instance.
72      *
73      * @param message human-oriented message
74      * @param cause {@code null-ok;} exception that caused this one
75      */
ExceptionWithContext(String message, Throwable cause)76     public ExceptionWithContext(String message, Throwable cause) {
77         super((message != null) ? message :
78               (cause != null) ? cause.getMessage() : null,
79               cause);
80 
81         if (cause instanceof ExceptionWithContext) {
82             String ctx = ((ExceptionWithContext) cause).context.toString();
83             context = new StringBuffer(ctx.length() + 200);
84             context.append(ctx);
85         } else {
86             context = new StringBuffer(200);
87         }
88     }
89 
90     /** {@inheritDoc} */
91     @Override
printStackTrace(PrintStream out)92     public void printStackTrace(PrintStream out) {
93         super.printStackTrace(out);
94         out.println(context);
95     }
96 
97     /** {@inheritDoc} */
98     @Override
printStackTrace(PrintWriter out)99     public void printStackTrace(PrintWriter out) {
100         super.printStackTrace(out);
101         out.println(context);
102     }
103 
104     /**
105      * Adds a line of context to this instance.
106      *
107      * @param str {@code non-null;} new context
108      */
addContext(String str)109     public void addContext(String str) {
110         if (str == null) {
111             throw new NullPointerException("str == null");
112         }
113 
114         context.append(str);
115         if (!str.endsWith("\n")) {
116             context.append('\n');
117         }
118     }
119 
120     /**
121      * Gets the context.
122      *
123      * @return {@code non-null;} the context
124      */
getContext()125     public String getContext() {
126         return context.toString();
127     }
128 
129     /**
130      * Prints the message and context.
131      *
132      * @param out {@code non-null;} where to print to
133      */
printContext(PrintStream out)134     public void printContext(PrintStream out) {
135         out.println(getMessage());
136         out.print(context);
137     }
138 
139     /**
140      * Prints the message and context.
141      *
142      * @param out {@code non-null;} where to print to
143      */
printContext(PrintWriter out)144     public void printContext(PrintWriter out) {
145         out.println(getMessage());
146         out.print(context);
147     }
148 }
149