Source code: com/port80/util/Debug.java
1 /** Debug mode configuration.
2 */
3
4 //
5 // Copyright(c) 2002, Chris Leung
6 //
7
8 package com.port80.util;
9
10 import java.util.*;
11
12 /** Debug mode and related utilities to selectively enable specific debug modes.
13 Debug.set('*') enables all debug modes. Modes 'debug','trace','test','verbose','check'
14 exists by default (but disabled except 'test' is default enabled) on startup
15 and after Debug.clear().
16
17 Builtin modes:
18 debug Turns on debug messages.
19 trace Turns on trace messages.
20 test Turns on test messages, which are temporary and would normally remove
21 from source code after the testing.
22 verbose Turns on verbose messages during normal execution.
23 check Turns on check mode code, which provide additional sanity checkings that
24 normal execution should skip.
25
26 USAGE:
27
28 . Note that all data and methods are static.
29
30 . For class that have custom debug mode, it should add the mode in a static initialization block:
31
32 static { Debug.add("package.classname"); }
33
34 The added mode by default is disabled. However, if the mode already exist add() would not change
35 its enable/disable state.
36
37 . The main program is responsible for enabling the specific debug modes by the enable() method.
38 Since the static initialization are executed when the class is loaded, it may be initialized
39 after the main program command line processing. The command line processing can enable specific
40 modes, in that case, the static initialization would be change the enable/disable state.
41 The command line processing call enable() with a wildcard ('*') pattern. In that case, the
42 modes that match the pattern would be enabled when it is added.
43
44 enable("specific-mode"); // Enable a single mode.
45 enable("wildcard*pattern"); // Enable all existing and future added modes that match the pattern.
46
47 . There is also disable() methods, however, they should be used sparsely when really neccessary.
48 If there are contradicting enable and disable wildcard patterns, the result is undetermined.
49
50 . It is the main program's main method repsonsible for enable/disable debugging of a particular module
51 (after checking command line options).
52
53 . Each module check (static) whether it is required to run in debug mode:
54
55 public static boolean DEBUG=Debug.isEnabled(<packagename>)||Debug.isEnabled(<packgename.classname>);
56
57 */
58
59 public class Debug {
60
61 static private final Boolean ENABLE =new Boolean(true);
62 static private final Boolean DISABLE =new Boolean(false);
63
64 static private Map theModes =null;
65 static private Map theDefaults =null;
66
67 static {init();}
68
69 static public void clear() {init();}
70
71 /** Enable a list of debug modes.
72 *
73 * @param s The debug mode is added if not already exist.
74 * The mode string can also be use wildcard '*' to enable
75 * multiple modes. In that case, all existing and future modes
76 * that match the pattern would be enabled.
77 *
78 * Due to the way Java initialized static variables, which initialized dynamically
79 * when the class is loaded. The static initialization that add debug modes may
80 * not be executed even during command line processing of the main class. So we
81 * have to keep the wild card pattern from command line options and apply them
82 * when new modes are added.
83 */
84 static public void enable(List modes) {
85 if(theModes==null) init();
86 if(modes==null) return;
87 for(int i=0; i<modes.size(); i++) {
88 String mode=(String)modes.get(i);
89 if(mode.indexOf('*')==-1) {
90 theModes.put(mode,ENABLE);
91 msg.debug("Debug.enable(): mode="+mode);
92 continue;
93 }
94 // Wild card.
95 mode=msg.subst("s/\\*/.*/g",mode);
96 // Enable future added modes that match.
97 theDefaults.put(mode,ENABLE);
98 // Enable existing modes that match.
99 TreeSet keys=new TreeSet(theModes.keySet());
100 for(Iterator it=keys.iterator(); it.hasNext();) {
101 String key=(String)it.next();
102 if(msg.match("/"+mode+"/",key)) {
103 theModes.put(key,ENABLE);
104 msg.debug("Debug.enable(): matched: pattern="+mode+", key="+key);
105 }
106 }
107 }
108 }
109
110 static public void enable(String modes) {
111 if(theModes==null) init();
112 if(modes==null) return;
113 enable(msg.split("/,/",modes));
114 }
115
116 /** Disable a list of debug mode.
117 *
118 * @param modes List of modes to be disabled. If not yet exist, the modes would be added.
119 * Wildcard pattern can be used and in that case all existing and future modes
120 * added that match the pattern would be disabled.
121 */
122 static public void disable(List modes) {
123 if(theModes==null) init();
124 if(modes==null) return;
125 for(int i=0; i<modes.size(); i++) {
126 String mode=(String)modes.get(i);
127 if(mode.indexOf('*')==-1) {
128 theModes.put(mode,DISABLE );
129 msg.debug("Debug.disable(): mode="+mode);
130 continue;
131 }
132 // Wild card.
133 mode=msg.subst("s/\\*/.*/g",mode);
134 // Enable future added modes that match.
135 theDefaults.put(mode,DISABLE);
136 // Enable existing modes that match.
137 TreeSet keys=new TreeSet(theModes.keySet());
138 for(Iterator it=keys.iterator(); it.hasNext();) {
139 String key=(String)it.next();
140 if(msg.match("/"+mode+"/",key)) {
141 msg.debug("Debug.disable(): matched: pattern="+mode+", key="+key);
142 theModes.put(key,DISABLE);
143 }
144 }
145 }
146 }
147
148 static public void disable(String modes) {
149 if(theModes==null) init();
150 if(modes==null) return;
151 disable(msg.split("/,/",modes));
152 }
153
154 /** Add a mode, by default disabled. If the mode already exist, its enable/disable state
155 * would not be changed. If the mode match any wildcard patterns (specified in previous
156 * enable() or disable() calls), it would be enable/disabled accordingly.
157 *
158 * @param mode The mode to be added. No wildcard allowed here.
159 */
160 static public void add (String mode) {
161 if(theModes==null) init();
162 Object modeObject=theModes.get(mode);
163 if (modeObject!=null) return;
164 // New added, disable by default.
165 theModes.put(mode,DISABLE);
166 // Check pattern table.
167 TreeSet keys=new TreeSet(theDefaults.keySet());
168 for(Iterator it=keys.iterator(); it.hasNext(); ) {
169 String key=(String)it.next();
170 Boolean value=(Boolean)theDefaults.get(key);
171 if(msg.match("/^"+key+"$/",mode)) {
172 theModes.put(mode,value);
173 }
174 }
175 msg.debug("Debug.add(): mode="+mode+", value="+theModes.get(mode).toString());
176 }
177
178 /** Add a mode and optionally enable it.
179 *
180 * @param on true = enable the added mode.
181 */
182 static public void add (String s, boolean on) {
183 if(theModes==null) init();
184 theModes.put(s, (on? ENABLE: DISABLE));
185 }
186
187 ////////////////////
188
189 /** Return the name of all declared debug modes.
190 */
191 static public List getModes() {
192 List keys = new Vector(new TreeSet(theModes.keySet()));
193 return keys;
194 }
195
196 /** Return the name of all debug modes that are enabled.
197 */
198 static public List getEnables() {
199 List ret=msg.newListInstance();
200 TreeSet keys = new TreeSet(theModes.keySet());
201 for(Iterator it=keys.iterator(); it.hasNext();) {
202 Object key=it.next();
203 Boolean value=(Boolean)theModes.get(key);
204 if(value.booleanValue()) ret.add(key);
205 }
206 return ret;
207 }
208
209 /** Return the name of all debug modes that are disabled.
210 */
211 static public List getDisables() {
212 List ret=msg.newListInstance();
213 TreeSet keys = new TreeSet(theModes.keySet());
214 for(Iterator it=keys.iterator(); it.hasNext();) {
215 Object key=it.next();
216 Boolean value=(Boolean)theModes.get(key);
217 if(!value.booleanValue()) ret.add(key);
218 }
219 return ret;
220 }
221
222 static public boolean isEnabled (String s) {
223 if(!isDebug()) return false;
224 Object o = theModes.get(s);
225 return ( o != null && ((Boolean)o).booleanValue() );
226 }
227
228 //////////////////// Some predefined mode and shortcut.
229
230 static public boolean isOn() {
231 return ((Boolean)theModes.get("debug")).booleanValue();
232 }
233 static public boolean isDebug() {
234 return ((Boolean)theModes.get("debug")).booleanValue();
235 }
236 static public boolean isTrace() {
237 return ((Boolean)theModes.get("trace")).booleanValue();
238 }
239 static public boolean isTest() {
240 return ((Boolean)theModes.get("test")).booleanValue();
241 }
242 static public boolean isVerbose() {
243 return ((Boolean)theModes.get("verbose")).booleanValue();
244 }
245 static public boolean isCheck() {
246 return ((Boolean)theModes.get("check")).booleanValue();
247 }
248
249 /** Same as enable(),disable(),isEnabled(),isDebug()...etc. */
250 static public void set (String s) {enable(s);}
251 static public void reset (String s) {disable(s);}
252 static public boolean get (String s) {return isEnabled(s);}
253 static public boolean on() { return isDebug(); }
254 static public boolean debug() { return isDebug(); }
255 static public boolean trace() { return isTrace(); }
256 static public boolean test() { return isTest(); }
257 static public boolean verbose() { return isVerbose(); }
258 static public boolean check() { return isCheck(); }
259
260 //////////////////// Private ////////////////////
261
262 static private void init() {
263 theModes=msg.newMapInstance();
264 theDefaults=msg.newMapInstance();
265 theModes.put("debug", DISABLE);
266 theModes.put("trace", DISABLE);
267 theModes.put("test", DISABLE);
268 theModes.put("verbose", DISABLE);
269 theModes.put("check", DISABLE);
270 }
271
272 }