| Level.java |
1 /*
2 * %W% %E%
3 *
4 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8 package java.util.logging;
9 import java.util.ResourceBundle;
10
11 /**
12 * The Level class defines a set of standard logging levels that
13 * can be used to control logging output. The logging Level objects
14 * are ordered and are specified by ordered integers. Enabling logging
15 * at a given level also enables logging at all higher levels.
16 * <p>
17 * Clients should normally use the predefined Level constants such
18 * as Level.SEVERE.
19 * <p>
20 * The levels in descending order are:
21 * <ul>
22 * <li>SEVERE (highest value)
23 * <li>WARNING
24 * <li>INFO
25 * <li>CONFIG
26 * <li>FINE
27 * <li>FINER
28 * <li>FINEST (lowest value)
29 * </ul>
30 * In addition there is a level OFF that can be used to turn
31 * off logging, and a level ALL that can be used to enable
32 * logging of all messages.
33 * <p>
34 * It is possible for third parties to define additional logging
35 * levels by subclassing Level. In such cases subclasses should
36 * take care to chose unique integer level values and to ensure that
37 * they maintain the Object uniqueness property across serialization
38 * by defining a suitable readResolve method.
39 *
40 * @version %I%, %G%
41 * @since 1.4
42 */
43
44 public class Level implements java.io.Serializable {
45 private static java.util.ArrayList known = new java.util.ArrayList();
46 private static String defaultBundle = "sun.util.logging.resources.logging";
47
48 /**
49 * @serial The non-localized name of the level.
50 */
51 private final String name;
52
53 /**
54 * @serial The integer value of the level.
55 */
56 private final int value;
57
58 /**
59 * @serial The resource bundle name to be used in localizing the level name.
60 */
61 private final String resourceBundleName;
62
63 /**
64 * OFF is a special level that can be used to turn off logging.
65 * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
66 */
67 public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
68
69 /**
70 * SEVERE is a message level indicating a serious failure.
71 * <p>
72 * In general SEVERE messages should describe events that are
73 * of considerable importance and which will prevent normal
74 * program execution. They should be reasonably intelligible
75 * to end users and to system administrators.
76 * This level is initialized to <CODE>1000</CODE>.
77 */
78 public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
79
80 /**
81 * WARNING is a message level indicating a potential problem.
82 * <p>
83 * In general WARNING messages should describe events that will
84 * be of interest to end users or system managers, or which
85 * indicate potential problems.
86 * This level is initialized to <CODE>900</CODE>.
87 */
88 public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
89
90 /**
91 * INFO is a message level for informational messages.
92 * <p>
93 * Typically INFO messages will be written to the console
94 * or its equivalent. So the INFO level should only be
95 * used for reasonably significant messages that will
96 * make sense to end users and system admins.
97 * This level is initialized to <CODE>800</CODE>.
98 */
99 public static final Level INFO = new Level("INFO", 800, defaultBundle);
100
101 /**
102 * CONFIG is a message level for static configuration messages.
103 * <p>
104 * CONFIG messages are intended to provide a variety of static
105 * configuration information, to assist in debugging problems
106 * that may be associated with particular configurations.
107 * For example, CONFIG message might include the CPU type,
108 * the graphics depth, the GUI look-and-feel, etc.
109 * This level is initialized to <CODE>700</CODE>.
110 */
111 public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
112
113 /**
114 * FINE is a message level providing tracing information.
115 * <p>
116 * All of FINE, FINER, and FINEST are intended for relatively
117 * detailed tracing. The exact meaning of the three levels will
118 * vary between subsystems, but in general, FINEST should be used
119 * for the most voluminous detailed output, FINER for somewhat
120 * less detailed output, and FINE for the lowest volume (and
121 * most important) messages.
122 * <p>
123 * In general the FINE level should be used for information
124 * that will be broadly interesting to developers who do not have
125 * a specialized interest in the specific subsystem.
126 * <p>
127 * FINE messages might include things like minor (recoverable)
128 * failures. Issues indicating potential performance problems
129 * are also worth logging as FINE.
130 * This level is initialized to <CODE>500</CODE>.
131 */
132 public static final Level FINE = new Level("FINE", 500, defaultBundle);
133
134 /**
135 * FINER indicates a fairly detailed tracing message.
136 * By default logging calls for entering, returning, or throwing
137 * an exception are traced at this level.
138 * This level is initialized to <CODE>400</CODE>.
139 */
140 public static final Level FINER = new Level("FINER", 400, defaultBundle);
141
142 /**
143 * FINEST indicates a highly detailed tracing message.
144 * This level is initialized to <CODE>300</CODE>.
145 */
146 public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
147
148 /**
149 * ALL indicates that all messages should be logged.
150 * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
151 */
152 public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
153
154 /**
155 * Create a named Level with a given integer value.
156 * <p>
157 * Note that this constructor is "protected" to allow subclassing.
158 * In general clients of logging should use one of the constant Level
159 * objects such as SEVERE or FINEST. However, if clients need to
160 * add new logging levels, they may subclass Level and define new
161 * constants.
162 * @param name the name of the Level, for example "SEVERE".
163 * @param value an integer value for the level.
164 * @throws NullPointerException if the name is null
165 */
166 protected Level(String name, int value) {
167 this(name, value, null);
168 }
169
170 /**
171 * Create a named Level with a given integer value and a
172 * given localization resource name.
173 * <p>
174 * @param name the name of the Level, for example "SEVERE".
175 * @param value an integer value for the level.
176 * @param resourceBundleName name of a resource bundle to use in
177 * localizing the given name. If the resourceBundleName is null
178 * or an empty string, it is ignored.
179 * @throws NullPointerException if the name is null
180 */
181 protected Level(String name, int value, String resourceBundleName) {
182 if (name == null) {
183 throw new NullPointerException();
184 }
185 this.name = name;
186 this.value = value;
187 this.resourceBundleName = resourceBundleName;
188 synchronized (Level.class) {
189 known.add(this);
190 }
191 }
192
193 /**
194 * Return the level's localization resource bundle name, or
195 * null if no localization bundle is defined.
196 *
197 * @return localization resource bundle name
198 */
199 public String getResourceBundleName() {
200 return resourceBundleName;
201 }
202
203 /**
204 * Return the non-localized string name of the Level.
205 *
206 * @return non-localized name
207 */
208 public String getName() {
209 return name;
210 }
211
212 /**
213 * Return the localized string name of the Level, for
214 * the current default locale.
215 * <p>
216 * If no localization information is available, the
217 * non-localized name is returned.
218 *
219 * @return localized name
220 */
221 public String getLocalizedName() {
222 try {
223 ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
224 return rb.getString(name);
225 } catch (Exception ex) {
226 return name;
227 }
228 }
229
230 /**
231 * @return the non-localized name of the Level, for example "INFO".
232 */
233 public final String toString() {
234 return name;
235 }
236
237 /**
238 * Get the integer value for this level. This integer value
239 * can be used for efficient ordering comparisons between
240 * Level objects.
241 * @return the integer value for this level.
242 */
243 public final int intValue() {
244 return value;
245 }
246
247 private static final long serialVersionUID = -8176160795706313070L;
248
249 // Serialization magic to prevent "doppelgangers".
250 // This is a performance optimization.
251 private Object readResolve() {
252 synchronized (Level.class) {
253 for (int i = 0; i < known.size(); i++) {
254 Level other = (Level) known.get(i);
255 if (this.name.equals(other.name) && this.value == other.value
256 && (this.resourceBundleName == other.resourceBundleName ||
257 (this.resourceBundleName != null &&
258 this.resourceBundleName.equals(other.resourceBundleName)))) {
259 return other;
260 }
261 }
262 // Woops. Whoever sent us this object knows
263 // about a new log level. Add it to our list.
264 known.add(this);
265 return this;
266 }
267 }
268
269 /**
270 * Parse a level name string into a Level.
271 * <p>
272 * The argument string may consist of either a level name
273 * or an integer value.
274 * <p>
275 * For example:
276 * <ul>
277 * <li> "SEVERE"
278 * <li> "1000"
279 * </ul>
280 * @param name string to be parsed
281 * @throws NullPointerException if the name is null
282 * @throws IllegalArgumentException if the value is not valid.
283 * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
284 * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
285 * Known names are the levels defined by this class (i.e. <CODE>FINE</CODE>,
286 * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
287 * appropriate package access, or new levels defined or created
288 * by subclasses.
289 *
290 * @return The parsed value. Passing an integer that corresponds to a known name
291 * (eg 700) will return the associated name (eg <CODE>CONFIG</CODE>).
292 * Passing an integer that does not (eg 1) will return a new level name
293 * initialized to that value.
294 */
295 public static synchronized Level parse(String name) throws IllegalArgumentException {
296 // Check that name is not null.
297 name.length();
298
299 // Look for a known Level with the given non-localized name.
300 for (int i = 0; i < known.size(); i++) {
301 Level l = (Level) known.get(i);
302 if (name.equals(l.name)) {
303 return l;
304 }
305 }
306
307 // Now, check if the given name is an integer. If so,
308 // first look for a Level with the given value and then
309 // if necessary create one.
310 try {
311 int x = Integer.parseInt(name);
312 for (int i = 0; i < known.size(); i++) {
313 Level l = (Level) known.get(i);
314 if (l.value == x) {
315 return l;
316 }
317 }
318 // Create a new Level.
319 return new Level(name, x);
320 } catch (NumberFormatException ex) {
321 // Not an integer.
322 // Drop through.
323 }
324
325 // Finally, look for a known level with the given localized name,
326 // in the current default locale.
327 // This is relatively expensive, but not excessively so.
328 for (int i = 0; i < known.size(); i++) {
329 Level l = (Level) known.get(i);
330 if (name.equals(l.getLocalizedName())) {
331 return l;
332 }
333 }
334
335 // OK, we've tried everything and failed
336 throw new IllegalArgumentException("Bad level \"" + name + "\"");
337 }
338
339 /**
340 * Compare two objects for value equality.
341 * @return true if and only if the two objects have the same level value.
342 */
343 public boolean equals(Object ox) {
344 try {
345 Level lx = (Level)ox;
346 return (lx.value == this.value);
347 } catch (Exception ex) {
348 return false;
349 }
350 }
351
352 /**
353 * Generate a hashcode.
354 * @return a hashcode based on the level value
355 */
356 public int hashCode() {
357 return this.value;
358 }
359 }
360