From 3d9f33759d5c2e1d6e6d8438d8ae78416bfac086 Mon Sep 17 00:00:00 2001 From: Masayoshi Okutsu Date: Fri, 19 Jul 2013 12:14:34 +0900 Subject: [PATCH] 8001029: Add new date/time capability Reviewed-by: mchung, hawtin --- jdk/src/share/classes/java/util/TimeZone.java | 140 +++++------------- .../util/TimeZone/SetDefaultSecurityTest.java | 67 +++++++++ 2 files changed, 107 insertions(+), 100 deletions(-) create mode 100644 jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java diff --git a/jdk/src/share/classes/java/util/TimeZone.java b/jdk/src/share/classes/java/util/TimeZone.java index ba4abb91f2c..3075bff157a 100644 --- a/jdk/src/share/classes/java/util/TimeZone.java +++ b/jdk/src/share/classes/java/util/TimeZone.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -39,13 +39,9 @@ package java.util; import java.io.Serializable; -import java.lang.ref.SoftReference; import java.security.AccessController; import java.security.PrivilegedAction; import java.time.ZoneId; -import java.util.concurrent.ConcurrentHashMap; -import sun.misc.JavaAWTAccess; -import sun.misc.SharedSecrets; import sun.security.action.GetPropertyAction; import sun.util.calendar.ZoneInfo; import sun.util.calendar.ZoneInfoFile; @@ -596,11 +592,26 @@ abstract public class TimeZone implements Serializable, Cloneable { private static native String getSystemGMTOffsetID(); /** - * Gets the default TimeZone for this host. - * The source of the default TimeZone - * may vary with implementation. - * @return a default TimeZone. - * @see #setDefault + * Gets the default {@code TimeZone} of the Java virtual machine. If the + * cached default {@code TimeZone} is available, its clone is returned. + * Otherwise, the method takes the following steps to determine the default + * time zone. + * + *

+ * + *

The default {@code TimeZone} created from the ID is cached, + * and its clone is returned. The {@code user.timezone} property + * value is set to the ID upon return. + * + * @return the default {@code TimeZone} + * @see #setDefault(TimeZone) */ public static TimeZone getDefault() { return (TimeZone) getDefaultRef().clone(); @@ -611,14 +622,11 @@ abstract public class TimeZone implements Serializable, Cloneable { * method doesn't create a clone. */ static TimeZone getDefaultRef() { - TimeZone defaultZone = getDefaultInAppContext(); + TimeZone defaultZone = defaultTimeZone; if (defaultZone == null) { - defaultZone = defaultTimeZone; - if (defaultZone == null) { - // Need to initialize the default time zone. - defaultZone = setDefaultZone(); - assert defaultZone != null; - } + // Need to initialize the default time zone. + defaultZone = setDefaultZone(); + assert defaultZone != null; } // Don't clone here. return defaultZone; @@ -676,95 +684,27 @@ abstract public class TimeZone implements Serializable, Cloneable { return tz; } - private static boolean hasPermission() { - boolean hasPermission = true; - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPermission(new PropertyPermission - ("user.timezone", "write")); - } catch (SecurityException e) { - hasPermission = false; - } - } - return hasPermission; - } - /** - * Sets the TimeZone that is - * returned by the getDefault method. If zone - * is null, reset the default to the value it had originally when the - * VM first started. - * @param zone the new default time zone + * Sets the {@code TimeZone} that is returned by the {@code getDefault} + * method. {@code zone} is cached. If {@code zone} is null, the cached + * default {@code TimeZone} is cleared. This method doesn't change the value + * of the {@code user.timezone} property. + * + * @param zone the new default {@code TimeZone}, or null + * @throws SecurityException if the security manager's {@code checkPermission} + * denies {@code PropertyPermission("user.timezone", + * "write")} * @see #getDefault + * @see PropertyPermission */ public static void setDefault(TimeZone zone) { - if (hasPermission()) { - synchronized (TimeZone.class) { - defaultTimeZone = zone; - setDefaultInAppContext(null); - } - } else { - 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. - * - * 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. - */ - private static TimeZone getDefaultInAppContext() { - // JavaAWTAccess provides access implementation-private methods without using reflection. - JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - - 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. - * - * 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. - */ - private static void setDefaultInAppContext(TimeZone tz) { - // JavaAWTAccess provides access implementation-private methods without using reflection. - JavaAWTAccess javaAWTAccess = SharedSecrets.getJavaAWTAccess(); - - if (javaAWTAccess == null) { - mainAppContextDefault = tz; - } else { - if (!javaAWTAccess.isDisposed()) { - javaAWTAccess.put(TimeZone.class, tz); - if (javaAWTAccess.isMainAppContext()) { - mainAppContextDefault = null; - } - } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new PropertyPermission + ("user.timezone", "write")); } + defaultTimeZone = zone; } /** diff --git a/jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java b/jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java new file mode 100644 index 00000000000..e749ffe9420 --- /dev/null +++ b/jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java @@ -0,0 +1,67 @@ +/* + * 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. 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. + */ + +/* + * @test + * @bug 8001029 + * @summary Make sure that TimeZone.setDefault throws a SecurityException if the + * security manager doesn't permit. + * @run main/othervm SetDefaultSecurityTest + */ + +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +public class SetDefaultSecurityTest { + static final TimeZone NOWHERE = new SimpleTimeZone(Integer.MAX_VALUE, "Nowhere"); + + public static void main(String[] args) { + TimeZone defaultZone = TimeZone.getDefault(); + + // Make sure that TimeZone.setDefault works for trusted code + TimeZone.setDefault(NOWHERE); + if (!NOWHERE.equals(TimeZone.getDefault())) { + new RuntimeException("TimeZone.setDefault doesn't work for trusted code."); + } + // Restore defaultZone + TimeZone.setDefault(defaultZone); + if (!defaultZone.equals(TimeZone.getDefault())) { + new RuntimeException("TimeZone.setDefault doesn't restore defaultZone."); + } + + // Install a SecurityManager. + System.setSecurityManager(new SecurityManager()); + try { + TimeZone.setDefault(NOWHERE); + throw new RuntimeException("TimeZone.setDefault doesn't throw a SecurityException."); + } catch (SecurityException se) { + // OK + } + TimeZone tz = TimeZone.getDefault(); + if (!defaultZone.equals(tz)) { + throw new RuntimeException("Default TimeZone changed: " + tz); + } + } +}