8001029: Add new date/time capability
authorokutsu
Fri, 19 Jul 2013 12:14:34 +0900
changeset 20822 2552851d9562
parent 20821 e0d0a585aa49
child 20823 ddd111318407
8001029: Add new date/time capability Reviewed-by: mchung, hawtin
jdk/src/share/classes/java/util/TimeZone.java
jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java
--- a/jdk/src/share/classes/java/util/TimeZone.java	Thu Jul 18 18:52:14 2013 +0100
+++ b/jdk/src/share/classes/java/util/TimeZone.java	Fri Jul 19 12:14:34 2013 +0900
@@ -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 @@
     private static native String getSystemGMTOffsetID();
 
     /**
-     * Gets the default <code>TimeZone</code> for this host.
-     * The source of the default <code>TimeZone</code>
-     * may vary with implementation.
-     * @return a default <code>TimeZone</code>.
-     * @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.
+     *
+     * <p><ul>
+     * <li>Use the {@code user.timezone} property value as the default
+     * time zone ID if it's available.</li>
+     * <li>Detect the platform time zone ID. The source of the
+     * platform time zone and ID mapping may vary with implementation.</li>
+     * <li>Use {@code GMT} as the last resort if the given or detected
+     * time zone ID is unknown.</li>
+     * </ul>
+     *
+     * <p>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 @@
      * 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 @@
         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 <code>TimeZone</code> that is
-     * returned by the <code>getDefault</code> method.  If <code>zone</code>
-     * 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);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission
+                               ("user.timezone", "write"));
         }
-    }
-
-    /**
-     * 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;
-                }
-            }
-        }
+        defaultTimeZone = zone;
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/TimeZone/SetDefaultSecurityTest.java	Fri Jul 19 12:14:34 2013 +0900
@@ -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);
+        }
+    }
+}