1 /*
2  * Copyright (C) 2017 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.libcore.timezone.util;
18 
19 import java.io.IOException;
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.util.ArrayList;
23 import java.util.LinkedList;
24 import java.util.List;
25 
26 /**
27  * Stores context, errors and error severity for logging and flow control. This class distinguishes
28  * between warnings (just info), errors (may not be immediately fatal) and fatal (immediately
29  * fatal).
30  */
31 public final class Errors {
32 
33     private final static int LEVEL_WARNING = 1;
34     private final static int LEVEL_ERROR = 2;
35     private final static int LEVEL_FATAL = 3;
36 
37     private int level = 0;
38 
39     private final LinkedList<String> scopes = new LinkedList<>();
40     private final List<String> messages = new ArrayList<>();
41 
Errors()42     public Errors() {
43     }
44 
pushScope(String name)45     public void pushScope(String name) {
46         scopes.add(name);
47     }
48 
popScope()49     public String popScope() {
50         return scopes.removeLast();
51     }
52 
53     /** Adds a fatal error, and immediately throws {@link HaltExecutionException}. */
addFatalAndHalt(String msg)54     public HaltExecutionException addFatalAndHalt(String msg) throws HaltExecutionException {
55         addInternal(msg, null, LEVEL_FATAL);
56         throw new HaltExecutionException("Fatal error");
57     }
58 
59     /** Adds a fatal error, and immediately throws {@link HaltExecutionException}. */
addFatalAndHalt(String msg, Throwable t)60     public HaltExecutionException addFatalAndHalt(String msg, Throwable t)
61             throws HaltExecutionException {
62         addInternal(msg, t, LEVEL_FATAL);
63         throw new HaltExecutionException("Fatal error");
64     }
65 
addError(String msg)66     public void addError(String msg) {
67         addInternal(msg, null, LEVEL_ERROR);
68     }
69 
addError(String msg, Throwable t)70     public void addError(String msg, Throwable t) {
71         addInternal(msg, t, LEVEL_ERROR);
72     }
73 
addWarning(String msg)74     public void addWarning(String msg) {
75         addInternal(msg, null, LEVEL_WARNING);
76     }
77 
asString()78     public String asString() {
79         StringBuilder sb = new StringBuilder();
80         for (String message : messages) {
81             sb.append(message);
82             sb.append("\n");
83         }
84         return sb.toString();
85     }
86 
isEmpty()87     public boolean isEmpty() {
88         return messages.isEmpty();
89     }
90 
91     /** True if there are error or fatal messages. */
hasError()92     public boolean hasError() {
93         return level >= LEVEL_ERROR;
94     }
95 
96     /** True if there are fatal messages. */
hasFatal()97     public boolean hasFatal() {
98         return level >= LEVEL_FATAL;
99     }
100 
addInternal(String msg, Throwable t, int level)101     private void addInternal(String msg, Throwable t, int level) {
102         this.level = Math.max(this.level, level);
103         addMessage(msg);
104         if (t != null) {
105             try (StringWriter out = new StringWriter();
106                     PrintWriter printWriter = new PrintWriter(out)) {
107                 t.printStackTrace(printWriter);
108                 addMessage(out.toString());
109             } catch (IOException e) {
110                 // Impossible - this is actually a compiler bug. Nothing throws IOException above.
111                 throw new AssertionError("Impossible exception thrown", e);
112             }
113         }
114     }
115 
addMessage(String msg)116     private void addMessage(String msg) {
117         messages.add(scopes.toString() + ": " + msg);
118     }
119 
120     /** Throws a {@link HaltExecutionException} if there are any error or fatal messages. */
throwIfError(String why)121     public void throwIfError(String why) throws HaltExecutionException {
122         if (hasError()) {
123             throw new HaltExecutionException(why);
124         }
125     }
126 
127     /** Thrown to halt execution. */
128     public static class HaltExecutionException extends Exception {
HaltExecutionException(String why)129         HaltExecutionException(String why) {
130             super(why);
131         }
132     }
133 }
134