001/* Level.java -- a class for indicating logging levels 002 Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.util.logging; 040 041import java.io.Serializable; 042import java.util.ResourceBundle; 043 044/** 045 * A class for indicating logging levels. A number of commonly used 046 * levels is pre-defined (such as <code>java.util.logging.Level.INFO</code>), 047 * and applications should utilize those whenever possible. For specialized 048 * purposes, however, applications can sub-class Level in order to define 049 * custom logging levels. 050 * 051 * @author Sascha Brawer (brawer@acm.org) 052 */ 053public class Level implements Serializable 054{ 055 /* The integer values are the same as in the Sun J2SE 1.4. 056 * They have been obtained with a test program. In J2SE 1.4.1, 057 * Sun has amended the API documentation; these values are now 058 * publicly documented. 059 */ 060 061 /** 062 * The <code>OFF</code> level is used as a threshold for filtering 063 * log records, meaning that no message should be logged. 064 * 065 * @see Logger#setLevel(java.util.logging.Level) 066 */ 067 public static final Level OFF = new Level ("OFF", Integer.MAX_VALUE); 068 069 /** 070 * Log records whose level is <code>SEVERE</code> indicate a serious 071 * failure that prevents normal program execution. Messages at this 072 * level should be understandable to an inexperienced, non-technical 073 * end user. Ideally, they explain in simple words what actions the 074 * user can take in order to resolve the problem. 075 */ 076 public static final Level SEVERE = new Level ("SEVERE", 1000); 077 078 079 /** 080 * Log records whose level is <code>WARNING</code> indicate a 081 * potential problem that does not prevent normal program execution. 082 * Messages at this level should be understandable to an 083 * inexperienced, non-technical end user. Ideally, they explain in 084 * simple words what actions the user can take in order to resolve 085 * the problem. 086 */ 087 public static final Level WARNING = new Level ("WARNING", 900); 088 089 090 /** 091 * Log records whose level is <code>INFO</code> are used in purely 092 * informational situations that do not constitute serious errors or 093 * potential problems. In the default logging configuration, INFO 094 * messages will be written to the system console. For this reason, 095 * the INFO level should be used only for messages that are 096 * important to end users and system administrators. Messages at 097 * this level should be understandable to an inexperienced, 098 * non-technical user. 099 */ 100 public static final Level INFO = new Level ("INFO", 800); 101 102 103 /** 104 * Log records whose level is <code>CONFIG</code> are used for 105 * describing the static configuration, for example the windowing 106 * environment, the operating system version, etc. 107 */ 108 public static final Level CONFIG = new Level ("CONFIG", 700); 109 110 111 /** 112 * Log records whose level is <code>FINE</code> are typically used 113 * for messages that are relevant for developers using 114 * the component generating log messages. Examples include minor, 115 * recoverable failures, or possible inefficiencies. 116 */ 117 public static final Level FINE = new Level ("FINE", 500); 118 119 120 /** 121 * Log records whose level is <code>FINER</code> are intended for 122 * rather detailed tracing, for example entering a method, returning 123 * from a method, or throwing an exception. 124 */ 125 public static final Level FINER = new Level ("FINER", 400); 126 127 128 /** 129 * Log records whose level is <code>FINEST</code> are used for 130 * highly detailed tracing, for example to indicate that a certain 131 * point inside the body of a method has been reached. 132 */ 133 public static final Level FINEST = new Level ("FINEST", 300); 134 135 136 /** 137 * The <code>ALL</code> level is used as a threshold for filtering 138 * log records, meaning that every message should be logged. 139 * 140 * @see Logger#setLevel(java.util.logging.Level) 141 */ 142 public static final Level ALL = new Level ("ALL", Integer.MIN_VALUE); 143 144 145 private static final Level[] knownLevels = { 146 ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, OFF 147 }; 148 149 150 /** 151 * The name of the Level without localizing it, for example 152 * "WARNING". 153 */ 154 private String name; 155 156 157 /** 158 * The integer value of this <code>Level</code>. 159 */ 160 private int value; 161 162 163 /** 164 * The name of the resource bundle used for localizing the level 165 * name, or <code>null</code> if the name does not undergo 166 * localization. 167 */ 168 private String resourceBundleName; 169 170 171 /** 172 * Creates a logging level given a name and an integer value. 173 * It rarely is necessary to create custom levels, 174 * as most applications should be well served with one of the 175 * standard levels such as <code>Level.CONFIG</code>, 176 * <code>Level.INFO</code>, or <code>Level.FINE</code>. 177 * 178 * @param name the name of the level. 179 * 180 * @param value the integer value of the level. Please note 181 * that the Java<small><sup>TM</sup></small> 182 * Logging API does not specify integer 183 * values for standard levels (such as 184 * Level.FINE). Therefore, a custom 185 * level should pass an integer value that 186 * is calculated at run-time, e.g. 187 * <code>(Level.FINE.intValue() + Level.CONFIG.intValue()) 188 * / 2</code> for a level between FINE and CONFIG. 189 */ 190 protected Level(String name, int value) 191 { 192 this(name, value, null); 193 } 194 195 196 /** 197 * Create a logging level given a name, an integer value and a name 198 * of a resource bundle for localizing the level name. It rarely 199 * is necessary to create custom levels, as most applications 200 * should be well served with one of the standard levels such as 201 * <code>Level.CONFIG</code>, <code>Level.INFO</code>, or 202 * <code>Level.FINE</code>. 203 * 204 * @param name the name of the level. 205 * 206 * @param value the integer value of the level. Please note 207 * that the Java<small><sup>TM</sup></small> 208 * Logging API does not specify integer 209 * values for standard levels (such as 210 * Level.FINE). Therefore, a custom 211 * level should pass an integer value that 212 * is calculated at run-time, e.g. 213 * <code>(Level.FINE.intValue() + Level.CONFIG.intValue()) 214 * / 2</code> for a level between FINE and CONFIG. 215 * 216 * @param resourceBundleName the name of a resource bundle 217 * for localizing the level name, or <code>null</code> 218 * if the name does not need to be localized. 219 */ 220 protected Level(String name, int value, String resourceBundleName) 221 { 222 this.name = name; 223 this.value = value; 224 this.resourceBundleName = resourceBundleName; 225 } 226 227 228 static final long serialVersionUID = -8176160795706313070L; 229 230 231 /** 232 * Checks whether the Level has the same intValue as one of the 233 * pre-defined levels. If so, the pre-defined level object is 234 * returned. 235 * 236 * <br/>Since the resource bundle name is not taken into 237 * consideration, it is possible to resolve Level objects that have 238 * been de-serialized by another implementation, even if the other 239 * implementation uses a different resource bundle for localizing 240 * the names of pre-defined levels. 241 */ 242 private Object readResolve() 243 { 244 for (int i = 0; i < knownLevels.length; i++) 245 if (value == knownLevels[i].intValue()) 246 return knownLevels[i]; 247 248 return this; 249 } 250 251 252 /** 253 * Returns the name of the resource bundle used for localizing the 254 * level name. 255 * 256 * @return the name of the resource bundle used for localizing the 257 * level name, or <code>null</code> if the name does not undergo 258 * localization. 259 */ 260 public String getResourceBundleName() 261 { 262 return resourceBundleName; 263 } 264 265 266 /** 267 * Returns the name of the Level without localizing it, for example 268 * "WARNING". 269 */ 270 public String getName() 271 { 272 return name; 273 } 274 275 276 /** 277 * Returns the name of the Level after localizing it, for example 278 * "WARNUNG". 279 */ 280 public String getLocalizedName() 281 { 282 String localizedName = null; 283 284 if (resourceBundleName != null) 285 { 286 try 287 { 288 ResourceBundle b = ResourceBundle.getBundle(resourceBundleName); 289 localizedName = b.getString(name); 290 } 291 catch (Exception _) 292 { 293 } 294 } 295 296 if (localizedName != null) 297 return localizedName; 298 else 299 return name; 300 } 301 302 303 /** 304 * Returns the name of the Level without localizing it, for example 305 * "WARNING". 306 */ 307 public final String toString() 308 { 309 return getName(); 310 } 311 312 313 /** 314 * Returns the integer value of the Level. 315 */ 316 public final int intValue() 317 { 318 return value; 319 } 320 321 322 /** 323 * Returns one of the standard Levels given either its name or its 324 * integer value. Custom subclasses of Level will not be returned 325 * by this method. 326 * 327 * @throws IllegalArgumentException if <code>name</code> is neither 328 * the name nor the integer value of one of the pre-defined standard 329 * logging levels. 330 * 331 * @throws NullPointerException if <code>name</code> is null. 332 * 333 */ 334 public static Level parse(String name) 335 throws IllegalArgumentException 336 { 337 /* This will throw a NullPointerException if name is null, 338 * as required by the API specification. 339 */ 340 name = name.intern(); 341 342 for (int i = 0; i < knownLevels.length; i++) 343 { 344 // It's safe to use == instead of .equals here because only the 345 // standard logging levels will be returned by this method, and 346 // they are all created using string literals. 347 if (name == knownLevels[i].name) 348 return knownLevels[i]; 349 } 350 351 try 352 { 353 int num = Integer.parseInt(name); 354 for (int i = 0; i < knownLevels.length; i++) 355 if (num == knownLevels[i].value) 356 return knownLevels[i]; 357 } 358 catch (NumberFormatException _) 359 { 360 } 361 362 String msg = "Not the name of a standard logging level: \"" + name + "\""; 363 throw new IllegalArgumentException(msg); 364 } 365 366 367 /** 368 * Checks whether this Level's integer value is equal to that of 369 * another object. 370 * 371 * @return <code>true</code> if <code>other</code> is an instance of 372 * <code>java.util.logging.Level</code> and has the same integer 373 * value, <code>false</code> otherwise. 374 */ 375 public boolean equals(Object other) 376 { 377 if (!(other instanceof Level)) 378 return false; 379 380 return value == ((Level) other).value; 381 } 382 383 384 /** 385 * Returns a hash code for this Level which is based on its numeric 386 * value. 387 */ 388 public int hashCode() 389 { 390 return value; 391 } 392 393 394 /** 395 * Determines whether or not this Level is one of the standard 396 * levels specified in the Logging API. 397 * 398 * <p>This method is package-private because it is not part 399 * of the logging API specification. However, an XMLFormatter 400 * is supposed to emit the numeric value for a custom log 401 * level, but the name for a pre-defined level. It seems 402 * cleaner to put this method to Level than to write some 403 * procedural code for XMLFormatter. 404 * 405 * @return <code>true</code> if this Level is a standard level, 406 * <code>false</code> otherwise. 407 */ 408 final boolean isStandardLevel() 409 { 410 for (int i = 0; i < knownLevels.length; i++) 411 if (knownLevels[i] == this) 412 return true; 413 414 return false; 415 } 416} 417