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