1. /*
  2. * @(#)Level.java 1.12 03/01/27
  3. *
  4. * Copyright 2003 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.12, 01/27/03
  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. */
  149. protected Level(String name, int value) {
  150. this(name, value, null);
  151. }
  152. /**
  153. * Create a named Level with a given integer value and a
  154. * given localization resource name.
  155. * <p>
  156. * @param name the name of the Level, for example "SEVERE".
  157. * @param value an integer value for the level.
  158. * @param resourceBundleName name of a resource bundle to use in
  159. * localizing the given name (may be null).
  160. */
  161. protected Level(String name, int value, String resourceBundleName) {
  162. this.name = name;
  163. this.value = value;
  164. this.resourceBundleName = resourceBundleName;
  165. synchronized (Level.class) {
  166. known.add(this);
  167. }
  168. }
  169. /**
  170. * Return the level's localization resource bundle name, or
  171. * null if no localization bundle is defined.
  172. *
  173. * @return localization resource bundle name
  174. */
  175. public String getResourceBundleName() {
  176. return resourceBundleName;
  177. }
  178. /**
  179. * Return the non-localized string name of the Level.
  180. *
  181. * @return non-localized name
  182. */
  183. public String getName() {
  184. return name;
  185. }
  186. /**
  187. * Return the localized string name of the Level, for
  188. * the current default locale.
  189. * <p>
  190. * If no localization information is available, the
  191. * non-localized name is returned.
  192. *
  193. * @return localized name
  194. */
  195. public String getLocalizedName() {
  196. try {
  197. ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
  198. return rb.getString(name);
  199. } catch (Exception ex) {
  200. return name;
  201. }
  202. }
  203. /**
  204. * @return the non-localized name of the Level, for example "INFO".
  205. */
  206. public final String toString() {
  207. return name;
  208. }
  209. /**
  210. * Get the integer value for this level. This integer value
  211. * can be used for efficient ordering comparisons between
  212. * Level objects.
  213. * @return the integer value for this level.
  214. */
  215. public final int intValue() {
  216. return value;
  217. }
  218. // Serialization magic to prevent "doppelgangers".
  219. // This is a peformance optimization.
  220. private Object readResolve() {
  221. synchronized (Level.class) {
  222. for (int i = 0; i < known.size(); i++) {
  223. Level other = (Level) known.get(i);
  224. if (this.name.equals(other.name) && this.value == other.value
  225. && (this.resourceBundleName == other.resourceBundleName ||
  226. (this.resourceBundleName != null &&
  227. this.resourceBundleName.equals(other.resourceBundleName)))) {
  228. return other;
  229. }
  230. }
  231. // Woops. Whoever sent us this object knows
  232. // about a new log level. Add it to our list.
  233. known.add(this);
  234. return this;
  235. }
  236. }
  237. /**
  238. * Parse a level name string into a Level.
  239. * <p>
  240. * The argument string may consist of either a level name
  241. * or an integer value.
  242. * <p>
  243. * For example:
  244. * <ul>
  245. * <li> "SEVERE"
  246. * <li> "1000"
  247. * </ul>
  248. * @param name string to be parsed
  249. * @return parsed value
  250. * @throws NullPointerException if the name is null
  251. * @throws IllegalArgumentException if the value is neither one of the
  252. * known names nor an integer.
  253. */
  254. public static synchronized Level parse(String name) throws IllegalArgumentException {
  255. // Check that name is not null.
  256. name.length();
  257. // Look for a known Level with the given non-localized name.
  258. for (int i = 0; i < known.size(); i++) {
  259. Level l = (Level) known.get(i);
  260. if (name.equals(l.name)) {
  261. return l;
  262. }
  263. }
  264. // Now, check if the given name is an integer. If so,
  265. // first look for a Level with the given value and then
  266. // if necessary create one.
  267. try {
  268. int x = Integer.parseInt(name);
  269. for (int i = 0; i < known.size(); i++) {
  270. Level l = (Level) known.get(i);
  271. if (l.value == x) {
  272. return l;
  273. }
  274. }
  275. // Create a new Level.
  276. return new Level(name, x);
  277. } catch (NumberFormatException ex) {
  278. // Not an integer.
  279. // Drop through.
  280. }
  281. // Finally, look for a known level with the given localized name,
  282. // in the current default locale.
  283. // This is relatively expensive, but not excessively so.
  284. for (int i = 0; i < known.size(); i++) {
  285. Level l = (Level) known.get(i);
  286. if (name.equals(l.getLocalizedName())) {
  287. return l;
  288. }
  289. }
  290. // OK, we'ved tried everything and failed
  291. throw new IllegalArgumentException("Bad level \"" + name + "\"");
  292. }
  293. /**
  294. * Compare two objects for value equality.
  295. * @return true if and only if the two objects have the same level value.
  296. */
  297. public boolean equals(Object ox) {
  298. try {
  299. Level lx = (Level)ox;
  300. return (lx.value == this.value);
  301. } catch (Exception ex) {
  302. return false;
  303. }
  304. }
  305. /**
  306. * Generate a hashcode.
  307. * @return a hashcode based on the level value
  308. */
  309. public int hashCode() {
  310. return this.value;
  311. }
  312. }