diff --git a/java-1.7.0-openjdk.spec b/java-1.7.0-openjdk.spec index b1ad23c..7881547 100644 --- a/java-1.7.0-openjdk.spec +++ b/java-1.7.0-openjdk.spec @@ -153,7 +153,7 @@ Name: java-%{javaver}-%{origin} Version: %{javaver}.%{buildver} -Release: %{icedtea_version}%{?dist}.1 +Release: %{icedtea_version}.1%{?dist} # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons, # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -425,10 +425,8 @@ Patch302: systemtap.patch Patch400: rhino-icedtea-2.1.1.patch # Temporary patches -# Patches to reverse 2 2012-02-01 security update - -# Back out 6664509 which bnreaks custom log managers -Patch1000: sec-2013-02-01-6664509.patch +# Patch to fix regression caused by fix for 6664509 +Patch1000: sec-2013-02-01-8005615.patch # Back out 7201064 which breaks TCK Patch1001: sec-2013-02-01-7201064.patch @@ -685,7 +683,7 @@ for TP in $TMPPATCHES ; do done ; pushd openjdk/jdk/ -%patch1000 -p1 -R +%patch1000 -p1 %patch1001 -p1 -R popd @@ -1487,6 +1485,9 @@ exit 0 %doc %{buildoutputdir}/j2sdk-image/jre/LICENSE %changelog +* Thu Feb 07 2013 Deepak Bhole - 1.7.0.9-2.3.5.1.fc18 +- Added patch for 8005615 to fix regression caused by fix for 6664509 + * Wed Feb 06 2013 Deepak Bhole - 1.7.0.9-2.3.5.fc18.1 - Backed out 6664509 and 7201064.patch which cause regressions diff --git a/sec-2013-02-01-6664509.patch b/sec-2013-02-01-6664509.patch deleted file mode 100644 index cd55ce7..0000000 --- a/sec-2013-02-01-6664509.patch +++ /dev/null @@ -1,1365 +0,0 @@ -# HG changeset patch -# User mchung -# Date 1353965537 28800 -# Node ID f26def552d2c4873aeaee00241f60efc462a11a7 -# Parent 6f9dde55bd49829cf41bd45b766780c2ec7e0bc1 -6664509: Add logging context -6664528: Find log level matching its name or value given at construction time -Reviewed-by: alanb, ahgross, jgish, hawtin - -diff --git a/src/share/classes/java/util/logging/Level.java b/src/share/classes/java/util/logging/Level.java ---- a/src/share/classes/java/util/logging/Level.java -+++ b/src/share/classes/java/util/logging/Level.java -@@ -24,6 +24,10 @@ - */ - - package java.util.logging; -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; - import java.util.ResourceBundle; - - /** -@@ -59,7 +63,6 @@ import java.util.ResourceBundle; - */ - - public class Level implements java.io.Serializable { -- private static java.util.ArrayList known = new java.util.ArrayList<>(); - private static String defaultBundle = "sun.util.logging.resources.logging"; - - /** -@@ -76,6 +79,9 @@ public class Level implements java.io.Se - * @serial The resource bundle name to be used in localizing the level name. - */ - private final String resourceBundleName; -+ -+ // localized level name -+ private String localizedLevelName; - - /** - * OFF is a special level that can be used to turn off logging. -@@ -202,9 +208,8 @@ public class Level implements java.io.Se - this.name = name; - this.value = value; - this.resourceBundleName = resourceBundleName; -- synchronized (Level.class) { -- known.add(this); -- } -+ this.localizedLevelName = resourceBundleName == null ? name : null; -+ KnownLevel.add(this); - } - - /** -@@ -236,12 +241,76 @@ public class Level implements java.io.Se - * @return localized name - */ - public String getLocalizedName() { -+ return getLocalizedLevelName(); -+ } -+ -+ // package-private getLevelName() is used by the implementation -+ // instead of getName() to avoid calling the subclass's version -+ final String getLevelName() { -+ return this.name; -+ } -+ -+ final synchronized String getLocalizedLevelName() { -+ if (localizedLevelName != null) { -+ return localizedLevelName; -+ } -+ - try { - ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName); -- return rb.getString(name); -+ localizedLevelName = rb.getString(name); - } catch (Exception ex) { -- return name; -+ localizedLevelName = name; - } -+ return localizedLevelName; -+ } -+ -+ // Returns a mirrored Level object that matches the given name as -+ // specified in the Level.parse method. Returns null if not found. -+ // -+ // It returns the same Level object as the one returned by Level.parse -+ // method if the given name is a non-localized name or integer. -+ // -+ // If the name is a localized name, findLevel and parse method may -+ // return a different level value if there is a custom Level subclass -+ // that overrides Level.getLocalizedName() to return a different string -+ // than what's returned by the default implementation. -+ // -+ static Level findLevel(String name) { -+ if (name == null) { -+ throw new NullPointerException(); -+ } -+ -+ KnownLevel level; -+ -+ // Look for a known Level with the given non-localized name. -+ level = KnownLevel.findByName(name); -+ if (level != null) { -+ return level.mirroredLevel; -+ } -+ -+ // Now, check if the given name is an integer. If so, -+ // first look for a Level with the given value and then -+ // if necessary create one. -+ try { -+ int x = Integer.parseInt(name); -+ level = KnownLevel.findByValue(x); -+ if (level == null) { -+ // add new Level -+ Level levelObject = new Level(name, x); -+ level = KnownLevel.findByValue(x); -+ } -+ return level.mirroredLevel; -+ } catch (NumberFormatException ex) { -+ // Not an integer. -+ // Drop through. -+ } -+ -+ level = KnownLevel.findByLocalizedLevelName(name); -+ if (level != null) { -+ return level.mirroredLevel; -+ } -+ -+ return null; - } - - /** -@@ -268,21 +337,15 @@ public class Level implements java.io.Se - // Serialization magic to prevent "doppelgangers". - // This is a performance optimization. - private Object readResolve() { -- synchronized (Level.class) { -- for (int i = 0; i < known.size(); i++) { -- Level other = known.get(i); -- if (this.name.equals(other.name) && this.value == other.value -- && (this.resourceBundleName == other.resourceBundleName || -- (this.resourceBundleName != null && -- this.resourceBundleName.equals(other.resourceBundleName)))) { -- return other; -- } -- } -- // Woops. Whoever sent us this object knows -- // about a new log level. Add it to our list. -- known.add(this); -- return this; -+ KnownLevel o = KnownLevel.matches(this); -+ if (o != null) { -+ return o.levelObject; - } -+ -+ // Woops. Whoever sent us this object knows -+ // about a new log level. Add it to our list. -+ Level level = new Level(this.name, this.value, this.resourceBundleName); -+ return level; - } - - /** -@@ -296,6 +359,7 @@ public class Level implements java.io.Se - *
  • "SEVERE" - *
  • "1000" - * -+ * - * @param name string to be parsed - * @throws NullPointerException if the name is null - * @throws IllegalArgumentException if the value is not valid. -@@ -315,12 +379,12 @@ public class Level implements java.io.Se - // Check that name is not null. - name.length(); - -+ KnownLevel level; -+ - // Look for a known Level with the given non-localized name. -- for (int i = 0; i < known.size(); i++) { -- Level l = known.get(i); -- if (name.equals(l.name)) { -- return l; -- } -+ level = KnownLevel.findByName(name); -+ if (level != null) { -+ return level.levelObject; - } - - // Now, check if the given name is an integer. If so, -@@ -328,14 +392,13 @@ public class Level implements java.io.Se - // if necessary create one. - try { - int x = Integer.parseInt(name); -- for (int i = 0; i < known.size(); i++) { -- Level l = known.get(i); -- if (l.value == x) { -- return l; -- } -+ level = KnownLevel.findByValue(x); -+ if (level == null) { -+ // add new Level -+ Level levelObject = new Level(name, x); -+ level = KnownLevel.findByValue(x); - } -- // Create a new Level. -- return new Level(name, x); -+ return level.levelObject; - } catch (NumberFormatException ex) { - // Not an integer. - // Drop through. -@@ -344,11 +407,9 @@ public class Level implements java.io.Se - // Finally, look for a known level with the given localized name, - // in the current default locale. - // This is relatively expensive, but not excessively so. -- for (int i = 0; i < known.size(); i++) { -- Level l = known.get(i); -- if (name.equals(l.getLocalizedName())) { -- return l; -- } -+ level = KnownLevel.findByLocalizedName(name); -+ if (level != null) { -+ return level.levelObject; - } - - // OK, we've tried everything and failed -@@ -375,4 +436,124 @@ public class Level implements java.io.Se - public int hashCode() { - return this.value; - } -+ -+ // KnownLevel class maintains the global list of all known levels. -+ // The API allows multiple custom Level instances of the same name/value -+ // be created. This class provides convenient methods to find a level -+ // by a given name, by a given value, or by a given localized name. -+ // -+ // KnownLevel wraps the following Level objects: -+ // 1. levelObject: standard Level object or custom Level object -+ // 2. mirroredLevel: Level object representing the level specified in the -+ // logging configuration. -+ // -+ // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods -+ // are non-final but the name and resource bundle name are parameters to -+ // the Level constructor. Use the mirroredLevel object instead of the -+ // levelObject to prevent the logging framework to execute foreign code -+ // implemented by untrusted Level subclass. -+ // -+ // Implementation Notes: -+ // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods -+ // were final, the following KnownLevel implementation can be removed. -+ // Future API change should take this into consideration. -+ static final class KnownLevel { -+ private static Map> nameToLevels = new HashMap<>(); -+ private static Map> intToLevels = new HashMap<>(); -+ final Level levelObject; // instance of Level class or Level subclass -+ final Level mirroredLevel; // instance of Level class -+ 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); -+ } -+ } -+ -+ static synchronized void add(Level l) { -+ // the mirroredLevel object is always added to the list -+ // before the custom Level instance -+ KnownLevel o = new KnownLevel(l); -+ List list = nameToLevels.get(l.name); -+ if (list == null) { -+ list = new ArrayList<>(); -+ nameToLevels.put(l.name, list); -+ } -+ list.add(o); -+ -+ list = intToLevels.get(l.value); -+ if (list == null) { -+ list = new ArrayList<>(); -+ intToLevels.put(l.value, list); -+ } -+ list.add(o); -+ } -+ -+ // Returns a KnownLevel with the given non-localized name. -+ static synchronized KnownLevel findByName(String name) { -+ List list = nameToLevels.get(name); -+ if (list != null) { -+ return list.get(0); -+ } -+ return null; -+ } -+ -+ // Returns a KnownLevel with the given value. -+ static synchronized KnownLevel findByValue(int value) { -+ List list = intToLevels.get(value); -+ if (list != null) { -+ return list.get(0); -+ } -+ return null; -+ } -+ -+ // Returns a KnownLevel with the given localized name matching -+ // by calling the Level.getLocalizedLevelName() method (i.e. found -+ // from the resourceBundle associated with the Level object). -+ // This method does not call Level.getLocalizedName() that may -+ // be overridden in a subclass implementation -+ static synchronized KnownLevel findByLocalizedLevelName(String name) { -+ for (List levels : nameToLevels.values()) { -+ for (KnownLevel l : levels) { -+ String lname = l.levelObject.getLocalizedLevelName(); -+ if (name.equals(lname)) { -+ return l; -+ } -+ } -+ } -+ 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 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 list = nameToLevels.get(l.name); -+ if (list != null) { -+ for (KnownLevel level : list) { -+ Level other = level.mirroredLevel; -+ if (l.value == other.value && -+ (l.resourceBundleName == other.resourceBundleName || -+ (l.resourceBundleName != null && -+ l.resourceBundleName.equals(other.resourceBundleName)))) { -+ return level; -+ } -+ } -+ } -+ return null; -+ } -+ } -+ - } -diff --git a/src/share/classes/java/util/logging/LogManager.java b/src/share/classes/java/util/logging/LogManager.java ---- a/src/share/classes/java/util/logging/LogManager.java -+++ b/src/share/classes/java/util/logging/LogManager.java -@@ -34,6 +34,8 @@ import java.beans.PropertyChangeListener - import java.beans.PropertyChangeListener; - import java.beans.PropertyChangeSupport; - import java.net.URL; -+import sun.misc.JavaAWTAccess; -+import sun.misc.SharedSecrets; - import sun.security.action.GetPropertyAction; - - /** -@@ -155,10 +157,9 @@ public class LogManager { - = new PropertyChangeSupport(LogManager.class); - private final static Level defaultLevel = Level.INFO; - -- // Table of named Loggers that maps names to Loggers. -- private Hashtable namedLoggers = new Hashtable<>(); -- // Tree of named Loggers -- private LogNode root = new LogNode(null); -+ // LoggerContext for system loggers and user loggers -+ private final LoggerContext systemContext = new SystemLoggerContext(); -+ private final LoggerContext userContext = new UserLoggerContext(); - private Logger rootLogger; - - // Have we done the primordial reading of the configuration file? -@@ -196,12 +197,13 @@ public class LogManager { - - // Create and retain Logger for the root of the namespace. - manager.rootLogger = manager.new RootLogger(); -- manager.addLogger(manager.rootLogger); -+ manager.systemContext.addLogger(manager.rootLogger); -+ manager.userContext.addLogger(manager.rootLogger); - - // Adding the global Logger. Doing so in the Logger. - // would deadlock with the LogManager.. - Logger.global.setLogManager(manager); -- manager.addLogger(Logger.global); -+ manager.systemContext.addLogger(Logger.global); - - // We don't call readConfiguration() here, as we may be running - // very early in the JVM startup sequence. Instead readConfiguration -@@ -279,14 +281,14 @@ public class LogManager { - return; - } - readPrimordialConfiguration = true; -+ - try { -- AccessController.doPrivileged(new PrivilegedExceptionAction() { -- public Object run() throws Exception { -+ AccessController.doPrivileged(new PrivilegedExceptionAction() { -+ public Void run() throws Exception { - readConfiguration(); - - // Platform loggers begin to delegate to java.util.logging.Logger - sun.util.logging.PlatformLogger.redirectPlatformLoggers(); -- - return null; - } - }); -@@ -337,62 +339,290 @@ public class LogManager { - changes.removePropertyChangeListener(l); - } - -- // Package-level method. -- // Find or create a specified logger instance. If a logger has -- // already been created with the given name it is returned. -- // Otherwise a new logger instance is created and registered -- // in the LogManager global namespace. -+ // Returns the LoggerContext for the user code (i.e. application or AppContext). -+ // Loggers are isolated from each AppContext. -+ LoggerContext getUserContext() { -+ LoggerContext context = null; - -- // This method will always return a non-null Logger object. -- // Synchronization is not required here. All synchronization for -- // adding a new Logger object is handled by addLogger(). -- Logger demandLogger(String name) { -- Logger result = getLogger(name); -- if (result == null) { -- // only allocate the new logger once -- Logger newLogger = new Logger(name, null); -- do { -- if (addLogger(newLogger)) { -- // We successfully added the new Logger that we -- // created above so return it without refetching. -- return newLogger; -+ SecurityManager sm = System.getSecurityManager(); -+ JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess(); -+ if (sm != null && javaAwtAccess != null) { -+ synchronized (javaAwtAccess) { -+ // AppContext.getAppContext() returns the system AppContext if called -+ // from a system thread but Logger.getLogger might be called from -+ // an applet code. Instead, find the AppContext of the applet code -+ // from the execution stack. -+ Object ecx = javaAwtAccess.getExecutionContext(); -+ if (ecx == null) { -+ // fall back to AppContext.getAppContext() -+ ecx = javaAwtAccess.getContext(); - } -- -- // We didn't add the new Logger that we created above -- // because another thread added a Logger with the same -- // name after our null check above and before our call -- // to addLogger(). We have to refetch the Logger because -- // addLogger() returns a boolean instead of the Logger -- // reference itself. However, if the thread that created -- // the other Logger is not holding a strong reference to -- // the other Logger, then it is possible for the other -- // Logger to be GC'ed after we saw it in addLogger() and -- // before we can refetch it. If it has been GC'ed then -- // we'll just loop around and try again. -- result = getLogger(name); -- } while (result == null); -+ context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); -+ if (context == null) { -+ if (javaAwtAccess.isMainAppContext()) { -+ context = userContext; -+ } else { -+ context = new UserLoggerContext(); -+ context.addLogger(manager.rootLogger); -+ } -+ javaAwtAccess.put(ecx, LoggerContext.class, context); -+ } -+ } -+ } else { -+ context = userContext; - } -- return result; -+ return context; - } - -- // If logger.getUseParentHandlers() returns 'true' and any of the logger's -- // parents have levels or handlers defined, make sure they are instantiated. -- private void processParentHandlers(Logger logger, String name) { -- int ix = 1; -- for (;;) { -- int ix2 = name.indexOf(".", ix); -- if (ix2 < 0) { -- break; -+ LoggerContext getSystemContext() { -+ return systemContext; -+ } -+ -+ private List contexts() { -+ List cxs = new ArrayList<>(); -+ cxs.add(systemContext); -+ cxs.add(getUserContext()); -+ return cxs; -+ } -+ -+ static class LoggerContext { -+ // Table of named Loggers that maps names to Loggers. -+ private final Hashtable namedLoggers = new Hashtable<>(); -+ // Tree of named Loggers -+ private final LogNode root; -+ -+ private LoggerContext() { -+ this.root = new LogNode(null, this); -+ } -+ -+ synchronized Logger findLogger(String name) { -+ LoggerWeakRef ref = namedLoggers.get(name); -+ if (ref == null) { -+ return null; - } -- String pname = name.substring(0,ix2); -+ Logger logger = ref.get(); -+ if (logger == null) { -+ // Hashtable holds stale weak reference -+ // to a logger which has been GC-ed. -+ removeLogger(name); -+ } -+ return logger; -+ } - -- if (getProperty(pname+".level") != null || -- getProperty(pname+".handlers") != null) { -- // This pname has a level/handlers definition. -- // Make sure it exists. -- demandLogger(pname); -+ synchronized boolean addLogger(Logger logger) { -+ final String name = logger.getName(); -+ if (name == null) { -+ throw new NullPointerException(); - } -- ix = ix2+1; -+ -+ // cleanup some Loggers that have been GC'ed -+ manager.drainLoggerRefQueueBounded(); -+ -+ LoggerWeakRef ref = namedLoggers.get(name); -+ if (ref != null) { -+ if (ref.get() == null) { -+ // It's possible that the Logger was GC'ed after the -+ // drainLoggerRefQueueBounded() call above so allow -+ // a new one to be registered. -+ removeLogger(name); -+ } else { -+ // We already have a registered logger with the given name. -+ return false; -+ } -+ } -+ -+ // We're adding a new logger. -+ // Note that we are creating a weak reference here. -+ ref = manager.new LoggerWeakRef(logger); -+ namedLoggers.put(name, ref); -+ -+ // Apply any initial level defined for the new logger. -+ Level level = manager.getLevelProperty(name + ".level", null); -+ if (level != null) { -+ doSetLevel(logger, level); -+ } -+ -+ // Do we have a per logger handler too? -+ // Note: this will add a 200ms penalty -+ manager.loadLoggerHandlers(logger, name, name + ".handlers"); -+ processParentHandlers(logger, name); -+ -+ // Find the new node and its parent. -+ LogNode node = getNode(name); -+ node.loggerRef = ref; -+ Logger parent = null; -+ LogNode nodep = node.parent; -+ while (nodep != null) { -+ LoggerWeakRef nodeRef = nodep.loggerRef; -+ if (nodeRef != null) { -+ parent = nodeRef.get(); -+ if (parent != null) { -+ break; -+ } -+ } -+ nodep = nodep.parent; -+ } -+ -+ if (parent != null) { -+ doSetParent(logger, parent); -+ } -+ // Walk over the children and tell them we are their new parent. -+ node.walkAndSetParent(logger); -+ // new LogNode is ready so tell the LoggerWeakRef about it -+ ref.setNode(node); -+ return true; -+ } -+ -+ void removeLogger(String name) { -+ namedLoggers.remove(name); -+ } -+ -+ synchronized Enumeration getLoggerNames() { -+ return namedLoggers.keys(); -+ } -+ -+ Logger demandLogger(String name) { -+ return demandLogger(name, null); -+ } -+ -+ // Find or create a specified logger instance. If a logger has -+ // already been created with the given name it is returned. -+ // Otherwise a new logger instance is created and registered -+ // in the LogManager global namespace. -+ -+ // This method will always return a non-null Logger object. -+ // Synchronization is not required here. All synchronization for -+ // adding a new Logger object is handled by addLogger(). -+ Logger demandLogger(String name, String resourceBundleName) { -+ Logger result = findLogger(name); -+ if (result == null) { -+ // only allocate the new logger once -+ Logger newLogger = new Logger(name, resourceBundleName); -+ do { -+ if (addLogger(newLogger)) { -+ // We successfully added the new Logger that we -+ // created above so return it without refetching. -+ return newLogger; -+ } -+ -+ // We didn't add the new Logger that we created above -+ // because another thread added a Logger with the same -+ // name after our null check above and before our call -+ // to addLogger(). We have to refetch the Logger because -+ // addLogger() returns a boolean instead of the Logger -+ // reference itself. However, if the thread that created -+ // the other Logger is not holding a strong reference to -+ // the other Logger, then it is possible for the other -+ // Logger to be GC'ed after we saw it in addLogger() and -+ // before we can refetch it. If it has been GC'ed then -+ // we'll just loop around and try again. -+ result = findLogger(name); -+ } while (result == null); -+ } -+ return result; -+ } -+ -+ // If logger.getUseParentHandlers() returns 'true' and any of the logger's -+ // parents have levels or handlers defined, make sure they are instantiated. -+ private void processParentHandlers(Logger logger, String name) { -+ int ix = 1; -+ for (;;) { -+ int ix2 = name.indexOf(".", ix); -+ if (ix2 < 0) { -+ break; -+ } -+ String pname = name.substring(0, ix2); -+ -+ if (manager.getProperty(pname + ".level") != null || -+ manager.getProperty(pname + ".handlers") != null) { -+ // This pname has a level/handlers definition. -+ // Make sure it exists. -+ demandLogger(pname); -+ } -+ ix = ix2+1; -+ } -+ } -+ -+ // Gets a node in our tree of logger nodes. -+ // If necessary, create it. -+ LogNode getNode(String name) { -+ if (name == null || name.equals("")) { -+ return root; -+ } -+ LogNode node = root; -+ while (name.length() > 0) { -+ int ix = name.indexOf("."); -+ String head; -+ if (ix > 0) { -+ head = name.substring(0, ix); -+ name = name.substring(ix + 1); -+ } else { -+ head = name; -+ name = ""; -+ } -+ if (node.children == null) { -+ node.children = new HashMap<>(); -+ } -+ LogNode child = node.children.get(head); -+ if (child == null) { -+ child = new LogNode(node, this); -+ node.children.put(head, child); -+ } -+ node = child; -+ } -+ return node; -+ } -+ } -+ -+ static class SystemLoggerContext extends LoggerContext { -+ // Default resource bundle for all system loggers -+ Logger demandLogger(String name) { -+ // default to use the system logger's resource bundle -+ return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); -+ } -+ } -+ -+ static class UserLoggerContext extends LoggerContext { -+ /** -+ * Returns a Logger of the given name if there is one registered -+ * in this context. Otherwise, it will return the one registered -+ * in the system context if there is one. The returned Logger -+ * instance may be initialized with a different resourceBundleName. -+ * If no such logger exists, a new Logger instance will be created -+ * and registered in this context. -+ */ -+ Logger demandLogger(String name, String resourceBundleName) { -+ Logger result = findLogger(name); -+ if (result == null) { -+ // use the system logger if exists; or allocate a new logger. -+ // The system logger is added to the app logger context so that -+ // any child logger created in the app logger context can have -+ // a system logger as its parent if already exist. -+ Logger logger = manager.systemContext.findLogger(name); -+ Logger newLogger = -+ logger != null ? logger : new Logger(name, resourceBundleName); -+ do { -+ if (addLogger(newLogger)) { -+ // We successfully added the new Logger that we -+ // created above so return it without refetching. -+ return newLogger; -+ } -+ -+ // We didn't add the new Logger that we created above -+ // because another thread added a Logger with the same -+ // name after our null check above and before our call -+ // to addLogger(). We have to refetch the Logger because -+ // addLogger() returns a boolean instead of the Logger -+ // reference itself. However, if the thread that created -+ // the other Logger is not holding a strong reference to -+ // the other Logger, then it is possible for the other -+ // Logger to be GC'ed after we saw it in addLogger() and -+ // before we can refetch it. If it has been GC'ed then -+ // we'll just loop around and try again. -+ result = findLogger(name); -+ } while (result == null); -+ } -+ return result; - } - } - -@@ -415,18 +645,19 @@ public class LogManager { - for (int i = 0; i < names.length; i++) { - String word = names[i]; - try { -- Class clz = ClassLoader.getSystemClassLoader().loadClass(word); -- Handler hdl = (Handler) clz.newInstance(); -- try { -- // Check if there is a property defining the -- // this handler's level. -- String levs = getProperty(word + ".level"); -- if (levs != null) { -- hdl.setLevel(Level.parse(levs)); -+ Class clz = ClassLoader.getSystemClassLoader().loadClass(word); -+ Handler hdl = (Handler) clz.newInstance(); -+ // Check if there is a property defining the -+ // this handler's level. -+ String levs = getProperty(word + ".level"); -+ if (levs != null) { -+ Level l = Level.findLevel(levs); -+ if (l != null) { -+ hdl.setLevel(l); -+ } else { -+ // Probably a bad level. Drop through. -+ System.err.println("Can't set level for " + word); - } -- } catch (Exception ex) { -- System.err.println("Can't set level for " + word); -- // Probably a bad level. Drop through. - } - // Add this Handler to the logger - logger.addHandler(hdl); -@@ -482,7 +713,7 @@ public class LogManager { - if (node != null) { - // if we have a LogNode, then we were a named Logger - // so clear namedLoggers weak ref to us -- manager.namedLoggers.remove(name); -+ node.context.removeLogger(name); - name = null; // clear our ref to the Logger's name - - node.loggerRef = null; // clear LogNode's weak ref to us -@@ -571,70 +802,15 @@ public class LogManager { - * false if a logger of that name already exists. - * @exception NullPointerException if the logger name is null. - */ -- public synchronized boolean addLogger(Logger logger) { -+ public boolean addLogger(Logger logger) { - final String name = logger.getName(); - if (name == null) { - throw new NullPointerException(); - } -- -- // cleanup some Loggers that have been GC'ed -- drainLoggerRefQueueBounded(); -- -- LoggerWeakRef ref = namedLoggers.get(name); -- if (ref != null) { -- if (ref.get() == null) { -- // It's possible that the Logger was GC'ed after the -- // drainLoggerRefQueueBounded() call above so allow -- // a new one to be registered. -- namedLoggers.remove(name); -- } else { -- // We already have a registered logger with the given name. -- return false; -- } -+ if (systemContext.findLogger(name) != null) { -+ return false; - } -- -- // We're adding a new logger. -- // Note that we are creating a weak reference here. -- ref = new LoggerWeakRef(logger); -- namedLoggers.put(name, ref); -- -- // Apply any initial level defined for the new logger. -- Level level = getLevelProperty(name+".level", null); -- if (level != null) { -- doSetLevel(logger, level); -- } -- -- // Do we have a per logger handler too? -- // Note: this will add a 200ms penalty -- loadLoggerHandlers(logger, name, name+".handlers"); -- processParentHandlers(logger, name); -- -- // Find the new node and its parent. -- LogNode node = findNode(name); -- node.loggerRef = ref; -- Logger parent = null; -- LogNode nodep = node.parent; -- while (nodep != null) { -- LoggerWeakRef nodeRef = nodep.loggerRef; -- if (nodeRef != null) { -- parent = nodeRef.get(); -- if (parent != null) { -- break; -- } -- } -- nodep = nodep.parent; -- } -- -- if (parent != null) { -- doSetParent(logger, parent); -- } -- // Walk over the children and tell them we are their new parent. -- node.walkAndSetParent(logger); -- -- // new LogNode is ready so tell the LoggerWeakRef about it -- ref.setNode(node); -- -- return true; -+ return getUserContext().addLogger(logger); - } - - -@@ -676,36 +852,6 @@ public class LogManager { - }}); - } - -- // Find a node in our tree of logger nodes. -- // If necessary, create it. -- private LogNode findNode(String name) { -- if (name == null || name.equals("")) { -- return root; -- } -- LogNode node = root; -- while (name.length() > 0) { -- int ix = name.indexOf("."); -- String head; -- if (ix > 0) { -- head = name.substring(0,ix); -- name = name.substring(ix+1); -- } else { -- head = name; -- name = ""; -- } -- if (node.children == null) { -- node.children = new HashMap<>(); -- } -- LogNode child = node.children.get(head); -- if (child == null) { -- child = new LogNode(node); -- node.children.put(head, child); -- } -- node = child; -- } -- return node; -- } -- - /** - * Method to find a named logger. - *

    -@@ -721,18 +867,16 @@ public class LogManager { - * @param name name of the logger - * @return matching logger or null if none is found - */ -- public synchronized Logger getLogger(String name) { -- LoggerWeakRef ref = namedLoggers.get(name); -- if (ref == null) { -- return null; -- } -- Logger logger = ref.get(); -- if (logger == null) { -- // Hashtable holds stale weak reference -- // to a logger which has been GC-ed. -- namedLoggers.remove(name); -- } -- return logger; -+ public Logger getLogger(String name) { -+ // return the first logger added -+ // -+ // once a system logger is added in the system context, no one can -+ // adds a logger with the same name in the global context -+ // (see LogManager.addLogger). So if there is a logger in the global -+ // context with the same name as one in the system context, it must be -+ // added before the system logger was created. -+ Logger logger = getUserContext().findLogger(name); -+ return logger != null ? logger : systemContext.findLogger(name); - } - - /** -@@ -751,8 +895,11 @@ public class LogManager { - *

    - * @return enumeration of logger name strings - */ -- public synchronized Enumeration getLoggerNames() { -- return namedLoggers.keys(); -+ public Enumeration getLoggerNames() { -+ // only return unique names -+ Set names = new HashSet<>(Collections.list(systemContext.getLoggerNames())); -+ names.addAll(Collections.list(getUserContext().getLoggerNames())); -+ return Collections.enumeration(names); - } - - /** -@@ -837,20 +984,20 @@ public class LogManager { - // the global handlers, if they haven't been initialized yet. - initializedGlobalHandlers = true; - } -- Enumeration enum_ = getLoggerNames(); -- while (enum_.hasMoreElements()) { -- String name = (String)enum_.nextElement(); -- resetLogger(name); -+ for (LoggerContext cx : contexts()) { -+ Enumeration enum_ = cx.getLoggerNames(); -+ while (enum_.hasMoreElements()) { -+ String name = enum_.nextElement(); -+ Logger logger = cx.findLogger(name); -+ if (logger != null) { -+ resetLogger(logger); -+ } -+ } - } - } - -- - // Private method to reset an individual target logger. -- private void resetLogger(String name) { -- Logger logger = getLogger(name); -- if (logger == null) { -- return; -- } -+ private void resetLogger(Logger logger) { - // Close all the Logger's handlers. - Handler[] targets = logger.getHandlers(); - for (int i = 0; i < targets.length; i++) { -@@ -862,6 +1009,7 @@ public class LogManager { - // Problems closing a handler? Keep going... - } - } -+ String name = logger.getName(); - if (name != null && name.equals("")) { - // This is the root logger. - logger.setLevel(defaultLevel); -@@ -1009,11 +1157,8 @@ public class LogManager { - if (val == null) { - return defaultValue; - } -- try { -- return Level.parse(val.trim()); -- } catch (Exception ex) { -- return defaultValue; -- } -+ Level l = Level.findLevel(val.trim()); -+ return l != null ? l : defaultValue; - } - - // Package private method to get a filter property. -@@ -1104,9 +1249,11 @@ public class LogManager { - HashMap children; - LoggerWeakRef loggerRef; - LogNode parent; -+ final LoggerContext context; - -- LogNode(LogNode parent) { -+ LogNode(LogNode parent, LoggerContext context) { - this.parent = parent; -+ this.context = context; - } - - // Recursive method to walk the tree below a node and set -@@ -1165,7 +1312,7 @@ public class LogManager { - // Private method to be called when the configuration has - // changed to apply any level settings to any pre-existing loggers. - synchronized private void setLevelsOnExistingLoggers() { -- Enumeration enum_ = props.propertyNames(); -+ Enumeration enum_ = props.propertyNames(); - while (enum_.hasMoreElements()) { - String key = (String)enum_.nextElement(); - if (!key.endsWith(".level")) { -@@ -1179,11 +1326,13 @@ public class LogManager { - System.err.println("Bad level value for property: " + key); - continue; - } -- Logger l = getLogger(name); -- if (l == null) { -- continue; -+ for (LoggerContext cx : contexts()) { -+ Logger l = cx.findLogger(name); -+ if (l == null) { -+ continue; -+ } -+ l.setLevel(level); - } -- l.setLevel(level); - } - } - -diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java ---- a/src/share/classes/java/util/logging/Logger.java -+++ b/src/share/classes/java/util/logging/Logger.java -@@ -30,6 +30,7 @@ import java.util.concurrent.CopyOnWriteA - import java.util.concurrent.CopyOnWriteArrayList; - import java.security.*; - import java.lang.ref.WeakReference; -+import java.util.logging.LogManager.LoggerContext; - - /** - * A Logger object is used to log messages for a specific -@@ -283,6 +284,26 @@ public class Logger { - } - } - -+ // Until all JDK code converted to call sun.util.logging.PlatformLogger -+ // (see 7054233), we need to determine if Logger.getLogger is to add -+ // a system logger or user logger. -+ // -+ // As an interim solution, if the immediate caller whose caller loader is -+ // null, we assume it's a system logger and add it to the system context. -+ private static LoggerContext getLoggerContext() { -+ LogManager manager = LogManager.getLogManager(); -+ SecurityManager sm = System.getSecurityManager(); -+ if (sm != null) { -+ // 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller -+ final int SKIP_FRAMES = 3; -+ Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); -+ if (caller.getClassLoader() == null) { -+ return manager.getSystemContext(); -+ } -+ } -+ return manager.getUserContext(); -+ } -+ - /** - * Find or create a logger for a named subsystem. If a logger has - * already been created with the given name it is returned. Otherwise -@@ -324,8 +345,8 @@ public class Logger { - // would throw an IllegalArgumentException in the second call - // because the wrapper would result in an attempt to replace - // the existing "resourceBundleForFoo" with null. -- LogManager manager = LogManager.getLogManager(); -- return manager.demandLogger(name); -+ LoggerContext context = getLoggerContext(); -+ return context.demandLogger(name); - } - - /** -@@ -372,8 +393,8 @@ public class Logger { - // Synchronization is not required here. All synchronization for - // adding a new Logger object is handled by LogManager.addLogger(). - public static Logger getLogger(String name, String resourceBundleName) { -- LogManager manager = LogManager.getLogManager(); -- Logger result = manager.demandLogger(name); -+ LoggerContext context = getLoggerContext(); -+ Logger result = context.demandLogger(name, resourceBundleName); - if (result.resourceBundleName == null) { - // Note: we may get a MissingResourceException here. - result.setupResourceInfo(resourceBundleName); -@@ -384,6 +405,18 @@ public class Logger { - return result; - } - -+ // package-private -+ // Add a platform logger to the system context. -+ // i.e. caller of sun.util.logging.PlatformLogger.getLogger -+ static Logger getPlatformLogger(String name) { -+ LogManager manager = LogManager.getLogManager(); -+ LoggerContext context = manager.getSystemContext(); -+ -+ // all loggers in the system context will default to -+ // the system logger's resource bundle -+ Logger result = context.demandLogger(name); -+ return result; -+ } - - /** - * Create an anonymous Logger. The newly created Logger is not -@@ -536,7 +569,7 @@ public class Logger { - private void doLog(LogRecord lr) { - lr.setLoggerName(name); - String ebname = getEffectiveResourceBundleName(); -- if (ebname != null) { -+ if (ebname != null && !ebname.equals(SYSTEM_LOGGER_RB_NAME)) { - lr.setResourceBundleName(ebname); - lr.setResourceBundle(findResourceBundle(ebname)); - } -@@ -1285,6 +1318,22 @@ public class Logger { - // May also return null if we can't find the resource bundle and - // there is no suitable previous cached value. - -+ static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging"; -+ -+ private static ResourceBundle findSystemResourceBundle(final Locale locale) { -+ // the resource bundle is in a restricted package -+ return AccessController.doPrivileged(new PrivilegedAction() { -+ public ResourceBundle run() { -+ try { -+ return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, -+ locale); -+ } catch (MissingResourceException e) { -+ throw new InternalError(e.toString()); -+ } -+ } -+ }); -+ } -+ - private synchronized ResourceBundle findResourceBundle(String name) { - // Return a null bundle for a null name. - if (name == null) { -@@ -1296,6 +1345,13 @@ public class Logger { - // Normally we should hit on our simple one entry cache. - if (catalog != null && currentLocale == catalogLocale - && name == catalogName) { -+ return catalog; -+ } -+ -+ if (name.equals(SYSTEM_LOGGER_RB_NAME)) { -+ catalog = findSystemResourceBundle(currentLocale); -+ catalogName = name; -+ catalogLocale = currentLocale; - return catalog; - } - -@@ -1314,7 +1370,6 @@ public class Logger { - // Woops. We can't find the ResourceBundle in the default - // ClassLoader. Drop through. - } -- - - // Fall back to searching up the call stack and trying each - // calling ClassLoader. -diff --git a/src/share/classes/java/util/logging/Logging.java b/src/share/classes/java/util/logging/Logging.java ---- a/src/share/classes/java/util/logging/Logging.java -+++ b/src/share/classes/java/util/logging/Logging.java -@@ -34,15 +34,15 @@ import java.util.ArrayList; - * - * The LoggingMXBean interface provides a standard - * method for management access to the individual -- * java.util.Logger objects available at runtime. -+ * {@code Logger} objects available at runtime. - * - * @author Ron Mann - * @author Mandy Chung - * @since 1.5 - * - * @see javax.management -- * @see java.util.Logger -- * @see java.util.LogManager -+ * @see Logger -+ * @see LogManager - */ - class Logging implements LoggingMXBean { - -@@ -75,7 +75,7 @@ class Logging implements LoggingMXBean { - if (level == null) { - return EMPTY_STRING; - } else { -- return level.getName(); -+ return level.getLevelName(); - } - } - -@@ -85,7 +85,6 @@ class Logging implements LoggingMXBean { - } - - Logger logger = logManager.getLogger(loggerName); -- - if (logger == null) { - throw new IllegalArgumentException("Logger " + loggerName + - "does not exist"); -@@ -94,7 +93,10 @@ class Logging implements LoggingMXBean { - Level level = null; - if (levelName != null) { - // parse will throw IAE if logLevel is invalid -- level = Level.parse(levelName); -+ level = Level.findLevel(levelName); -+ if (level == null) { -+ throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); -+ } - } - - logger.setLevel(level); -diff --git a/src/share/classes/java/util/logging/LoggingProxyImpl.java b/src/share/classes/java/util/logging/LoggingProxyImpl.java ---- a/src/share/classes/java/util/logging/LoggingProxyImpl.java -+++ b/src/share/classes/java/util/logging/LoggingProxyImpl.java -@@ -37,7 +37,8 @@ class LoggingProxyImpl implements Loggin - - @Override - public Object getLogger(String name) { -- return Logger.getLogger(name); -+ // always create a platform logger with the resource bundle name -+ return Logger.getPlatformLogger(name); - } - - @Override -@@ -92,12 +93,16 @@ class LoggingProxyImpl implements Loggin - - @Override - public Object parseLevel(String levelName) { -- return Level.parse(levelName); -+ Level level = Level.findLevel(levelName); -+ if (level == null) { -+ throw new IllegalArgumentException("Unknown level \"" + levelName + "\""); -+ } -+ return level; - } - - @Override - public String getLevelName(Object level) { -- return ((Level) level).getName(); -+ return ((Level) level).getLevelName(); - } - - @Override -diff --git a/src/share/classes/java/util/logging/SimpleFormatter.java b/src/share/classes/java/util/logging/SimpleFormatter.java ---- a/src/share/classes/java/util/logging/SimpleFormatter.java -+++ b/src/share/classes/java/util/logging/SimpleFormatter.java -@@ -162,7 +162,7 @@ public class SimpleFormatter extends For - dat, - source, - record.getLoggerName(), -- record.getLevel().getLocalizedName(), -+ record.getLevel().getLocalizedLevelName(), - message, - throwable); - } -diff --git a/src/share/classes/sun/awt/AppContext.java b/src/share/classes/sun/awt/AppContext.java ---- a/src/share/classes/sun/awt/AppContext.java -+++ b/src/share/classes/sun/awt/AppContext.java -@@ -327,19 +327,25 @@ public final class AppContext { - // Before we return the main "system" AppContext, check to - // see if there's an AWTSecurityManager installed. If so, - // allow it to choose the AppContext to return. -- SecurityManager securityManager = System.getSecurityManager(); -- if ((securityManager != null) && -- (securityManager instanceof AWTSecurityManager)) -- { -- AWTSecurityManager awtSecMgr = (AWTSecurityManager)securityManager; -- AppContext secAppContext = awtSecMgr.getAppContext(); -- if (secAppContext != null) { -- appContext = secAppContext; // Return what we're told -- } -+ AppContext secAppContext = getExecutionAppContext(); -+ if (secAppContext != null) { -+ appContext = secAppContext; // Return what we're told - } - } - - return appContext; -+ } -+ -+ private final static AppContext getExecutionAppContext() { -+ SecurityManager securityManager = System.getSecurityManager(); -+ if ((securityManager != null) && -+ (securityManager instanceof AWTSecurityManager)) -+ { -+ AWTSecurityManager awtSecMgr = (AWTSecurityManager) securityManager; -+ AppContext secAppContext = awtSecMgr.getAppContext(); -+ return secAppContext; // Return what we're told -+ } -+ return null; - } - - /** -@@ -806,6 +812,21 @@ public final class AppContext { - public boolean isMainAppContext() { - return (numAppContexts == 1); - } -+ public Object getContext() { -+ return getAppContext(); -+ } -+ public Object getExecutionContext() { -+ return getExecutionAppContext(); -+ } -+ public Object get(Object context, Object key) { -+ return ((AppContext)context).get(key); -+ } -+ public void put(Object context, Object key, Object value) { -+ ((AppContext)context).put(key, value); -+ } -+ public void remove(Object context, Object key) { -+ ((AppContext)context).remove(key); -+ } - }); - } - } -diff --git a/src/share/classes/sun/misc/JavaAWTAccess.java b/src/share/classes/sun/misc/JavaAWTAccess.java ---- a/src/share/classes/sun/misc/JavaAWTAccess.java -+++ b/src/share/classes/sun/misc/JavaAWTAccess.java -@@ -26,6 +26,14 @@ package sun.misc; - package sun.misc; - - public interface JavaAWTAccess { -+ public Object getContext(); -+ public Object getExecutionContext(); -+ -+ public Object get(Object context, Object key); -+ public void put(Object context, Object key, Object value); -+ public void remove(Object context, Object key); -+ -+ // convenience methods whose context is the object returned by getContext() - public Object get(Object key); - public void put(Object key, Object value); - public void remove(Object key); -diff --git a/src/share/lib/security/java.security b/src/share/lib/security/java.security ---- a/src/share/lib/security/java.security -+++ b/src/share/lib/security/java.security -@@ -126,6 +126,9 @@ package.access=sun.,\ - package.access=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ -+ com.sun.istack.internal.,\ -+ com.sun.jmx.default.,\ -+ com.sun.jmx.remote.util.,\ - com.sun.org.apache.xerces.internal.utils.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ -@@ -144,6 +147,9 @@ package.definition=sun.,\ - package.definition=sun.,\ - com.sun.xml.internal.,\ - com.sun.imageio.,\ -+ com.sun.istack.internal.,\ -+ com.sun.jmx.default.,\ -+ com.sun.jmx.remote.util.,\ - com.sun.org.apache.xerces.internal.utils.,\ - com.sun.org.apache.xalan.internal.utils.,\ - com.sun.org.glassfish.external.,\ diff --git a/sec-2013-02-01-8005615.patch b/sec-2013-02-01-8005615.patch new file mode 100644 index 0000000..bcd1d02 --- /dev/null +++ b/sec-2013-02-01-8005615.patch @@ -0,0 +1,646 @@ +diff --git a/src/share/classes/java/util/logging/LogManager.java b/src/share/classes/java/util/logging/LogManager.java +--- a/src/share/classes/java/util/logging/LogManager.java ++++ b/src/share/classes/java/util/logging/LogManager.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2000, 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 +@@ -159,7 +159,7 @@ + + // LoggerContext for system loggers and user loggers + private final LoggerContext systemContext = new SystemLoggerContext(); +- private final LoggerContext userContext = new UserLoggerContext(); ++ private final LoggerContext userContext = new LoggerContext(); + private Logger rootLogger; + + // Have we done the primordial reading of the configuration file? +@@ -197,13 +197,13 @@ + + // Create and retain Logger for the root of the namespace. + manager.rootLogger = manager.new RootLogger(); +- manager.systemContext.addLogger(manager.rootLogger); +- manager.userContext.addLogger(manager.rootLogger); ++ manager.addLogger(manager.rootLogger); ++ manager.systemContext.addLocalLogger(manager.rootLogger); + + // Adding the global Logger. Doing so in the Logger. + // would deadlock with the LogManager.. + Logger.global.setLogManager(manager); +- manager.systemContext.addLogger(Logger.global); ++ manager.addLogger(Logger.global); + + // We don't call readConfiguration() here, as we may be running + // very early in the JVM startup sequence. Instead readConfiguration +@@ -341,7 +341,7 @@ + + // Returns the LoggerContext for the user code (i.e. application or AppContext). + // Loggers are isolated from each AppContext. +- LoggerContext getUserContext() { ++ private LoggerContext getUserContext() { + LoggerContext context = null; + + SecurityManager sm = System.getSecurityManager(); +@@ -357,13 +357,13 @@ + // fall back to AppContext.getAppContext() + ecx = javaAwtAccess.getContext(); + } +- context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class); ++ context = (LoggerContext) javaAwtAccess.get(ecx, LoggerContext.class); + if (context == null) { + if (javaAwtAccess.isMainAppContext()) { + context = userContext; + } else { +- context = new UserLoggerContext(); +- context.addLogger(manager.rootLogger); ++ context = new LoggerContext(); ++ context.addLocalLogger(manager.rootLogger); + } + javaAwtAccess.put(ecx, LoggerContext.class, context); + } +@@ -374,10 +374,6 @@ + return context; + } + +- LoggerContext getSystemContext() { +- return systemContext; +- } +- + private List contexts() { + List cxs = new ArrayList<>(); + cxs.add(systemContext); +@@ -385,6 +381,58 @@ + return cxs; + } + ++ // Find or create a specified logger instance. If a logger has ++ // already been created with the given name it is returned. ++ // Otherwise a new logger instance is created and registered ++ // in the LogManager global namespace. ++ // This method will always return a non-null Logger object. ++ // Synchronization is not required here. All synchronization for ++ // adding a new Logger object is handled by addLogger(). ++ // ++ // This method must delegate to the LogManager implementation to ++ // add a new Logger or return the one that has been added previously ++ // as a LogManager subclass may override the addLogger, getLogger, ++ // readConfiguration, and other methods. ++ Logger demandLogger(String name, String resourceBundleName) { ++ Logger result = getLogger(name); ++ if (result == null) { ++ // only allocate the new logger once ++ Logger newLogger = new Logger(name, resourceBundleName); ++ do { ++ if (addLogger(newLogger)) { ++ // We successfully added the new Logger that we ++ // created above so return it without refetching. ++ return newLogger; ++ } ++ ++ // We didn't add the new Logger that we created above ++ // because another thread added a Logger with the same ++ // name after our null check above and before our call ++ // to addLogger(). We have to refetch the Logger because ++ // addLogger() returns a boolean instead of the Logger ++ // reference itself. However, if the thread that created ++ // the other Logger is not holding a strong reference to ++ // the other Logger, then it is possible for the other ++ // Logger to be GC'ed after we saw it in addLogger() and ++ // before we can refetch it. If it has been GC'ed then ++ // we'll just loop around and try again. ++ result = getLogger(name); ++ } while (result == null); ++ } ++ return result; ++ } ++ ++ Logger demandSystemLogger(String name, String resourceBundleName) { ++ return systemContext.demandLogger(name, resourceBundleName); ++ } ++ ++ // LoggerContext maintains the logger namespace per context. ++ // The default LogManager implementation has one system context and user ++ // context. The system context is used to maintain the namespace for ++ // all system loggers and is queried by the system code. If a system logger ++ // doesn't exist in the user context, it'll also be added to the user context. ++ // The user context is queried by the user code and all other loggers are ++ // added in the user context. + static class LoggerContext { + // Table of named Loggers that maps names to Loggers. + private final Hashtable namedLoggers = new Hashtable<>(); +@@ -395,6 +443,12 @@ + this.root = new LogNode(null, this); + } + ++ Logger demandLogger(String name, String resourceBundleName) { ++ // a LogManager subclass may have its own implementation to add and ++ // get a Logger. So delegate to the LogManager to do the work. ++ return manager.demandLogger(name, resourceBundleName); ++ } ++ + synchronized Logger findLogger(String name) { + LoggerWeakRef ref = namedLoggers.get(name); + if (ref == null) { +@@ -409,7 +463,9 @@ + return logger; + } + +- synchronized boolean addLogger(Logger logger) { ++ // Add a logger to this context. This method will only set its level ++ // and process parent loggers. It doesn't set its handlers. ++ synchronized boolean addLocalLogger(Logger logger) { + final String name = logger.getName(); + if (name == null) { + throw new NullPointerException(); +@@ -442,9 +498,6 @@ + doSetLevel(logger, level); + } + +- // Do we have a per logger handler too? +- // Note: this will add a 200ms penalty +- manager.loadLoggerHandlers(logger, name, name + ".handlers"); + processParentHandlers(logger, name); + + // Find the new node and its parent. +@@ -481,50 +534,21 @@ + return namedLoggers.keys(); + } + +- Logger demandLogger(String name) { +- return demandLogger(name, null); +- } +- +- // Find or create a specified logger instance. If a logger has +- // already been created with the given name it is returned. +- // Otherwise a new logger instance is created and registered +- // in the LogManager global namespace. +- +- // This method will always return a non-null Logger object. +- // Synchronization is not required here. All synchronization for +- // adding a new Logger object is handled by addLogger(). +- Logger demandLogger(String name, String resourceBundleName) { +- Logger result = findLogger(name); +- if (result == null) { +- // only allocate the new logger once +- Logger newLogger = new Logger(name, resourceBundleName); +- do { +- if (addLogger(newLogger)) { +- // We successfully added the new Logger that we +- // created above so return it without refetching. +- return newLogger; +- } +- +- // We didn't add the new Logger that we created above +- // because another thread added a Logger with the same +- // name after our null check above and before our call +- // to addLogger(). We have to refetch the Logger because +- // addLogger() returns a boolean instead of the Logger +- // reference itself. However, if the thread that created +- // the other Logger is not holding a strong reference to +- // the other Logger, then it is possible for the other +- // Logger to be GC'ed after we saw it in addLogger() and +- // before we can refetch it. If it has been GC'ed then +- // we'll just loop around and try again. +- result = findLogger(name); +- } while (result == null); +- } +- return result; +- } +- + // If logger.getUseParentHandlers() returns 'true' and any of the logger's + // parents have levels or handlers defined, make sure they are instantiated. +- private void processParentHandlers(Logger logger, String name) { ++ private void processParentHandlers(final Logger logger, final String name) { ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ if (logger != manager.rootLogger) { ++ boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true); ++ if (!useParent) { ++ logger.setUseParentHandlers(false); ++ } ++ } ++ return null; ++ } ++ }); ++ + int ix = 1; + for (;;) { + int ix2 = name.indexOf(".", ix); +@@ -537,9 +561,9 @@ + manager.getProperty(pname + ".handlers") != null) { + // This pname has a level/handlers definition. + // Make sure it exists. +- demandLogger(pname); ++ demandLogger(pname, null); + } +- ix = ix2+1; ++ ix = ix2 + 1; + } + } + +@@ -575,54 +599,52 @@ + } + + static class SystemLoggerContext extends LoggerContext { +- // Default resource bundle for all system loggers +- Logger demandLogger(String name) { +- // default to use the system logger's resource bundle +- return super.demandLogger(name, Logger.SYSTEM_LOGGER_RB_NAME); +- } +- } +- +- static class UserLoggerContext extends LoggerContext { +- /** +- * Returns a Logger of the given name if there is one registered +- * in this context. Otherwise, it will return the one registered +- * in the system context if there is one. The returned Logger +- * instance may be initialized with a different resourceBundleName. +- * If no such logger exists, a new Logger instance will be created +- * and registered in this context. +- */ ++ // Add a system logger in the system context's namespace as well as ++ // in the LogManager's namespace if not exist so that there is only ++ // one single logger of the given name. System loggers are visible ++ // to applications unless a logger of the same name has been added. + Logger demandLogger(String name, String resourceBundleName) { + Logger result = findLogger(name); + if (result == null) { +- // use the system logger if exists; or allocate a new logger. +- // The system logger is added to the app logger context so that +- // any child logger created in the app logger context can have +- // a system logger as its parent if already exist. +- Logger logger = manager.systemContext.findLogger(name); +- Logger newLogger = +- logger != null ? logger : new Logger(name, resourceBundleName); ++ // only allocate the new system logger once ++ Logger newLogger = new Logger(name, resourceBundleName); + do { +- if (addLogger(newLogger)) { ++ if (addLocalLogger(newLogger)) { + // We successfully added the new Logger that we + // created above so return it without refetching. +- return newLogger; ++ result = newLogger; ++ } else { ++ // We didn't add the new Logger that we created above ++ // because another thread added a Logger with the same ++ // name after our null check above and before our call ++ // to addLogger(). We have to refetch the Logger because ++ // addLogger() returns a boolean instead of the Logger ++ // reference itself. However, if the thread that created ++ // the other Logger is not holding a strong reference to ++ // the other Logger, then it is possible for the other ++ // Logger to be GC'ed after we saw it in addLogger() and ++ // before we can refetch it. If it has been GC'ed then ++ // we'll just loop around and try again. ++ result = findLogger(name); + } +- +- // We didn't add the new Logger that we created above +- // because another thread added a Logger with the same +- // name after our null check above and before our call +- // to addLogger(). We have to refetch the Logger because +- // addLogger() returns a boolean instead of the Logger +- // reference itself. However, if the thread that created +- // the other Logger is not holding a strong reference to +- // the other Logger, then it is possible for the other +- // Logger to be GC'ed after we saw it in addLogger() and +- // before we can refetch it. If it has been GC'ed then +- // we'll just loop around and try again. +- result = findLogger(name); + } while (result == null); + } +- return result; ++ // Add the system logger to the LogManager's namespace if not exists ++ // The LogManager will set its handlers via the LogManager.addLogger method. ++ if (!manager.addLogger(result) && result.getHandlers().length == 0) { ++ // if logger already exists but handlers not set ++ final Logger l = manager.getLogger(name); ++ final Logger logger = result; ++ AccessController.doPrivileged(new PrivilegedAction() { ++ public Void run() { ++ for (Handler hdl : l.getHandlers()) { ++ logger.addHandler(hdl); ++ } ++ return null; ++ } ++ }); ++ } ++ return result; + } + } + +@@ -634,12 +656,6 @@ + final String handlersPropertyName) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { +- if (logger != rootLogger) { +- boolean useParent = getBooleanProperty(name + ".useParentHandlers", true); +- if (!useParent) { +- logger.setUseParentHandlers(false); +- } +- } + + String names[] = parseClassNames(handlersPropertyName); + for (int i = 0; i < names.length; i++) { +@@ -668,7 +684,8 @@ + } + } + return null; +- }}); ++ } ++ }); + } + + +@@ -802,15 +819,20 @@ + * false if a logger of that name already exists. + * @exception NullPointerException if the logger name is null. + */ +- public boolean addLogger(Logger logger) { ++ public synchronized boolean addLogger(Logger logger) { + final String name = logger.getName(); + if (name == null) { + throw new NullPointerException(); + } +- if (systemContext.findLogger(name) != null) { ++ LoggerContext cx = getUserContext(); ++ if (cx.addLocalLogger(logger)) { ++ // Do we have a per logger handler too? ++ // Note: this will add a 200ms penalty ++ loadLoggerHandlers(logger, name, name + ".handlers"); ++ return true; ++ } else { + return false; + } +- return getUserContext().addLogger(logger); + } + + +@@ -868,15 +890,7 @@ + * @return matching logger or null if none is found + */ + public Logger getLogger(String name) { +- // return the first logger added +- // +- // once a system logger is added in the system context, no one can +- // adds a logger with the same name in the global context +- // (see LogManager.addLogger). So if there is a logger in the global +- // context with the same name as one in the system context, it must be +- // added before the system logger was created. +- Logger logger = getUserContext().findLogger(name); +- return logger != null ? logger : systemContext.findLogger(name); ++ return getUserContext().findLogger(name); + } + + /** +@@ -896,10 +910,7 @@ + * @return enumeration of logger name strings + */ + public Enumeration getLoggerNames() { +- // only return unique names +- Set names = new HashSet<>(Collections.list(systemContext.getLoggerNames())); +- names.addAll(Collections.list(getUserContext().getLoggerNames())); +- return Collections.enumeration(names); ++ return getUserContext().getLoggerNames(); + } + + /** +diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java +--- a/src/share/classes/java/util/logging/Logger.java ++++ b/src/share/classes/java/util/logging/Logger.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2000, 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 +@@ -30,7 +30,6 @@ + import java.util.concurrent.CopyOnWriteArrayList; + import java.security.*; + import java.lang.ref.WeakReference; +-import java.util.logging.LogManager.LoggerContext; + + /** + * A Logger object is used to log messages for a specific +@@ -70,7 +69,7 @@ + * effective level from its parent. + *

    + * On each logging call the Logger initially performs a cheap +- * check of the request level (e.g., SEVERE or FINE) against the ++ * check of the request level (e.g. SEVERE or FINE) against the + * effective log level of the logger. If the request level is + * lower than the log level, the logging call returns immediately. + *

    +@@ -290,18 +289,32 @@ + // + // As an interim solution, if the immediate caller whose caller loader is + // null, we assume it's a system logger and add it to the system context. +- private static LoggerContext getLoggerContext() { ++ // These system loggers only set the resource bundle to the given ++ // resource bundle name (rather than the default system resource bundle). ++ private static class SystemLoggerHelper { ++ static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); ++ private static boolean getBooleanProperty(final String key) { ++ String s = AccessController.doPrivileged(new PrivilegedAction() { ++ public String run() { ++ return System.getProperty(key); ++ } ++ }); ++ return Boolean.valueOf(s); ++ } ++ } ++ ++ private static Logger demandLogger(String name, String resourceBundleName) { + LogManager manager = LogManager.getLogManager(); + SecurityManager sm = System.getSecurityManager(); +- if (sm != null) { ++ if (sm != null && !SystemLoggerHelper.disableCallerCheck) { + // 0: Reflection 1: Logger.getLoggerContext 2: Logger.getLogger 3: caller + final int SKIP_FRAMES = 3; + Class caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES); + if (caller.getClassLoader() == null) { +- return manager.getSystemContext(); ++ return manager.demandSystemLogger(name, resourceBundleName); + } + } +- return manager.getUserContext(); ++ return manager.demandLogger(name, resourceBundleName); + } + + /** +@@ -331,22 +344,8 @@ + * @return a suitable Logger + * @throws NullPointerException if the name is null. + */ +- +- // Synchronization is not required here. All synchronization for +- // adding a new Logger object is handled by LogManager.addLogger(). +- public static Logger getLogger(String name) { +- // This method is intentionally not a wrapper around a call +- // to getLogger(name, resourceBundleName). If it were then +- // this sequence: +- // +- // getLogger("Foo", "resourceBundleForFoo"); +- // getLogger("Foo"); +- // +- // would throw an IllegalArgumentException in the second call +- // because the wrapper would result in an attempt to replace +- // the existing "resourceBundleForFoo" with null. +- LoggerContext context = getLoggerContext(); +- return context.demandLogger(name); ++ public static synchronized Logger getLogger(String name) { ++ return demandLogger(name, null); + } + + /** +@@ -389,12 +388,8 @@ + * a different resource bundle name. + * @throws NullPointerException if the name is null. + */ +- +- // Synchronization is not required here. All synchronization for +- // adding a new Logger object is handled by LogManager.addLogger(). +- public static Logger getLogger(String name, String resourceBundleName) { +- LoggerContext context = getLoggerContext(); +- Logger result = context.demandLogger(name, resourceBundleName); ++ public static synchronized Logger getLogger(String name, String resourceBundleName) { ++ Logger result = demandLogger(name, resourceBundleName); + if (result.resourceBundleName == null) { + // Note: we may get a MissingResourceException here. + result.setupResourceInfo(resourceBundleName); +@@ -410,12 +405,7 @@ + // i.e. caller of sun.util.logging.PlatformLogger.getLogger + static Logger getPlatformLogger(String name) { + LogManager manager = LogManager.getLogManager(); +- LoggerContext context = manager.getSystemContext(); +- +- // all loggers in the system context will default to +- // the system logger's resource bundle +- Logger result = context.demandLogger(name); +- return result; ++ return manager.demandSystemLogger(name, null); + } + + /** +@@ -588,7 +578,7 @@ + * level then the given message is forwarded to all the + * registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + */ + public void log(Level level, String msg) { +@@ -606,7 +596,7 @@ + * level then a corresponding LogRecord is created and forwarded + * to all the registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + * @param param1 parameter to the message + */ +@@ -627,7 +617,7 @@ + * level then a corresponding LogRecord is created and forwarded + * to all the registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + * @param params array of parameters to the message + */ +@@ -652,7 +642,7 @@ + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param msg The string message (or a key in the message catalog) + * @param thrown Throwable associated with log message. + */ +@@ -677,7 +667,7 @@ + * level then the given message is forwarded to all the + * registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param msg The string message (or a key in the message catalog) +@@ -700,7 +690,7 @@ + * level then a corresponding LogRecord is created and forwarded + * to all the registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param msg The string message (or a key in the message catalog) +@@ -727,7 +717,7 @@ + * level then a corresponding LogRecord is created and forwarded + * to all the registered output Handler objects. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param msg The string message (or a key in the message catalog) +@@ -758,7 +748,7 @@ + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param msg The string message (or a key in the message catalog) +@@ -805,7 +795,7 @@ + * resource bundle name is null, or an empty String or invalid + * then the msg string is not localized. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param bundleName name of resource bundle to localize msg, +@@ -836,7 +826,7 @@ + * resource bundle name is null, or an empty String or invalid + * then the msg string is not localized. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param bundleName name of resource bundle to localize msg, +@@ -869,7 +859,7 @@ + * resource bundle name is null, or an empty String or invalid + * then the msg string is not localized. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param bundleName name of resource bundle to localize msg, +@@ -906,7 +896,7 @@ + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    +- * @param level One of the message level identifiers, e.g., SEVERE ++ * @param level One of the message level identifiers, e.g. SEVERE + * @param sourceClass name of class that issued the logging request + * @param sourceMethod name of method that issued the logging request + * @param bundleName name of resource bundle to localize msg, +@@ -1326,7 +1316,8 @@ + public ResourceBundle run() { + try { + return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, +- locale); ++ locale, ++ ClassLoader.getSystemClassLoader()); + } catch (MissingResourceException e) { + throw new InternalError(e.toString()); + }