001 /*
002 * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.util.logging;
027
028 import java.util.ResourceBundle;
029
030 /**
031 * The Level class defines a set of standard logging levels that
032 * can be used to control logging output. The logging Level objects
033 * are ordered and are specified by ordered integers. Enabling logging
034 * at a given level also enables logging at all higher levels.
035 * <p>
036 * Clients should normally use the predefined Level constants such
037 * as Level.SEVERE.
038 * <p>
039 * The levels in descending order are:
040 * <ul>
041 * <li>SEVERE (highest value)
042 * <li>WARNING
043 * <li>INFO
044 * <li>CONFIG
045 * <li>FINE
046 * <li>FINER
047 * <li>FINEST (lowest value)
048 * </ul>
049 * In addition there is a level OFF that can be used to turn
050 * off logging, and a level ALL that can be used to enable
051 * logging of all messages.
052 * <p>
053 * It is possible for third parties to define additional logging
054 * levels by subclassing Level. In such cases subclasses should
055 * take care to chose unique integer level values and to ensure that
056 * they maintain the Object uniqueness property across serialization
057 * by defining a suitable readResolve method.
058 *
059 * @version 1.27, 05/09/07
060 * @since 1.4
061 */
062
063 public class Level implements java.io.Serializable {
064 private static java.util.ArrayList<Level> known = new java.util.ArrayList<Level>();
065 private static String defaultBundle = "sun.util.logging.resources.logging";
066
067 /**
068 * @serial The non-localized name of the level.
069 */
070 private final String name;
071
072 /**
073 * @serial The integer value of the level.
074 */
075 private final int value;
076
077 /**
078 * @serial The resource bundle name to be used in localizing the level name.
079 */
080 private final String resourceBundleName;
081
082 /**
083 * OFF is a special level that can be used to turn off logging.
084 * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
085 */
086 public static final Level OFF = new Level("OFF", Integer.MAX_VALUE,
087 defaultBundle);
088
089 /**
090 * SEVERE is a message level indicating a serious failure.
091 * <p>
092 * In general SEVERE messages should describe events that are
093 * of considerable importance and which will prevent normal
094 * program execution. They should be reasonably intelligible
095 * to end users and to system administrators.
096 * This level is initialized to <CODE>1000</CODE>.
097 */
098 public static final Level SEVERE = new Level("SEVERE", 1000,
099 defaultBundle);
100
101 /**
102 * WARNING is a message level indicating a potential problem.
103 * <p>
104 * In general WARNING messages should describe events that will
105 * be of interest to end users or system managers, or which
106 * indicate potential problems.
107 * This level is initialized to <CODE>900</CODE>.
108 */
109 public static final Level WARNING = new Level("WARNING", 900,
110 defaultBundle);
111
112 /**
113 * INFO is a message level for informational messages.
114 * <p>
115 * Typically INFO messages will be written to the console
116 * or its equivalent. So the INFO level should only be
117 * used for reasonably significant messages that will
118 * make sense to end users and system admins.
119 * This level is initialized to <CODE>800</CODE>.
120 */
121 public static final Level INFO = new Level("INFO", 800,
122 defaultBundle);
123
124 /**
125 * CONFIG is a message level for static configuration messages.
126 * <p>
127 * CONFIG messages are intended to provide a variety of static
128 * configuration information, to assist in debugging problems
129 * that may be associated with particular configurations.
130 * For example, CONFIG message might include the CPU type,
131 * the graphics depth, the GUI look-and-feel, etc.
132 * This level is initialized to <CODE>700</CODE>.
133 */
134 public static final Level CONFIG = new Level("CONFIG", 700,
135 defaultBundle);
136
137 /**
138 * FINE is a message level providing tracing information.
139 * <p>
140 * All of FINE, FINER, and FINEST are intended for relatively
141 * detailed tracing. The exact meaning of the three levels will
142 * vary between subsystems, but in general, FINEST should be used
143 * for the most voluminous detailed output, FINER for somewhat
144 * less detailed output, and FINE for the lowest volume (and
145 * most important) messages.
146 * <p>
147 * In general the FINE level should be used for information
148 * that will be broadly interesting to developers who do not have
149 * a specialized interest in the specific subsystem.
150 * <p>
151 * FINE messages might include things like minor (recoverable)
152 * failures. Issues indicating potential performance problems
153 * are also worth logging as FINE.
154 * This level is initialized to <CODE>500</CODE>.
155 */
156 public static final Level FINE = new Level("FINE", 500,
157 defaultBundle);
158
159 /**
160 * FINER indicates a fairly detailed tracing message.
161 * By default logging calls for entering, returning, or throwing
162 * an exception are traced at this level.
163 * This level is initialized to <CODE>400</CODE>.
164 */
165 public static final Level FINER = new Level("FINER", 400,
166 defaultBundle);
167
168 /**
169 * FINEST indicates a highly detailed tracing message.
170 * This level is initialized to <CODE>300</CODE>.
171 */
172 public static final Level FINEST = new Level("FINEST", 300,
173 defaultBundle);
174
175 /**
176 * ALL indicates that all messages should be logged.
177 * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
178 */
179 public static final Level ALL = new Level("ALL", Integer.MIN_VALUE,
180 defaultBundle);
181
182 /**
183 * Create a named Level with a given integer value.
184 * <p>
185 * Note that this constructor is "protected" to allow subclassing.
186 * In general clients of logging should use one of the constant Level
187 * objects such as SEVERE or FINEST. However, if clients need to
188 * add new logging levels, they may subclass Level and define new
189 * constants.
190 * @param name the name of the Level, for example "SEVERE".
191 * @param value an integer value for the level.
192 * @throws NullPointerException if the name is null
193 */
194 protected Level(String name, int value) {
195 this (name, value, null);
196 }
197
198 /**
199 * Create a named Level with a given integer value and a
200 * given localization resource name.
201 * <p>
202 * @param name the name of the Level, for example "SEVERE".
203 * @param value an integer value for the level.
204 * @param resourceBundleName name of a resource bundle to use in
205 * localizing the given name. If the resourceBundleName is null
206 * or an empty string, it is ignored.
207 * @throws NullPointerException if the name is null
208 */
209 protected Level(String name, int value, String resourceBundleName) {
210 if (name == null) {
211 throw new NullPointerException();
212 }
213 this .name = name;
214 this .value = value;
215 this .resourceBundleName = resourceBundleName;
216 synchronized (Level.class) {
217 known.add(this );
218 }
219 }
220
221 /**
222 * Return the level's localization resource bundle name, or
223 * null if no localization bundle is defined.
224 *
225 * @return localization resource bundle name
226 */
227 public String getResourceBundleName() {
228 return resourceBundleName;
229 }
230
231 /**
232 * Return the non-localized string name of the Level.
233 *
234 * @return non-localized name
235 */
236 public String getName() {
237 return name;
238 }
239
240 /**
241 * Return the localized string name of the Level, for
242 * the current default locale.
243 * <p>
244 * If no localization information is available, the
245 * non-localized name is returned.
246 *
247 * @return localized name
248 */
249 public String getLocalizedName() {
250 try {
251 ResourceBundle rb = ResourceBundle
252 .getBundle(resourceBundleName);
253 return rb.getString(name);
254 } catch (Exception ex) {
255 return name;
256 }
257 }
258
259 /**
260 * @return the non-localized name of the Level, for example "INFO".
261 */
262 public final String toString() {
263 return name;
264 }
265
266 /**
267 * Get the integer value for this level. This integer value
268 * can be used for efficient ordering comparisons between
269 * Level objects.
270 * @return the integer value for this level.
271 */
272 public final int intValue() {
273 return value;
274 }
275
276 private static final long serialVersionUID = -8176160795706313070L;
277
278 // Serialization magic to prevent "doppelgangers".
279 // This is a performance optimization.
280 private Object readResolve() {
281 synchronized (Level.class) {
282 for (int i = 0; i < known.size(); i++) {
283 Level other = (Level) known.get(i);
284 if (this .name.equals(other.name)
285 && this .value == other.value
286 && (this .resourceBundleName == other.resourceBundleName || (this .resourceBundleName != null && this .resourceBundleName
287 .equals(other.resourceBundleName)))) {
288 return other;
289 }
290 }
291 // Woops. Whoever sent us this object knows
292 // about a new log level. Add it to our list.
293 known.add(this );
294 return this ;
295 }
296 }
297
298 /**
299 * Parse a level name string into a Level.
300 * <p>
301 * The argument string may consist of either a level name
302 * or an integer value.
303 * <p>
304 * For example:
305 * <ul>
306 * <li> "SEVERE"
307 * <li> "1000"
308 * </ul>
309 * @param name string to be parsed
310 * @throws NullPointerException if the name is null
311 * @throws IllegalArgumentException if the value is not valid.
312 * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
313 * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
314 * Known names are the levels defined by this class (i.e. <CODE>FINE</CODE>,
315 * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
316 * appropriate package access, or new levels defined or created
317 * by subclasses.
318 *
319 * @return The parsed value. Passing an integer that corresponds to a known name
320 * (eg 700) will return the associated name (eg <CODE>CONFIG</CODE>).
321 * Passing an integer that does not (eg 1) will return a new level name
322 * initialized to that value.
323 */
324 public static synchronized Level parse(String name)
325 throws IllegalArgumentException {
326 // Check that name is not null.
327 name.length();
328
329 // Look for a known Level with the given non-localized name.
330 for (int i = 0; i < known.size(); i++) {
331 Level l = (Level) known.get(i);
332 if (name.equals(l.name)) {
333 return l;
334 }
335 }
336
337 // Now, check if the given name is an integer. If so,
338 // first look for a Level with the given value and then
339 // if necessary create one.
340 try {
341 int x = Integer.parseInt(name);
342 for (int i = 0; i < known.size(); i++) {
343 Level l = (Level) known.get(i);
344 if (l.value == x) {
345 return l;
346 }
347 }
348 // Create a new Level.
349 return new Level(name, x);
350 } catch (NumberFormatException ex) {
351 // Not an integer.
352 // Drop through.
353 }
354
355 // Finally, look for a known level with the given localized name,
356 // in the current default locale.
357 // This is relatively expensive, but not excessively so.
358 for (int i = 0; i < known.size(); i++) {
359 Level l = known.get(i);
360 if (name.equals(l.getLocalizedName())) {
361 return l;
362 }
363 }
364
365 // OK, we've tried everything and failed
366 throw new IllegalArgumentException("Bad level \"" + name + "\"");
367 }
368
369 /**
370 * Compare two objects for value equality.
371 * @return true if and only if the two objects have the same level value.
372 */
373 public boolean equals(Object ox) {
374 try {
375 Level lx = (Level) ox;
376 return (lx.value == this .value);
377 } catch (Exception ex) {
378 return false;
379 }
380 }
381
382 /**
383 * Generate a hashcode.
384 * @return a hashcode based on the level value
385 */
386 public int hashCode() {
387 return this.value;
388 }
389 }
|