1 /*
2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.jshell.debug;
27 
28 import java.io.PrintStream;
29 import java.util.HashMap;
30 import java.util.Map;
31 import jdk.jshell.JShell;
32 
33 /**
34  * This class is used to externally control output messages for debugging the
35  * implementation of the JShell API.
36  * <p>
37  * This is not part of the SPI nor API.
38  */
39 public class InternalDebugControl {
40 
41     /**
42      * This is a static only class; The constructor should never be called.
43      */
InternalDebugControl()44     private InternalDebugControl() {
45     }
46 
47     /**
48      * General debugging.
49      */
50     public static final int DBG_GEN = 0b0000001;
51 
52     /**
53      * File manager debuging.
54      */
55     public static final int DBG_FMGR = 0b0000010;
56 
57     /**
58      * Completion analysis debugging.
59      */
60     public static final int DBG_COMPA = 0b0000100;
61 
62     /**
63      * Dependency debugging.
64      */
65     public static final int DBG_DEP = 0b0001000;
66 
67     /**
68      * Event debugging.
69      */
70     public static final int DBG_EVNT = 0b0010000;
71 
72     /**
73      * Event debugging.
74      */
75     public static final int DBG_WRAP = 0b0100000;
76 
77     private static Map<JShell, Integer> debugMap = null;
78 
79     /**
80      * Sets which debug flags are enabled for a given JShell instance. The flags
81      * are or'ed bits as defined in {@code DBG_*}.
82      *
83      * @param state the JShell instance
84      * @param flags the or'ed debug bits
85      */
setDebugFlags(JShell state, int flags)86     public static void setDebugFlags(JShell state, int flags) {
87         if (debugMap == null) {
88             debugMap = new HashMap<>();
89         }
90         debugMap.put(state, flags);
91     }
92 
93     /**
94      * Release a JShell instance.
95      *
96      * @param state the JShell instance
97      */
release(JShell state)98     public static void release(JShell state) {
99         if (debugMap != null) {
100             debugMap.remove(state);
101         }
102     }
103 
104     /**
105      * Tests if any of the specified debug flags are enabled.
106      *
107      * @param state the JShell instance
108      * @param flag the {@code DBG_*} bits to check
109      * @return true if any of the flags are enabled
110      */
isDebugEnabled(JShell state, int flag)111     public static boolean isDebugEnabled(JShell state, int flag) {
112         if (debugMap == null) {
113             return false;
114         }
115         Integer flags = debugMap.get(state);
116         if (flags == null) {
117             return false;
118         }
119         return (flags & flag) != 0;
120     }
121 
122     /**
123      * Displays debug info if the specified debug flags are enabled.
124      *
125      * @param state the current JShell instance
126      * @param err the {@code PrintStream} to report on
127      * @param flags {@code DBG_*} flag bits to check
128      * @param format format string for the output
129      * @param args args for the format string
130      */
debug(JShell state, PrintStream err, int flags, String format, Object... args)131     public static void debug(JShell state, PrintStream err, int flags, String format, Object... args) {
132         if (isDebugEnabled(state, flags)) {
133             err.printf(format, args);
134         }
135     }
136 
137     /**
138      * Displays a fatal exception as debug info.
139      *
140      * @param state the current JShell instance
141      * @param err the {@code PrintStream} to report on
142      * @param ex the fatal Exception
143      * @param where additional context
144      */
debug(JShell state, PrintStream err, Throwable ex, String where)145     public static void debug(JShell state, PrintStream err, Throwable ex, String where) {
146         if (isDebugEnabled(state, 0xFFFFFFFF)) {
147             err.printf("Fatal error: %s: %s\n", where, ex.getMessage());
148             ex.printStackTrace(err);
149         }
150     }
151 }
152