--- a/jdk/test/java/util/logging/Level/CustomLevel.java Wed Sep 14 14:29:39 2016 +0200
+++ b/jdk/test/java/util/logging/Level/CustomLevel.java Wed Sep 14 14:04:14 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -22,12 +22,20 @@
*/
import java.io.*;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
import java.util.*;
import java.util.logging.*;
/*
* @test
- * @bug 8026027
+ * @bug 8026027 6543126
* @summary Test Level.parse to look up custom levels by name and its
* localized name
*
@@ -41,23 +49,168 @@
private static final List<Level> levels = new ArrayList<>();
private static final String RB_NAME = "myresource";
+ private static final String OTHERRB_NAME = "myresource2";
+
+ private static class CustomLevelReference extends WeakReference<Level> {
+ final String name;
+ final int value;
+ final String resourceBundleName;
+ public CustomLevelReference(Level level, ReferenceQueue<Level> queue) {
+ super(level, queue);
+ name = level.getName();
+ value = level.intValue();
+ resourceBundleName = level.getResourceBundleName();
+ }
+
+ @Override
+ public String toString() {
+ return "CustomLevelReference(\"" + name + "\", " + value + ", \""
+ + resourceBundleName + "\")";
+ }
+
+ }
+
public static void main(String[] args) throws Exception {
setupCustomLevels();
+ setUpCustomLevelsOtherLoader();
// Level.parse will return the custom Level instance
- ResourceBundle rb = ResourceBundle.getBundle(RB_NAME);
for (Level level : levels) {
+ final ResourceBundle rb = getResourceBundle(level);
String name = level.getName();
- if (!name.equals("WARNING") && !name.equals("INFO")) {
+ Level l = Level.parse(name);
+ if (!name.equals("WARNING") && !name.equals("INFO")
+ && !name.equals("SEVERE")) {
// custom level whose name doesn't conflict with any standard one
- checkCustomLevel(Level.parse(name), level);
+ checkCustomLevel(l, level);
+ } else if (l != Level.WARNING && l != Level.INFO && l != Level.SEVERE
+ || !name.equals(l.getName())) {
+ throw new RuntimeException("Unexpected level " + formatLevel(l));
}
+ System.out.println("Level.parse found expected level: "
+ + formatLevel(l));
String localizedName = rb.getString(level.getName());
- Level l = Level.parse(localizedName);
+ l = Level.parse(localizedName);
if (l != level) {
- throw new RuntimeException("Unexpected level " + l + " " + l.getClass());
+ throw new RuntimeException("Unexpected level " + l + " "
+ + l.getClass() + " for " + localizedName
+ + " in " + rb.getBaseBundleName());
+ }
+ }
+
+ final long otherLevelCount = levels.stream()
+ .filter(CustomLevel::isCustomLoader)
+ .count();
+
+ // Now verify that custom level instances are correctly
+ // garbage collected when no longer referenced
+ ReferenceQueue<Level> queue = new ReferenceQueue<>();
+ List<CustomLevelReference> refs = new ArrayList<>();
+ List<CustomLevelReference> customRefs = new ArrayList<>();
+ int otherLevels = 0;
+ while (!levels.isEmpty()) {
+ Level l = levels.stream().findAny().get();
+ boolean isCustomLoader = isCustomLoader(l);
+ if (isCustomLoader) otherLevels++;
+
+ CustomLevelReference ref = new CustomLevelReference(l, queue);
+ if (isCustomLoader) {
+ customRefs.add(ref);
+ } else {
+ refs.add(ref);
+ }
+
+ // remove strong references to l
+ levels.remove(l);
+ l = null;
+
+ // Run gc and wait for garbage collection
+ if (otherLevels == otherLevelCount) {
+ if (customRefs.size() != otherLevelCount) {
+ throw new RuntimeException("Test bug: customRefs.size() != "
+ + otherLevelCount);
+ }
+ waitForGC(customRefs, queue);
}
}
+ if (otherLevelCount != otherLevels || otherLevelCount == 0) {
+ throw new RuntimeException("Test bug: "
+ + "no or wrong count of levels loaded from custom loader");
+ }
+ if (!customRefs.isEmpty()) {
+ throw new RuntimeException(
+ "Test bug: customRefs.size() should be empty!");
+ }
+ while (!refs.isEmpty()) {
+ final Reference<?> ref = refs.remove(0);
+ if (ref.get() == null) {
+ throw new RuntimeException("Unexpected garbage collection for "
+ + ref);
+ }
+ }
+ }
+
+ private static void waitForGC(List<CustomLevelReference> customRefs,
+ ReferenceQueue<Level> queue)
+ throws InterruptedException
+ {
+ while (!customRefs.isEmpty()) {
+ Reference<? extends Level> ref2;
+ do {
+ System.gc();
+ Thread.sleep(100);
+ } while ((ref2 = queue.poll()) == null);
+
+ // Check garbage collected reference
+ if (!customRefs.contains(ref2)) {
+ throw new RuntimeException("Unexpected reference: " + ref2);
+ }
+ CustomLevelReference ref = customRefs.remove(customRefs.indexOf(ref2));
+ System.out.println(ref2 + " garbage collected");
+ final String name = ref.name;
+ Level l;
+ try {
+ l = Level.parse(name);
+ if (!name.equals("SEVERE")
+ && !name.equals("INFO")
+ || !name.equals(l.getName())) {
+ throw new RuntimeException("Unexpected level "
+ + formatLevel(l));
+ } else {
+ if (l == Level.WARNING || l == Level.INFO
+ || l == Level.SEVERE) {
+ System.out.println("Level.parse found expected level: "
+ + formatLevel(l));
+ } else {
+ throw new RuntimeException("Unexpected level "
+ + formatLevel(l));
+ }
+ }
+ } catch (IllegalArgumentException iae) {
+ if (!name.equals("WARNING")
+ && !name.equals("INFO")
+ && !name.equals("SEVERE")) {
+ System.out.println("Level.parse fired expected exception: "
+ + iae);
+ } else {
+ throw iae;
+ }
+ }
+ }
+ }
+
+ private static boolean isCustomLoader(Level level) {
+ final ClassLoader cl = level.getClass().getClassLoader();
+ return cl != null
+ && cl != ClassLoader.getPlatformClassLoader()
+ && cl != ClassLoader.getSystemClassLoader();
+ }
+
+ static ResourceBundle getResourceBundle(Level level) {
+ return isCustomLoader(level)
+ ? ResourceBundle.getBundle(OTHERRB_NAME, Locale.getDefault(),
+ level.getClass().getClassLoader())
+ : ResourceBundle.getBundle(RB_NAME);
}
private static void setupCustomLevels() throws IOException {
@@ -67,22 +220,53 @@
levels.add(new CustomLevel("WARNING", 1010, RB_NAME));
levels.add(new CustomLevel("INFO", 1000, RB_NAME));
}
+
+ static void setUpCustomLevelsOtherLoader()
+ throws MalformedURLException,
+ ClassNotFoundException, NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException
+ {
+ final String classes = System.getProperty("test.classes",
+ "build/classes");
+ final String sources = System.getProperty("test.src",
+ "src");
+ final URL curl = new File(classes).toURI().toURL();
+ final URL surl = new File(sources).toURI().toURL();
+ URLClassLoader loader = new URLClassLoader(new URL[] {curl, surl},
+ ClassLoader.getPlatformClassLoader());
+ Class<?> customLevelClass = Class.forName("CustomLevel", false, loader);
+ Method m = customLevelClass.getMethod("setUpCustomLevelsOtherLoader",
+ List.class);
+ m.invoke(null, levels);
+ }
+
+ public static void setUpCustomLevelsOtherLoader(List<Level> levels) {
+ levels.add(new CustomLevel("OTHEREMERGENCY", 1091, OTHERRB_NAME));
+ levels.add(new CustomLevel("OTHERALERT", 1061, OTHERRB_NAME));
+ levels.add(new CustomLevel("OTHERCRITICAL", 1031, OTHERRB_NAME));
+ levels.add(new CustomLevel("SEVERE", 1011, OTHERRB_NAME));
+ levels.add(new CustomLevel("INFO", 1000, OTHERRB_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));
+ throw new RuntimeException(formatLevel(level) + " != "
+ + formatLevel(expected));
}
if (!level.getName().equals(expected.getName())) {
- throw new RuntimeException(formatLevel(level) + " != " + formatLevel(expected));
+ 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));
+ throw new RuntimeException(formatLevel(level) + " != "
+ + formatLevel(expected));
}
- ResourceBundle rb = ResourceBundle.getBundle(RB_NAME);
+ final ResourceBundle rb = getResourceBundle(level);
String name = rb.getString(level.getName());
if (!level.getLocalizedName().equals(name)) {
// must have the same localized name