1b4ef06c453f2bdd6109b31785bd8bde9f4eaf56
[policy/apex-pdp.git] / tools / tools-common / src / main / java / org / onap / policy / apex / tools / common / Console.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * 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  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.apex.tools.common;
22
23 import java.io.PrintStream;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.commons.text.StrBuilder;
29 import org.slf4j.ext.XLoggerFactory;
30 import org.slf4j.helpers.MessageFormatter;
31
32 /**
33  * A console for printing messages with functionality similar to loggers. The class provides a static instance for all
34  * parts of an application. The default configuration is to not collect errors or warnings. The default types being
35  * activated are errors, warnings, and info messages.
36  *
37  * @author Sven van der Meer (sven.van.der.meer@ericsson.com)
38  */
39 public final class Console {
40     /** The console as static object. */
41     public static final Console CONSOLE = new Console();
42
43     /** Type for a quiet console, no messages being printed. */
44     public static final int TYPE_QUIET = 0;
45
46     /** Type for printing error messages. */
47     public static final int TYPE_ERROR = 0b0001;
48
49     /** Type for printing warning messages. */
50     public static final int TYPE_WARNING = 0b0010;
51
52     /** Type for printing information messages. */
53     public static final int TYPE_INFO = 0b0100;
54
55     /** Type for printing progress messages. */
56     public static final int TYPE_PROGRESS = 0b1000;
57
58     /** Type for printing debug messages. */
59     public static final int TYPE_DEBUG = 0b001_0000;
60
61     /** Type for printing trace messages. */
62     public static final int TYPE_TRACE = 0b010_0000;
63
64     /** Type for printing stack traces of caught exceptions. */
65     public static final int TYPE_STACKTRACE = 0b110_0000;
66
67     /** Type for a verbose console, activating all message types. */
68     public static final int TYPE_VERBOSE = 0b111_1111;
69
70     /** Configuration for a collecting error messages. */
71     public static final int CONFIG_COLLECT_ERRORS = 0b0001;
72
73     /** Configuration for a collecting warning messages. */
74     public static final int CONFIG_COLLECT_WARNINGS = 0b0010;
75
76     // Input and output streams
77     private static final PrintStream ERR_STREAM = System.err;
78
79     /** The setting for message types, set using type flags. */
80     private int types;
81
82     /** The console configuration, set using configuration flags. */
83     private int configuration;
84
85     /** A name for the application, if set used as prefix for messages. */
86     private String appName;
87
88     /** The list of errors, filled if error collection is activates. */
89     private final List<String> errors;
90
91     /** The list of warnings, filled if warning collection is activates. */
92     private final List<String> warnings;
93
94     /**
95      * Creates a new console. The constructor is private since the class provides static access to an instance. The
96      * default for types is verbose.
97      */
98     private Console() {
99         types = TYPE_VERBOSE;
100
101         configuration = 0;
102         errors = new ArrayList<>();
103         warnings = new ArrayList<>();
104     }
105
106     /**
107      * Sets the application name.
108      *
109      * @param appName new application name, use <code>null</code> to reset the application name, a non-blank string for
110      *        a new name, blank strings are ignored
111      */
112     public void setAppName(final String appName) {
113         if (appName == null) {
114             this.appName = null;
115         } else if (!StringUtils.isBlank(appName)) {
116             this.appName = appName;
117         }
118     }
119
120     /**
121      * Returns the application name.
122      *
123      * @return application name, null if not set, non-blank string otherwise
124      */
125     public String getAppName() {
126         return appName;
127     }
128
129     /**
130      * Activates a type.
131      *
132      * @param type the type to activate
133      */
134     public void activate(final int type) {
135         types = types | type;
136     }
137
138     /**
139      * Deactivates a type.
140      *
141      * @param type type to deactivate
142      */
143     public void deActivate(final int type) {
144         types = types & ~type;
145     }
146
147     /**
148      * Sets the type to the given type, effectively deactivating all other types.
149      *
150      * @param type new type
151      */
152     public void set(final int type) {
153         types = type;
154     }
155
156     /**
157      * Sets the type to the given types, effectively deactivating all other types.
158      *
159      * @param ts array of types to set
160      */
161     public void set(final int... ts) {
162         this.types = 0;
163         for (final int type : ts) {
164             this.activate(type);
165         }
166     }
167
168     /**
169      * Configures the console. Use the configuration flags in combination for the required configuration. For instance,
170      * to collect errors and warnings use <code>CONFIG_COLLECT_ERRORS | CONFIG_COLLECT_WARNINGS</code>.
171      *
172      * @param config the new configuration, overwrites the current configuration, 0 deactivates all settings
173      */
174     public void configure(final int config) {
175         this.configuration = config;
176     }
177
178     /**
179      * Prints an error message with message and objects if {@link #TYPE_ERROR} is set; and increases the error count.
180      * Errors are collected (if configuration is set) and the error counter is increased regardless of the console error
181      * type settings.
182      *
183      * @param message the error message, using the same format as the SLF4J MessageFormatter, nothing done if
184      *        <code>blank</code>
185      * @param objects the objects for substitution in the message
186      */
187     public void error(final String message, final Object... objects) {
188         if (StringUtils.isBlank(message)) {
189             return;
190         }
191
192         final StrBuilder err = new StrBuilder();
193         if (appName != null) {
194             err.append(this.getAppName()).append(": ");
195         }
196         err.append("error: ");
197         err.append(MessageFormatter.arrayFormat(message, objects).getMessage());
198
199         if ((types & TYPE_ERROR) == TYPE_ERROR) {
200             ERR_STREAM.println(err.build());
201         }
202         if ((configuration & CONFIG_COLLECT_ERRORS) == CONFIG_COLLECT_ERRORS) {
203             errors.add(err.build());
204         }
205     }
206
207     /**
208      * Prints a warning message with message and objects if {@link #TYPE_WARNING} is set; and increases the warning
209      * count. Warnings are collected (if configuration is set) and the warning counter is increased regardless of the
210      * console warning type settings.
211      *
212      * @param message the warning message, using the same format as the SLF4J MessageFormatter, nothing done if
213      *        <code>blank</code>
214      * @param objects the objects for substitution in the message
215      */
216     public void warn(final String message, final Object... objects) {
217         if (StringUtils.isBlank(message)) {
218             return;
219         }
220
221         final StrBuilder warn = new StrBuilder();
222         if (appName != null) {
223             warn.append(this.getAppName()).append(": ");
224         }
225         warn.append("warning: ");
226         warn.append(MessageFormatter.arrayFormat(message, objects).getMessage());
227
228         if ((types & TYPE_WARNING) == TYPE_WARNING) {
229             ERR_STREAM.println(warn.build());
230         }
231         if ((configuration & CONFIG_COLLECT_WARNINGS) == CONFIG_COLLECT_WARNINGS) {
232             warnings.add(warn.build());
233         }
234     }
235
236     /**
237      * Prints an info message with message and objects if {@link #TYPE_INFO} is set.
238      *
239      * @param message the warning message, using the same format as the SLF4J MessageFormatter, nothing done if
240      *        <code>blank</code>
241      * @param objects the objects for substitution in the message
242      */
243     public void info(final String message, final Object... objects) {
244         if (StringUtils.isBlank(message)) {
245             return;
246         }
247
248         if ((types & TYPE_INFO) == TYPE_INFO) {
249             if (appName != null) {
250                 ERR_STREAM.print(appName + ": ");
251             }
252             ERR_STREAM.println(MessageFormatter.arrayFormat(message, objects).getMessage());
253         }
254     }
255
256     /**
257      * Prints a progress message with message and objects if {@link #TYPE_PROGRESS} is set.
258      *
259      * @param message the warning message, using the same format as the SLF4J MessageFormatter, nothing done if
260      *        <code>blank</code>
261      * @param objects the objects for substitution in the message
262      */
263     public void progress(final String message, final Object... objects) {
264         if (StringUtils.isBlank(message)) {
265             return;
266         }
267
268         if ((types & TYPE_PROGRESS) == TYPE_PROGRESS) {
269             if (appName != null) {
270                 ERR_STREAM.print(appName + ": ");
271             }
272             ERR_STREAM.print("progress: ");
273             ERR_STREAM.println(MessageFormatter.arrayFormat(message, objects).getMessage());
274         }
275     }
276
277     /**
278      * Prints a debug message with message and objects if {@link #TYPE_DEBUG} is set.
279      *
280      * @param message the warning message, using the same format as the SLF4J MessageFormatter, nothing done if
281      *        <code>blank</code>
282      * @param objects the objects for substitution in the message
283      */
284     public void debug(final String message, final Object... objects) {
285         if (StringUtils.isBlank(message)) {
286             return;
287         }
288
289         if ((types & TYPE_DEBUG) == TYPE_DEBUG) {
290             if (appName != null) {
291                 ERR_STREAM.print(appName + ": ");
292             }
293             ERR_STREAM.print("debug: ");
294             ERR_STREAM.println(MessageFormatter.arrayFormat(message, objects).getMessage());
295         }
296     }
297
298     /**
299      * Prints a trace message with message and objects if {@link #TYPE_TRACE} is set.
300      *
301      * @param message the warning message, using the same format as the SLF4J MessageFormatter, nothing done if
302      *        <code>blank</code>
303      * @param objects the objects for substitution in the message
304      */
305     public void trace(final String message, final Object... objects) {
306         if (StringUtils.isBlank(message)) {
307             return;
308         }
309
310         if ((types & TYPE_TRACE) == TYPE_TRACE) {
311             if (appName != null) {
312                 ERR_STREAM.print(appName + ": ");
313             }
314             ERR_STREAM.print("trace: ");
315             ERR_STREAM.println(MessageFormatter.arrayFormat(message, objects).getMessage());
316         }
317     }
318
319     /**
320      * Prints message, cause, and stack trace for a given exception if {@link #TYPE_STACKTRACE} is set.
321      *
322      * @param exception the exception to print, ignored if <code>null</code>
323      */
324     public void stacktrace(final Exception exception) {
325         if (exception == null) {
326             return;
327         }
328
329         if ((types & TYPE_STACKTRACE) == TYPE_STACKTRACE) {
330             if (appName != null) {
331                 ERR_STREAM.print(appName + ": ");
332             }
333             ERR_STREAM.println(" exception message: " + exception.getMessage());
334             if (exception.getCause() != null) {
335                 ERR_STREAM.println(" exception cause: " + exception.getCause());
336             }
337             ERR_STREAM.println("for exception stack trace, please refer logs.");
338             XLoggerFactory.getXLogger(Console.class).error("stacktrace", exception);
339         }
340     }
341
342     /**
343      * Resets the error counter and the list of errors.
344      */
345     public void resetErrors() {
346         errors.clear();
347     }
348
349     /**
350      * Resets the warning counter and the list of warnings.
351      */
352     public void resetWarnings() {
353         warnings.clear();
354     }
355
356 }