Home | History | Annotate | Download | only in logging
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package java.util.logging;
     19 
     20 import dalvik.system.VMStack;
     21 import java.io.IOException;
     22 import java.io.ObjectInputStream;
     23 import java.io.Serializable;
     24 import java.util.ArrayList;
     25 import java.util.List;
     26 import java.util.Locale;
     27 import java.util.MissingResourceException;
     28 import java.util.ResourceBundle;
     29 import libcore.util.Objects;
     30 
     31 /**
     32  * {@code Level} objects are used to indicate the level of logging. There are a
     33  * set of predefined logging levels, each associated with an integer value.
     34  * Enabling a certain logging level also enables all logging levels with larger
     35  * values.
     36  * <p>
     37  * The predefined levels in ascending order are FINEST, FINER, FINE, CONFIG,
     38  * INFO, WARNING, SEVERE. There are two additional predefined levels, which are
     39  * ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no
     40  * messages.
     41  */
     42 public class Level implements Serializable {
     43 
     44     private static final long serialVersionUID = -8176160795706313070L;
     45 
     46     private static final List<Level> levels = new ArrayList<Level>(9);
     47 
     48     /**
     49      * The OFF level provides no logging messages.
     50      */
     51     public static final Level OFF = new Level("OFF", Integer.MAX_VALUE);
     52 
     53     /**
     54      * The SEVERE level provides severe failure messages.
     55      */
     56     public static final Level SEVERE = new Level("SEVERE", 1000);
     57 
     58     /**
     59      * The WARNING level provides warnings.
     60      */
     61     public static final Level WARNING = new Level("WARNING", 900);
     62 
     63     /**
     64      * The INFO level provides informative messages.
     65      */
     66     public static final Level INFO = new Level("INFO", 800);
     67 
     68     /**
     69      * The CONFIG level provides static configuration messages.
     70      */
     71     public static final Level CONFIG = new Level("CONFIG", 700);
     72 
     73     /**
     74      * The FINE level provides tracing messages.
     75      */
     76     public static final Level FINE = new Level("FINE", 500);
     77 
     78     /**
     79      * The FINER level provides more detailed tracing messages.
     80      */
     81     public static final Level FINER = new Level("FINER", 400);
     82 
     83     /**
     84      * The FINEST level provides highly detailed tracing messages.
     85      */
     86     public static final Level FINEST = new Level("FINEST", 300);
     87 
     88     /**
     89      * The ALL level provides all logging messages.
     90      */
     91     public static final Level ALL = new Level("ALL", Integer.MIN_VALUE);
     92 
     93     /**
     94      * Parses a level name into a {@code Level} object.
     95      *
     96      * @param name
     97      *            the name of the desired {@code level}, which cannot be
     98      *            {@code null}.
     99      * @return the level with the specified name.
    100      * @throws NullPointerException
    101      *             if {@code name} is {@code null}.
    102      * @throws IllegalArgumentException
    103      *             if {@code name} is not valid.
    104      */
    105     public static Level parse(String name) throws IllegalArgumentException {
    106         if (name == null) {
    107             throw new NullPointerException("name == null");
    108         }
    109 
    110         boolean isNameAnInt;
    111         int nameAsInt;
    112         try {
    113             nameAsInt = Integer.parseInt(name);
    114             isNameAnInt = true;
    115         } catch (NumberFormatException e) {
    116             nameAsInt = 0;
    117             isNameAnInt = false;
    118         }
    119 
    120         synchronized (levels) {
    121             for (Level level : levels) {
    122                 if (name.equals(level.getName())) {
    123                     return level;
    124                 }
    125             }
    126 
    127             if (isNameAnInt) {
    128                 /*
    129                  * Loop through levels a second time, so that the returned
    130                  * instance will be passed on the order of construction.
    131                  */
    132                 for (Level level : levels) {
    133                     if (nameAsInt == level.intValue()) {
    134                         return level;
    135                     }
    136                 }
    137             }
    138         }
    139 
    140         if (!isNameAnInt) {
    141             throw new IllegalArgumentException("Cannot parse name '" + name + "'");
    142         }
    143 
    144         return new Level(name, nameAsInt);
    145     }
    146 
    147     /**
    148      * The name of this Level.
    149      *
    150      * @serial
    151      */
    152     private final String name;
    153 
    154     /**
    155      * The integer value indicating the level.
    156      *
    157      * @serial
    158      */
    159     private final int value;
    160 
    161     /**
    162      * The name of the resource bundle used to localize the level name.
    163      *
    164      * @serial
    165      */
    166     private final String resourceBundleName;
    167 
    168     /**
    169      * The resource bundle associated with this level, used to localize the
    170      * level name.
    171      */
    172     private transient ResourceBundle rb;
    173 
    174     /**
    175      * Constructs an instance of {@code Level} taking the supplied name and
    176      * level value.
    177      *
    178      * @param name
    179      *            the name of the level.
    180      * @param level
    181      *            an integer value indicating the level.
    182      * @throws NullPointerException
    183      *             if {@code name} is {@code null}.
    184      */
    185     protected Level(String name, int level) {
    186         this(name, level, null);
    187     }
    188 
    189     /**
    190      * Constructs an instance of {@code Level} taking the supplied name, level
    191      * value and resource bundle name.
    192      *
    193      * @param name
    194      *            the name of the level.
    195      * @param level
    196      *            an integer value indicating the level.
    197      * @param resourceBundleName
    198      *            the name of the resource bundle to use.
    199      * @throws NullPointerException
    200      *             if {@code name} is {@code null}.
    201      */
    202     protected Level(String name, int level, String resourceBundleName) {
    203         if (name == null) {
    204             throw new NullPointerException("name == null");
    205         }
    206         this.name = name;
    207         this.value = level;
    208         this.resourceBundleName = resourceBundleName;
    209         if (resourceBundleName != null) {
    210             try {
    211                 rb = ResourceBundle.getBundle(resourceBundleName,
    212                         Locale.getDefault(), VMStack.getCallingClassLoader());
    213             } catch (MissingResourceException e) {
    214                 rb = null;
    215             }
    216         }
    217         synchronized (levels) {
    218             levels.add(this);
    219         }
    220     }
    221 
    222     /**
    223      * Gets the name of this level.
    224      *
    225      * @return this level's name.
    226      */
    227     public String getName() {
    228         return this.name;
    229     }
    230 
    231     /**
    232      * Gets the name of the resource bundle associated with this level.
    233      *
    234      * @return the name of this level's resource bundle.
    235      */
    236     public String getResourceBundleName() {
    237         return this.resourceBundleName;
    238     }
    239 
    240     /**
    241      * Gets the integer value indicating this level.
    242      *
    243      * @return this level's integer value.
    244      */
    245     public final int intValue() {
    246         return this.value;
    247     }
    248 
    249     /**
    250      * Serialization helper method to maintain singletons and add any new
    251      * levels.
    252      *
    253      * @return the resolved instance.
    254      */
    255     private Object readResolve() {
    256         synchronized (levels) {
    257             for (Level level : levels) {
    258                 if (value != level.value) {
    259                     continue;
    260                 }
    261                 if (!name.equals(level.name)) {
    262                     continue;
    263                 }
    264                 if (Objects.equal(resourceBundleName, level.resourceBundleName)) {
    265                     return level;
    266                 }
    267             }
    268             // This is a new value, so add it.
    269             levels.add(this);
    270             return this;
    271         }
    272     }
    273 
    274     /**
    275      * Serialization helper to setup transient resource bundle instance.
    276      *
    277      * @param in
    278      *            the input stream to read the instance data from.
    279      * @throws IOException
    280      *             if an IO error occurs.
    281      * @throws ClassNotFoundException
    282      *             if a class is not found.
    283      */
    284     private void readObject(ObjectInputStream in) throws IOException,
    285             ClassNotFoundException {
    286         in.defaultReadObject();
    287         if (resourceBundleName != null) {
    288             try {
    289                 rb = ResourceBundle.getBundle(resourceBundleName);
    290             } catch (MissingResourceException e) {
    291                 rb = null;
    292             }
    293         }
    294     }
    295 
    296     /**
    297      * Gets the localized name of this level. The default locale is used. If no
    298      * resource bundle is associated with this level then the original level
    299      * name is returned.
    300      *
    301      * @return the localized name of this level.
    302      */
    303     public String getLocalizedName() {
    304         if (rb == null) {
    305             return name;
    306         }
    307 
    308         try {
    309             return rb.getString(name);
    310         } catch (MissingResourceException e) {
    311             return name;
    312         }
    313     }
    314 
    315     /**
    316      * Compares two {@code Level} objects for equality. They are considered to
    317      * be equal if they have the same level value.
    318      *
    319      * @param o
    320      *            the other object to compare this level to.
    321      * @return {@code true} if this object equals to the supplied object,
    322      *         {@code false} otherwise.
    323      */
    324     @Override
    325     public boolean equals(Object o) {
    326         if (this == o) {
    327             return true;
    328         }
    329 
    330         if (!(o instanceof Level)) {
    331             return false;
    332         }
    333 
    334         return ((Level) o).intValue() == this.value;
    335     }
    336 
    337     /**
    338      * Returns the hash code of this {@code Level} object.
    339      *
    340      * @return this level's hash code.
    341      */
    342     @Override
    343     public int hashCode() {
    344         return this.value;
    345     }
    346 
    347     /**
    348      * Returns the string representation of this {@code Level} object. In
    349      * this case, it is the level's name.
    350      *
    351      * @return the string representation of this level.
    352      */
    353     @Override
    354     public final String toString() {
    355         return this.name;
    356     }
    357 }
    358