diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index 58c763a3fe5..4ece926849d 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -475,6 +475,7 @@ JAVA_JAVA_java = \ sun/misc/MessageUtils.java \ sun/misc/GC.java \ sun/misc/Service.java \ + sun/misc/JavaAWTAccess.java \ sun/misc/JavaLangAccess.java \ sun/misc/JavaIOAccess.java \ sun/misc/JavaIOFileDescriptorAccess.java \ diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index 266f627d7e2..a7132436b4c 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -43,6 +43,8 @@ import java.lang.ref.SoftReference; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.ConcurrentHashMap; +import sun.misc.SharedSecrets; +import sun.misc.JavaAWTAccess; import sun.security.action.GetPropertyAction; import sun.util.TimeZoneNameUtility; import sun.util.calendar.ZoneInfo; @@ -615,7 +617,7 @@ abstract public class TimeZone implements Serializable, Cloneable { * method doesn't create a clone. */ static TimeZone getDefaultRef() { - TimeZone defaultZone = defaultZoneTL.get(); + TimeZone defaultZone = getDefaultInAppContext(); if (defaultZone == null) { defaultZone = defaultTimeZone; if (defaultZone == null) { @@ -706,10 +708,65 @@ abstract public class TimeZone implements Serializable, Cloneable { if (hasPermission()) { synchronized (TimeZone.class) { defaultTimeZone = zone; - defaultZoneTL.set(null); + setDefaultInAppContext(null); } } else { - defaultZoneTL.set(zone); + setDefaultInAppContext(zone); + } + } + + /** + * Returns the default TimeZone in an AppContext if any AppContext + * has ever used. null is returned if any AppContext hasn't been + * used or if the AppContext doesn't have the default TimeZone. + */ + private synchronized static TimeZone getDefaultInAppContext() { + // JavaAWTAccess provides access implementation-private methods without using reflection. + JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); + + // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't + // been loaded. If so, it implies that AWTSecurityManager is not our + // SecurityManager and we can use a local static variable. + // This works around a build time issue. + if (javaAWTAccess == null) { + return mainAppContextDefault; + } else { + if (!javaAWTAccess.isDisposed()) { + TimeZone tz = (TimeZone) + javaAWTAccess.get(TimeZone.class); + if (tz == null && javaAWTAccess.isMainAppContext()) { + return mainAppContextDefault; + } else { + return tz; + } + } + } + return null; + } + + /** + * Sets the default TimeZone in the AppContext to the given + * tz. null is handled special: do nothing if any AppContext + * hasn't been used, remove the default TimeZone in the + * AppContext otherwise. + */ + private synchronized static void setDefaultInAppContext(TimeZone tz) { + // JavaAWTAccess provides access implementation-private methods without using reflection. + JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); + + // Note that javaAWTAccess may be null if sun.awt.AppContext class hasn't + // been loaded. If so, it implies that AWTSecurityManager is not our + // SecurityManager and we can use a local static variable. + // This works around a build time issue. + if (javaAWTAccess == null) { + mainAppContextDefault = tz; + } else { + if (!javaAWTAccess.isDisposed()) { + javaAWTAccess.put(TimeZone.class, tz); + if (javaAWTAccess.isMainAppContext()) { + mainAppContextDefault = null; + } + } } } @@ -760,12 +817,13 @@ abstract public class TimeZone implements Serializable, Cloneable { */ private String ID; private static volatile TimeZone defaultTimeZone; - private static final InheritableThreadLocal defaultZoneTL - = new InheritableThreadLocal(); static final String GMT_ID = "GMT"; private static final int GMT_ID_LENGTH = 3; + // a static TimeZone we can reference if no AppContext is in place + private static TimeZone mainAppContextDefault; + /** * Parses a custom time zone identifier and returns a corresponding zone. * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm) diff --git a/jdk/src/share/classes/sun/awt/AppContext.java b/jdk/src/share/classes/sun/awt/AppContext.java index e4b60a283d3..303d79345ca 100644 --- a/jdk/src/share/classes/sun/awt/AppContext.java +++ b/jdk/src/share/classes/sun/awt/AppContext.java @@ -777,6 +777,27 @@ public final class AppContext { } return changeSupport.getPropertyChangeListeners(propertyName); } + + // Set up JavaAWTAccess in SharedSecrets + static { + sun.misc.SharedSecrets.setJavaAWTAccess(new sun.misc.JavaAWTAccess() { + public Object get(Object key) { + return getAppContext().get(key); + } + public void put(Object key, Object value) { + getAppContext().put(key, value); + } + public void remove(Object key) { + getAppContext().remove(key); + } + public boolean isDisposed() { + return getAppContext().isDisposed(); + } + public boolean isMainAppContext() { + return (numAppContexts == 1); + } + }); + } } final class MostRecentKeyValue { diff --git a/jdk/src/share/classes/sun/misc/JavaAWTAccess.java b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java new file mode 100644 index 00000000000..6e3712592ce --- /dev/null +++ b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.misc; + +public interface JavaAWTAccess { + public Object get(Object key); + public void put(Object key, Object value); + public void remove(Object key); + public boolean isDisposed(); + public boolean isMainAppContext(); +} diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java index 0bd39b4a5d4..52c48e3d17e 100644 --- a/jdk/src/share/classes/sun/misc/SharedSecrets.java +++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java @@ -51,6 +51,7 @@ public class SharedSecrets { private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess; private static JavaSecurityAccess javaSecurityAccess; + private static JavaAWTAccess javaAWTAccess; public static JavaUtilJarAccess javaUtilJarAccess() { if (javaUtilJarAccess == null) { @@ -139,4 +140,14 @@ public class SharedSecrets { } return javaSecurityAccess; } + + public static void setJavaAWTAccess(JavaAWTAccess jaa) { + javaAWTAccess = jaa; + } + + public static JavaAWTAccess getJavaAWTAccess() { + // this may return null in which case calling code needs to + // provision for. + return javaAWTAccess; + } }