1 /*
2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.logging;
27 import java.lang.reflect.Module;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.ResourceBundle;
34
35 /**
36 * The Level class defines a set of standard logging levels that
37 * can be used to control logging output. The logging Level objects
38 * are ordered and are specified by ordered integers. Enabling logging
39 * at a given level also enables logging at all higher levels.
40 * <p>
41 * Clients should normally use the predefined Level constants such
42 * as Level.SEVERE.
43 * <p>
44 * The levels in descending order are:
45 * <ul>
46 * <li>SEVERE (highest value)
47 * <li>WARNING
48 * <li>INFO
49 * <li>CONFIG
50 * <li>FINE
51 * <li>FINER
52 * <li>FINEST (lowest value)
391 @Override
392 public final String toString() {
393 return name;
394 }
395
396 /**
397 * Get the integer value for this level. This integer value
398 * can be used for efficient ordering comparisons between
399 * Level objects.
400 * @return the integer value for this level.
401 */
402 public final int intValue() {
403 return value;
404 }
405
406 private static final long serialVersionUID = -8176160795706313070L;
407
408 // Serialization magic to prevent "doppelgangers".
409 // This is a performance optimization.
410 private Object readResolve() {
411 KnownLevel o = KnownLevel.matches(this);
412 if (o != null) {
413 return o.levelObject;
414 }
415
416 // Woops. Whoever sent us this object knows
417 // about a new log level. Add it to our list.
418 Level level = new Level(this.name, this.value, this.resourceBundleName);
419 return level;
420 }
421
422 /**
423 * Parse a level name string into a Level.
424 * <p>
425 * The argument string may consist of either a level name
426 * or an integer value.
427 * <p>
428 * For example:
429 * <ul>
430 * <li> "SEVERE"
431 * <li> "1000"
432 * </ul>
433 *
434 * @param name string to be parsed
435 * @throws NullPointerException if the name is null
436 * @throws IllegalArgumentException if the value is not valid.
437 * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
438 * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
439 * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
440 * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
441 * appropriate package access, or new levels defined or created
442 * by subclasses.
443 *
444 * @return The parsed value. Passing an integer that corresponds to a known name
445 * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
446 * Passing an integer that does not (e.g., 1) will return a new level name
447 * initialized to that value.
448 */
449 public static synchronized Level parse(String name) throws IllegalArgumentException {
450 // Check that name is not null.
451 name.length();
452
453 KnownLevel level;
454
455 // Look for a known Level with the given non-localized name.
456 level = KnownLevel.findByName(name);
457 if (level != null) {
458 return level.levelObject;
459 }
460
461 // Now, check if the given name is an integer. If so,
462 // first look for a Level with the given value and then
463 // if necessary create one.
464 try {
465 int x = Integer.parseInt(name);
466 level = KnownLevel.findByValue(x);
467 if (level == null) {
468 // add new Level
469 Level levelObject = new Level(name, x);
470 level = KnownLevel.findByValue(x);
471 }
472 return level.levelObject;
473 } catch (NumberFormatException ex) {
474 // Not an integer.
475 // Drop through.
476 }
477
478 // Finally, look for a known level with the given localized name,
479 // in the current default locale.
480 // This is relatively expensive, but not excessively so.
481 level = KnownLevel.findByLocalizedLevelName(name);
482 if (level != null) {
483 return level.levelObject;
484 }
485
486 // OK, we've tried everything and failed
487 throw new IllegalArgumentException("Bad level \"" + name + "\"");
488 }
489
490 /**
491 * Compare two objects for value equality.
492 * @return true if and only if the two objects have the same level value.
493 */
494 @Override
495 public boolean equals(Object ox) {
496 try {
497 Level lx = (Level)ox;
498 return (lx.value == this.value);
499 } catch (Exception ex) {
500 return false;
501 }
502 }
503
504 /**
513 // KnownLevel class maintains the global list of all known levels.
514 // The API allows multiple custom Level instances of the same name/value
515 // be created. This class provides convenient methods to find a level
516 // by a given name, by a given value, or by a given localized name.
517 //
518 // KnownLevel wraps the following Level objects:
519 // 1. levelObject: standard Level object or custom Level object
520 // 2. mirroredLevel: Level object representing the level specified in the
521 // logging configuration.
522 //
523 // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
524 // are non-final but the name and resource bundle name are parameters to
525 // the Level constructor. Use the mirroredLevel object instead of the
526 // levelObject to prevent the logging framework to execute foreign code
527 // implemented by untrusted Level subclass.
528 //
529 // Implementation Notes:
530 // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
531 // were final, the following KnownLevel implementation can be removed.
532 // Future API change should take this into consideration.
533 static final class KnownLevel {
534 private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
535 private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
536 final Level levelObject; // instance of Level class or Level subclass
537 final Level mirroredLevel; // mirror of the custom Level
538 KnownLevel(Level l) {
539 this.levelObject = l;
540 if (l.getClass() == Level.class) {
541 this.mirroredLevel = l;
542 } else {
543 // this mirrored level object is hidden
544 this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
545 }
546 }
547
548 static synchronized void add(Level l) {
549 // the mirroredLevel object is always added to the list
550 // before the custom Level instance
551 KnownLevel o = new KnownLevel(l);
552 List<KnownLevel> list = nameToLevels.get(l.name);
553 if (list == null) {
554 list = new ArrayList<>();
555 nameToLevels.put(l.name, list);
556 }
557 list.add(o);
558
559 list = intToLevels.get(l.value);
560 if (list == null) {
561 list = new ArrayList<>();
562 intToLevels.put(l.value, list);
563 }
564 list.add(o);
565 }
566
567 // Returns a KnownLevel with the given non-localized name.
568 static synchronized KnownLevel findByName(String name) {
569 List<KnownLevel> list = nameToLevels.get(name);
570 if (list != null) {
571 return list.get(0);
572 }
573 return null;
574 }
575
576 // Returns a KnownLevel with the given value.
577 static synchronized KnownLevel findByValue(int value) {
578 List<KnownLevel> list = intToLevels.get(value);
579 if (list != null) {
580 return list.get(0);
581 }
582 return null;
583 }
584
585 // Returns a KnownLevel with the given localized name matching
586 // by calling the Level.getLocalizedLevelName() method (i.e. found
587 // from the resourceBundle associated with the Level object).
588 // This method does not call Level.getLocalizedName() that may
589 // be overridden in a subclass implementation
590 static synchronized KnownLevel findByLocalizedLevelName(String name) {
591 for (List<KnownLevel> levels : nameToLevels.values()) {
592 for (KnownLevel l : levels) {
593 String lname = l.levelObject.getLocalizedLevelName();
594 if (name.equals(lname)) {
595 return l;
596 }
597 }
598 }
599 return null;
600 }
601
602 static synchronized KnownLevel matches(Level l) {
603 List<KnownLevel> list = nameToLevels.get(l.name);
604 if (list != null) {
605 for (KnownLevel level : list) {
606 Level other = level.mirroredLevel;
607 if (l.value == other.value &&
608 (l.resourceBundleName == other.resourceBundleName ||
609 (l.resourceBundleName != null &&
610 l.resourceBundleName.equals(other.resourceBundleName)))) {
611 return level;
612 }
613 }
614 }
615 return null;
616 }
617 }
618
619 }
|
1 /*
2 * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.logging;
27 import java.lang.ref.Reference;
28 import java.lang.ref.ReferenceQueue;
29 import java.lang.ref.WeakReference;
30 import java.lang.reflect.Module;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Map;
36 import java.util.Optional;
37 import java.util.ResourceBundle;
38
39 /**
40 * The Level class defines a set of standard logging levels that
41 * can be used to control logging output. The logging Level objects
42 * are ordered and are specified by ordered integers. Enabling logging
43 * at a given level also enables logging at all higher levels.
44 * <p>
45 * Clients should normally use the predefined Level constants such
46 * as Level.SEVERE.
47 * <p>
48 * The levels in descending order are:
49 * <ul>
50 * <li>SEVERE (highest value)
51 * <li>WARNING
52 * <li>INFO
53 * <li>CONFIG
54 * <li>FINE
55 * <li>FINER
56 * <li>FINEST (lowest value)
395 @Override
396 public final String toString() {
397 return name;
398 }
399
400 /**
401 * Get the integer value for this level. This integer value
402 * can be used for efficient ordering comparisons between
403 * Level objects.
404 * @return the integer value for this level.
405 */
406 public final int intValue() {
407 return value;
408 }
409
410 private static final long serialVersionUID = -8176160795706313070L;
411
412 // Serialization magic to prevent "doppelgangers".
413 // This is a performance optimization.
414 private Object readResolve() {
415 Level level;
416 KnownLevel ref;
417 do {
418 ref = KnownLevel.matches(this);
419 level = KnownLevel.levelObject(ref);
420 if (level != null) return level;
421 } while (ref != null);
422
423 // Woops. Whoever sent us this object knows
424 // about a new log level. Add it to our list.
425 level = new Level(this.name, this.value, this.resourceBundleName);
426 return level;
427 }
428
429 /**
430 * Parse a level name string into a Level.
431 * <p>
432 * The argument string may consist of either a level name
433 * or an integer value.
434 * <p>
435 * For example:
436 * <ul>
437 * <li> "SEVERE"
438 * <li> "1000"
439 * </ul>
440 *
441 * @param name string to be parsed
442 * @throws NullPointerException if the name is null
443 * @throws IllegalArgumentException if the value is not valid.
444 * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
445 * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
446 * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
447 * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
448 * appropriate package access, or new levels defined or created
449 * by subclasses.
450 *
451 * @return The parsed value. Passing an integer that corresponds to a known name
452 * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
453 * Passing an integer that does not (e.g., 1) will return a new level name
454 * initialized to that value.
455 */
456 public static synchronized Level parse(String name) throws IllegalArgumentException {
457 // Check that name is not null.
458 name.length();
459
460 KnownLevel ref;
461 Level level;
462
463 // Look for a known Level with the given non-localized name.
464 do {
465 ref = KnownLevel.findByName(name);
466 level = KnownLevel.levelObject(ref);
467 if (level != null) return level;
468 } while (ref != null);
469
470 // Now, check if the given name is an integer. If so,
471 // first look for a Level with the given value and then
472 // if necessary create one.
473 try {
474 int x = Integer.parseInt(name);
475 do {
476 ref = KnownLevel.findByValue(x);
477 level = KnownLevel.levelObject(ref);
478 if (level != null) return level;
479 } while (ref != null);
480 // add new Level.
481 Level levelObject = new Level(name, x);
482 ref = KnownLevel.findByValue(x);
483 return KnownLevel.levelObject(ref);
484 } catch (NumberFormatException ex) {
485 // Not an integer.
486 // Drop through.
487 }
488
489 // Finally, look for a known level with the given localized name,
490 // in the current default locale.
491 // This is relatively expensive, but not excessively so.
492 do {
493 ref = KnownLevel.findByLocalizedLevelName(name);
494 level = KnownLevel.levelObject(ref);
495 if (level != null) return level;
496 } while (ref != null);
497
498 // OK, we've tried everything and failed
499 throw new IllegalArgumentException("Bad level \"" + name + "\"");
500 }
501
502 /**
503 * Compare two objects for value equality.
504 * @return true if and only if the two objects have the same level value.
505 */
506 @Override
507 public boolean equals(Object ox) {
508 try {
509 Level lx = (Level)ox;
510 return (lx.value == this.value);
511 } catch (Exception ex) {
512 return false;
513 }
514 }
515
516 /**
525 // KnownLevel class maintains the global list of all known levels.
526 // The API allows multiple custom Level instances of the same name/value
527 // be created. This class provides convenient methods to find a level
528 // by a given name, by a given value, or by a given localized name.
529 //
530 // KnownLevel wraps the following Level objects:
531 // 1. levelObject: standard Level object or custom Level object
532 // 2. mirroredLevel: Level object representing the level specified in the
533 // logging configuration.
534 //
535 // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
536 // are non-final but the name and resource bundle name are parameters to
537 // the Level constructor. Use the mirroredLevel object instead of the
538 // levelObject to prevent the logging framework to execute foreign code
539 // implemented by untrusted Level subclass.
540 //
541 // Implementation Notes:
542 // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
543 // were final, the following KnownLevel implementation can be removed.
544 // Future API change should take this into consideration.
545 static final class KnownLevel extends WeakReference<Level> {
546 private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
547 private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
548 private static final ReferenceQueue<Level> QUEUE = new ReferenceQueue<>();
549
550 final Level mirroredLevel; // mirror of the custom Level
551 KnownLevel(Level l) {
552 super(l, QUEUE);
553 if (l.getClass() == Level.class) {
554 this.mirroredLevel = l;
555 } else {
556 // this mirrored level object is hidden
557 this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
558 }
559 }
560
561 private void remove() {
562 Optional.ofNullable(nameToLevels.get(mirroredLevel.name)).ifPresent((x) -> x.remove(this));
563 Optional.ofNullable(intToLevels.get(mirroredLevel.value)).ifPresent((x) -> x.remove(this));
564 }
565
566 static synchronized void purge(KnownLevel ref) {
567 ref.remove();
568 }
569
570 // Remove all stale KnownLevel instances
571 static synchronized void purge() {
572 Reference<? extends Level> ref;
573 while ((ref = QUEUE.poll()) != null) {
574 if (ref instanceof KnownLevel) {
575 ((KnownLevel)ref).remove();
576 }
577 }
578 }
579
580 static synchronized void add(Level l) {
581 purge();
582 // the mirroredLevel object is always added to the list
583 // before the custom Level instance
584 KnownLevel o = new KnownLevel(l);
585 List<KnownLevel> list = nameToLevels.get(l.name);
586 if (list == null) {
587 list = new ArrayList<>();
588 nameToLevels.put(l.name, list);
589 }
590 list.add(o);
591
592 list = intToLevels.get(l.value);
593 if (list == null) {
594 list = new ArrayList<>();
595 intToLevels.put(l.value, list);
596 }
597 list.add(o);
598 }
599
600 // Returns a KnownLevel with the given non-localized name.
601 static synchronized KnownLevel findByName(String name) {
602 purge();
603 List<KnownLevel> list = nameToLevels.get(name);
604 if (list != null) {
605 return list.stream().findFirst().orElse(null);
606 }
607 return null;
608 }
609
610 // Returns a KnownLevel with the given value.
611 static synchronized KnownLevel findByValue(int value) {
612 purge();
613 List<KnownLevel> list = intToLevels.get(value);
614 if (list != null) {
615 return list.stream().findFirst().orElse(null);
616 }
617 return null;
618 }
619
620 // Returns a KnownLevel with the given localized name matching
621 // by calling the Level.getLocalizedLevelName() method (i.e. found
622 // from the resourceBundle associated with the Level object).
623 // This method does not call Level.getLocalizedName() that may
624 // be overridden in a subclass implementation
625 static synchronized KnownLevel findByLocalizedLevelName(String name) {
626 purge();
627 for (List<KnownLevel> levels : nameToLevels.values()) {
628 for (KnownLevel l : levels) {
629 Level levelObject = l.get();
630 if (levelObject != null) {
631 String lname = levelObject.getLocalizedLevelName();
632 if (name.equals(lname)) {
633 return l;
634 }
635 }
636 }
637 }
638 return null;
639 }
640
641 static synchronized KnownLevel matches(Level l) {
642 purge();
643 List<KnownLevel> list = nameToLevels.get(l.name);
644 if (list != null) {
645 for (KnownLevel ref : list) {
646 Level other = ref.mirroredLevel;
647 if (l.value == other.value &&
648 (l.resourceBundleName == other.resourceBundleName ||
649 (l.resourceBundleName != null &&
650 l.resourceBundleName.equals(other.resourceBundleName)))) {
651 return ref;
652 }
653 }
654 }
655 return null;
656 }
657
658 static Level levelObject(KnownLevel ref) {
659 if (ref == null) return null;
660 final Level level = ref.get();
661 if (level == null) {
662 purge(ref);
663 }
664 return level;
665 }
666
667 }
668
669 }
|