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