/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.util.logging; import dalvik.system.VMStack; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import libcore.util.Objects; /** * {@code Level} objects are used to indicate the level of logging. There are a * set of predefined logging levels, each associated with an integer value. * Enabling a certain logging level also enables all logging levels with larger * values. * <p> * The predefined levels in ascending order are FINEST, FINER, FINE, CONFIG, * INFO, WARNING, SEVERE. There are two additional predefined levels, which are * ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no * messages. */ public class Level implements Serializable { private static final long serialVersionUID = -8176160795706313070L; private static final List<Level> levels = new ArrayList<Level>(9); /** * The OFF level provides no logging messages. */ public static final Level OFF = new Level("OFF", Integer.MAX_VALUE); /** * The SEVERE level provides severe failure messages. */ public static final Level SEVERE = new Level("SEVERE", 1000); /** * The WARNING level provides warnings. */ public static final Level WARNING = new Level("WARNING", 900); /** * The INFO level provides informative messages. */ public static final Level INFO = new Level("INFO", 800); /** * The CONFIG level provides static configuration messages. */ public static final Level CONFIG = new Level("CONFIG", 700); /** * The FINE level provides tracing messages. */ public static final Level FINE = new Level("FINE", 500); /** * The FINER level provides more detailed tracing messages. */ public static final Level FINER = new Level("FINER", 400); /** * The FINEST level provides highly detailed tracing messages. */ public static final Level FINEST = new Level("FINEST", 300); /** * The ALL level provides all logging messages. */ public static final Level ALL = new Level("ALL", Integer.MIN_VALUE); /** * Parses a level name into a {@code Level} object. * * @param name * the name of the desired {@code level}, which cannot be * {@code null}. * @return the level with the specified name. * @throws NullPointerException * if {@code name} is {@code null}. * @throws IllegalArgumentException * if {@code name} is not valid. */ public static Level parse(String name) throws IllegalArgumentException { if (name == null) { throw new NullPointerException("name == null"); } boolean isNameAnInt; int nameAsInt; try { nameAsInt = Integer.parseInt(name); isNameAnInt = true; } catch (NumberFormatException e) { nameAsInt = 0; isNameAnInt = false; } synchronized (levels) { for (Level level : levels) { if (name.equals(level.getName())) { return level; } } if (isNameAnInt) { /* * Loop through levels a second time, so that the returned * instance will be passed on the order of construction. */ for (Level level : levels) { if (nameAsInt == level.intValue()) { return level; } } } } if (!isNameAnInt) { throw new IllegalArgumentException("Cannot parse name '" + name + "'"); } return new Level(name, nameAsInt); } /** * The name of this Level. * * @serial */ private final String name; /** * The integer value indicating the level. * * @serial */ private final int value; /** * The name of the resource bundle used to localize the level name. * * @serial */ private final String resourceBundleName; /** * The resource bundle associated with this level, used to localize the * level name. */ private transient ResourceBundle rb; /** * Constructs an instance of {@code Level} taking the supplied name and * level value. * * @param name * the name of the level. * @param level * an integer value indicating the level. * @throws NullPointerException * if {@code name} is {@code null}. */ protected Level(String name, int level) { this(name, level, null); } /** * Constructs an instance of {@code Level} taking the supplied name, level * value and resource bundle name. * * @param name * the name of the level. * @param level * an integer value indicating the level. * @param resourceBundleName * the name of the resource bundle to use. * @throws NullPointerException * if {@code name} is {@code null}. */ protected Level(String name, int level, String resourceBundleName) { if (name == null) { throw new NullPointerException("name == null"); } this.name = name; this.value = level; this.resourceBundleName = resourceBundleName; if (resourceBundleName != null) { try { rb = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(), VMStack.getCallingClassLoader()); } catch (MissingResourceException e) { rb = null; } } synchronized (levels) { levels.add(this); } } /** * Gets the name of this level. * * @return this level's name. */ public String getName() { return this.name; } /** * Gets the name of the resource bundle associated with this level. * * @return the name of this level's resource bundle. */ public String getResourceBundleName() { return this.resourceBundleName; } /** * Gets the integer value indicating this level. * * @return this level's integer value. */ public final int intValue() { return this.value; } /** * Serialization helper method to maintain singletons and add any new * levels. * * @return the resolved instance. */ private Object readResolve() { synchronized (levels) { for (Level level : levels) { if (value != level.value) { continue; } if (!name.equals(level.name)) { continue; } if (Objects.equal(resourceBundleName, level.resourceBundleName)) { return level; } } // This is a new value, so add it. levels.add(this); return this; } } /** * Serialization helper to setup transient resource bundle instance. * * @param in * the input stream to read the instance data from. * @throws IOException * if an IO error occurs. * @throws ClassNotFoundException * if a class is not found. */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); if (resourceBundleName != null) { try { rb = ResourceBundle.getBundle(resourceBundleName); } catch (MissingResourceException e) { rb = null; } } } /** * Gets the localized name of this level. The default locale is used. If no * resource bundle is associated with this level then the original level * name is returned. * * @return the localized name of this level. */ public String getLocalizedName() { if (rb == null) { return name; } try { return rb.getString(name); } catch (MissingResourceException e) { return name; } } /** * Compares two {@code Level} objects for equality. They are considered to * be equal if they have the same level value. * * @param o * the other object to compare this level to. * @return {@code true} if this object equals to the supplied object, * {@code false} otherwise. */ @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Level)) { return false; } return ((Level) o).intValue() == this.value; } /** * Returns the hash code of this {@code Level} object. * * @return this level's hash code. */ @Override public int hashCode() { return this.value; } /** * Returns the string representation of this {@code Level} object. In * this case, it is the level's name. * * @return the string representation of this level. */ @Override public final String toString() { return this.name; } }