8026027: Level.parse should return the custom Level instance instead of the mirrored Level
authormchung
Wed, 09 Oct 2013 06:24:42 -0700
changeset 20745 3d2e35965c56
parent 20744 66fd18be6993
child 20746 e41a8a513b3e
8026027: Level.parse should return the custom Level instance instead of the mirrored Level Reviewed-by: dfuchs, chegar
jdk/src/share/classes/java/util/logging/Level.java
jdk/test/java/util/logging/Level/CustomLevel.java
jdk/test/java/util/logging/Level/myresource.properties
--- a/jdk/src/share/classes/java/util/logging/Level.java	Wed Oct 09 15:19:56 2013 +0200
+++ b/jdk/src/share/classes/java/util/logging/Level.java	Wed Oct 09 06:24:42 2013 -0700
@@ -204,6 +204,12 @@
      * @throws NullPointerException if the name is null
      */
     protected Level(String name, int value, String resourceBundleName) {
+        this(name, value, resourceBundleName, true);
+    }
+
+    // private constructor to specify whether this instance should be added
+    // to the KnownLevel list from which Level.parse method does its look up
+    private Level(String name, int value, String resourceBundleName, boolean visible) {
         if (name == null) {
             throw new NullPointerException();
         }
@@ -212,7 +218,9 @@
         this.resourceBundleName = resourceBundleName;
         this.localizedLevelName = resourceBundleName == null ? name : null;
         this.cachedLocale = null;
-        KnownLevel.add(this);
+        if (visible) {
+            KnownLevel.add(this);
+        }
     }
 
     /**
@@ -465,7 +473,7 @@
         // Finally, look for a known level with the given localized name,
         // in the current default locale.
         // This is relatively expensive, but not excessively so.
-        level = KnownLevel.findByLocalizedName(name);
+        level = KnownLevel.findByLocalizedLevelName(name);
         if (level != null) {
             return level.levelObject;
         }
@@ -521,13 +529,14 @@
         private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
         private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
         final Level levelObject;     // instance of Level class or Level subclass
-        final Level mirroredLevel;   // instance of Level class
+        final Level mirroredLevel;   // mirror of the custom Level
         KnownLevel(Level l) {
             this.levelObject = l;
             if (l.getClass() == Level.class) {
                 this.mirroredLevel = l;
             } else {
-                this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName);
+                // this mirrored level object is hidden
+                this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
             }
         }
 
@@ -585,20 +594,6 @@
             return null;
         }
 
-        // Returns a KnownLevel with the given localized name matching
-        // by calling the Level.getLocalizedName() method
-        static synchronized KnownLevel findByLocalizedName(String name) {
-            for (List<KnownLevel> levels : nameToLevels.values()) {
-                for (KnownLevel l : levels) {
-                    String lname = l.levelObject.getLocalizedName();
-                    if (name.equals(lname)) {
-                        return l;
-                    }
-                }
-            }
-            return null;
-        }
-
         static synchronized KnownLevel matches(Level l) {
             List<KnownLevel> list = nameToLevels.get(l.name);
             if (list != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Level/CustomLevel.java	Wed Oct 09 06:24:42 2013 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/*
+ * @test
+ * @bug 8026027
+ * @summary Test Level.parse to look up custom levels by name and its
+ *          localized name
+ *
+ * @run main/othervm CustomLevel
+ */
+
+public class CustomLevel extends Level {
+    public CustomLevel(String name, int value, String resourceBundleName) {
+        super(name, value, resourceBundleName);
+    }
+
+    private static final List<Level> levels = new ArrayList<>();
+    private static final String RB_NAME = "myresource";
+    public static void main(String[] args) throws Exception {
+        setupCustomLevels();
+
+        // Level.parse will return the custom Level instance
+        ResourceBundle rb = ResourceBundle.getBundle(RB_NAME);
+        for (Level level : levels) {
+            String name = level.getName();
+            if (!name.equals("WARNING") && !name.equals("INFO")) {
+                // custom level whose name doesn't conflict with any standard one
+                checkCustomLevel(Level.parse(name), level);
+            }
+            String localizedName = rb.getString(level.getName());
+            Level l = Level.parse(localizedName);
+            if (l != level) {
+                throw new RuntimeException("Unexpected level " + l + " " + l.getClass());
+            }
+        }
+    }
+
+    private static void setupCustomLevels() throws IOException {
+        levels.add(new CustomLevel("EMERGENCY", 1090, RB_NAME));
+        levels.add(new CustomLevel("ALERT", 1060, RB_NAME));
+        levels.add(new CustomLevel("CRITICAL", 1030, RB_NAME));
+        levels.add(new CustomLevel("WARNING", 1010, RB_NAME));
+        levels.add(new CustomLevel("INFO", 1000, RB_NAME));
+    }
+    static void checkCustomLevel(Level level, Level expected) {
+        // Level value must be the same
+        if (!level.equals(expected)) {
+            throw new RuntimeException(formatLevel(level) + " != " + formatLevel(expected));
+        }
+
+        if (!level.getName().equals(expected.getName())) {
+            throw new RuntimeException(formatLevel(level) + " != " + formatLevel(expected));
+        }
+
+        // Level.parse is expected to return the custom Level
+        if (level != expected) {
+            throw new RuntimeException(formatLevel(level) + " != " + formatLevel(expected));
+        }
+
+        ResourceBundle rb = ResourceBundle.getBundle(RB_NAME);
+        String name = rb.getString(level.getName());
+        if (!level.getLocalizedName().equals(name)) {
+            // must have the same localized name
+            throw new RuntimeException(level.getLocalizedName() + " != " + name);
+        }
+    }
+
+    static String formatLevel(Level l) {
+        return l + ":" + l.intValue() + ":" + l.getClass().getName();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Level/myresource.properties	Wed Oct 09 06:24:42 2013 -0700
@@ -0,0 +1,5 @@
+EMERGENCY=localized.emergency
+ALERT=localized.alert
+CRITICAL=localized.critical
+WARNING=localized.warning
+INFO=localized.info