001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util.logging;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.Serializable;
023: import java.util.ArrayList;
024: import java.util.List;
025: import java.util.Locale;
026: import java.util.MissingResourceException;
027: import java.util.ResourceBundle;
028:
029: import org.apache.harmony.kernel.vm.VM;
030: import org.apache.harmony.logging.internal.nls.Messages;
031:
032: /**
033: * <code>Level</code> objects are used to indicate the level of logging. There
034: * are a set of predefined logging levels, each associated with an integer
035: * value. Enabling a certain logging level also enables all logging levels with
036: * larger values.
037: * <p>
038: * The predefined levels in ascending order are FINEST, FINER, FINE, CONFIG,
039: * INFO, WARNING, SEVERE. There are two additional predefined levels, which are
040: * ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no
041: * messages.
042: * </p>
043: */
044: public class Level implements Serializable {
045:
046: private static final long serialVersionUID = -8176160795706313070L;
047:
048: private static final List<Level> levels = new ArrayList<Level>(9);
049:
050: /**
051: * The OFF level provides no logging messages.
052: */
053: public static final Level OFF = new Level("OFF", Integer.MAX_VALUE); //$NON-NLS-1$
054:
055: /**
056: * The SEVERE level indicates a severe failure.
057: */
058: public static final Level SEVERE = new Level("SEVERE", 1000); //$NON-NLS-1$
059:
060: /**
061: * The WARNING level indicates a warning.
062: */
063: public static final Level WARNING = new Level("WARNING", 900); //$NON-NLS-1$
064:
065: /**
066: * The INFO level indicates an informative message.
067: */
068: public static final Level INFO = new Level("INFO", 800); //$NON-NLS-1$
069:
070: /**
071: * The CONFIG level indicates a static configuration message.
072: */
073: public static final Level CONFIG = new Level("CONFIG", 700); //$NON-NLS-1$
074:
075: /**
076: * The FINE level provides tracing messages.
077: */
078: public static final Level FINE = new Level("FINE", 500); //$NON-NLS-1$
079:
080: /**
081: * The FINER level provides more detailed tracing messages.
082: */
083: public static final Level FINER = new Level("FINER", 400); //$NON-NLS-1$
084:
085: /**
086: * The FINEST level provides highly detailed tracing messages.
087: */
088: public static final Level FINEST = new Level("FINEST", 300); //$NON-NLS-1$
089:
090: /**
091: * The ALL level provides all logging messages.
092: */
093: public static final Level ALL = new Level("ALL", Integer.MIN_VALUE); //$NON-NLS-1$
094:
095: /**
096: * Parses a level name into a <code>Level</code> object.
097: *
098: * @param name
099: * the name of the desired level, which cannot be null
100: * @return a <code>Level</code> object with the specified name
101: * @throws NullPointerException
102: * if <code>name</code> is <code>null</code>.
103: * @throws IllegalArgumentException
104: * if <code>name</code> is not valid.
105: */
106: public static Level parse(String name)
107: throws IllegalArgumentException {
108: if (name == null) {
109: // logging.1C=The 'name' parameter is null.
110: throw new NullPointerException(Messages
111: .getString("logging.1C")); //$NON-NLS-1$
112: }
113:
114: boolean isNameAnInt;
115: int nameAsInt;
116: try {
117: nameAsInt = Integer.parseInt(name);
118: isNameAnInt = true;
119: } catch (NumberFormatException e) {
120: nameAsInt = 0;
121: isNameAnInt = false;
122: }
123:
124: synchronized (levels) {
125: for (Level level : levels) {
126: if (name.equals(level.getName())) {
127: return level;
128: }
129: }
130:
131: if (isNameAnInt) {
132: /*
133: * Loop through levels a second time, so that the returned
134: * instance will be passed on the order of construction.
135: */
136: for (Level level : levels) {
137: if (nameAsInt == level.intValue()) {
138: return level;
139: }
140: }
141: }
142: }
143:
144: if (!isNameAnInt) {
145: // logging.1D=Cannot parse this name: {0}
146: throw new IllegalArgumentException(Messages.getString(
147: "logging.1D", name)); //$NON-NLS-1$
148: }
149:
150: return new Level(name, nameAsInt);
151: }
152:
153: /**
154: * The name of this Level.
155: *
156: * @serial
157: */
158: private final String name;
159:
160: /**
161: * The integer value indicating the level.
162: *
163: * @serial
164: */
165: private final int value;
166:
167: /**
168: * The name of the resource bundle used to localize the level name.
169: *
170: * @serial
171: */
172: private final String resourceBundleName;
173:
174: /**
175: * The resource bundle associated with this level, used to localize the
176: * level name.
177: */
178: private transient ResourceBundle rb;
179:
180: /**
181: * Constructs an instance of <code>Level</code> taking the supplied name
182: * and level value.
183: *
184: * @param name
185: * name of the level
186: * @param level
187: * an integer value indicating the level
188: * @throws NullPointerException
189: * if <code>name</code> is <code>null</code>.
190: */
191: protected Level(String name, int level) {
192: this (name, level, null);
193: }
194:
195: /**
196: * Constructs an instance of <code>Level</code> taking the supplied name
197: * and level value.
198: *
199: * @param name
200: * name of the level
201: * @param level
202: * an integer value indicating the level
203: * @param resourceBundleName
204: * the name of the resource bundle to use
205: * @throws NullPointerException
206: * if <code>name</code> is <code>null</code>.
207: */
208: protected Level(String name, int level, String resourceBundleName) {
209: if (name == null) {
210: // logging.1C=The 'name' parameter is null.
211: throw new NullPointerException(Messages
212: .getString("logging.1C")); //$NON-NLS-1$
213: }
214: this .name = name;
215: this .value = level;
216: this .resourceBundleName = resourceBundleName;
217: if (resourceBundleName != null) {
218: try {
219: rb = ResourceBundle.getBundle(resourceBundleName,
220: Locale.getDefault(), VM.callerClassLoader());
221: } catch (MissingResourceException e) {
222: rb = null;
223: }
224: }
225: synchronized (levels) {
226: levels.add(this );
227: }
228: }
229:
230: /**
231: * Gets the name of this <code>Level</code>.
232: *
233: * @return the name of this <code>Level</code>
234: */
235: public String getName() {
236: return this .name;
237: }
238:
239: /**
240: * Gets the name of the resource bundle associated with this
241: * <code>Level</code>.
242: *
243: * @return the name of the resource bundle associated with this
244: * <code>Level</code>
245: */
246: public String getResourceBundleName() {
247: return this .resourceBundleName;
248: }
249:
250: /**
251: * Gets the integer value indicating this <code>Level</code>.
252: *
253: * @return the integer value indicating this <code>Level</code>
254: */
255: public final int intValue() {
256: return this .value;
257: }
258:
259: /**
260: * Serialization helper method to maintain singletons and add any new
261: * levels.
262: *
263: * @return The resolved instance.
264: */
265: private Object readResolve() {
266: synchronized (levels) {
267: for (Level level : levels) {
268: if (value != level.value) {
269: continue;
270: }
271: if (!name.equals(level.name)) {
272: continue;
273: }
274: if (resourceBundleName == level.resourceBundleName) {
275: return level;
276: } else if (resourceBundleName != null
277: && resourceBundleName
278: .equals(level.resourceBundleName)) {
279: return level;
280: }
281: }
282: // This is a new value, so add it.
283: levels.add(this );
284: return this ;
285: }
286: }
287:
288: /**
289: * Serialization helper to setup transient resource bundle instance.
290: *
291: * @param in
292: * The input stream to read the instance data from.
293: * @throws IOException
294: * if an IO error occurs.
295: * @throws ClassNotFoundException
296: * if a class is not found.
297: */
298: private void readObject(ObjectInputStream in) throws IOException,
299: ClassNotFoundException {
300: in.defaultReadObject();
301: if (resourceBundleName != null) {
302: try {
303: rb = ResourceBundle.getBundle(resourceBundleName);
304: } catch (MissingResourceException e) {
305: rb = null;
306: }
307: }
308: }
309:
310: /**
311: * Gets the localized name of this level. The default locale is used. If no
312: * resource bundle is associated with this <code>Level</code>, the
313: * original level name is returned.
314: *
315: * @return the localized name of this level
316: */
317: public String getLocalizedName() {
318: if (rb == null) {
319: return name;
320: }
321:
322: try {
323: return rb.getString(name);
324: } catch (MissingResourceException e) {
325: return name;
326: }
327: }
328:
329: /**
330: * Compares two <code>Level</code> objects for equality. They are
331: * considered to be equal if they have the same value.
332: *
333: * @param o
334: * the other object to be compared with
335: * @return <code>true</code> if this object equals to the supplied object,
336: * otherwise <code>false</code>
337: */
338: @Override
339: public boolean equals(Object o) {
340: if (this == o) {
341: return true;
342: }
343:
344: if (!(o instanceof Level)) {
345: return false;
346: }
347:
348: return ((Level) o).intValue() == this .value;
349: }
350:
351: /**
352: * Returns the hash code of this <code>Level</code> object.
353: *
354: * @return the hash code of this <code>Level</code> object
355: */
356: @Override
357: public int hashCode() {
358: return this .value;
359: }
360:
361: /**
362: * Returns the string representation of this <code>Level</code> object.
363: * Usually this will include its name.
364: *
365: * @return the string representation of this <code>Level</code> object
366: */
367: @Override
368: public final String toString() {
369: return this.name;
370: }
371: }
|