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