001    /* Level.java -- a class for indicating logging levels
002       Copyright (C) 2002, 2005, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.util.logging;
040    
041    import java.io.Serializable;
042    import 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     */
053    public 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