From ed15f54cfbc4535041f799d2b15770057fc7962c Mon Sep 17 00:00:00 2001 From: Yuka Kamiya Date: Wed, 21 Apr 2010 10:34:56 +0900 Subject: [PATCH 01/23] 6943963: NumericShaper with ARABIC doesn't shape digits correctly after calling another instance Reviewed-by: okutsu --- .../classes/java/awt/font/NumericShaper.java | 8 +- .../java/awt/font/NumericShaper/MTTest.java | 51 +++++---- .../awt/font/NumericShaper/ShapingTest.java | 107 +++++++++++------- 3 files changed, 100 insertions(+), 66 deletions(-) diff --git a/jdk/src/share/classes/java/awt/font/NumericShaper.java b/jdk/src/share/classes/java/awt/font/NumericShaper.java index 75f4dbad751..6aff9cba920 100644 --- a/jdk/src/share/classes/java/awt/font/NumericShaper.java +++ b/jdk/src/share/classes/java/awt/font/NumericShaper.java @@ -1163,8 +1163,14 @@ public final class NumericShaper implements java.io.Serializable { lastkey = newkey; ctxKey = newkey; - if (((mask & EASTERN_ARABIC) != 0) && (ctxKey == ARABIC_KEY || ctxKey == EASTERN_ARABIC_KEY)) { + if (((mask & EASTERN_ARABIC) != 0) && + (ctxKey == ARABIC_KEY || + ctxKey == EASTERN_ARABIC_KEY)) { ctxKey = EASTERN_ARABIC_KEY; + } else if (((mask & ARABIC) != 0) && + (ctxKey == ARABIC_KEY || + ctxKey == EASTERN_ARABIC_KEY)) { + ctxKey = ARABIC_KEY; } else if ((mask & (1<."); + System.err.println(" text = " + given); + System.err.println(" got = " + got); + System.err.println(" expected = " + expected); + } else { + System.out.println("OK with range(s) <" + ranges + ">."); + System.out.println(" text = " + given); + System.out.println(" got = " + got); + System.out.println(" expected = " + expected); } } From f05dd156c2cb16c6c78ccdced90a625f11119c46 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Wed, 21 Apr 2010 18:12:21 +0400 Subject: [PATCH 02/23] 6945316: The Win32ShellFolderManager2.isFileSystemRoot can throw NPE Reviewed-by: alexp --- .../awt/shell/Win32ShellFolderManager2.java | 11 ++- .../JFileChooser/6945316/bug6945316.java | 74 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/6945316/bug6945316.java diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index b7639fa77bb..1a53198349f 100644 --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -403,9 +403,14 @@ public class Win32ShellFolderManager2 extends ShellFolderManager { } } String path = dir.getPath(); - return (path.length() == 3 - && path.charAt(1) == ':' - && Arrays.asList(drives.listFiles()).contains(dir)); + + if (path.length() != 3 || path.charAt(1) != ':') { + return false; + } + + File[] files = drives.listFiles(); + + return files != null && Arrays.asList(files).contains(dir); } return false; } diff --git a/jdk/test/javax/swing/JFileChooser/6945316/bug6945316.java b/jdk/test/javax/swing/JFileChooser/6945316/bug6945316.java new file mode 100644 index 00000000000..cc495f7a6db --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/6945316/bug6945316.java @@ -0,0 +1,74 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6945316 + @summary The Win32ShellFolderManager2.isFileSystemRoot can throw NPE + @author Pavel Porvatov + @run main bug6945316 +*/ + +import sun.awt.OSInfo; +import sun.awt.shell.ShellFolder; + +import java.awt.*; +import java.io.File; +import java.util.concurrent.CountDownLatch; + +public class bug6945316 { + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("The test is suitable only for Windows OS. Skipped."); + + return; + } + + // Init toolkit because it shouldn't be interrupted while initialization + Toolkit.getDefaultToolkit(); + + // Init the sun.awt.shell.Win32ShellFolderManager2.drives field + ShellFolder.get("fileChooserComboBoxFolders"); + + // To get NPE the path must obey the following rules: + // path.length() == 3 && path.charAt(1) == ':' + final File tempFile = new File("c:\\"); + + for (int i = 0; i < 10000; i++) { + final CountDownLatch countDownLatch = new CountDownLatch(1); + + final Thread thread = new Thread() { + public void run() { + countDownLatch.countDown(); + + ShellFolder.isFileSystemRoot(tempFile); + } + }; + + thread.start(); + + countDownLatch.await(); + + thread.interrupt(); + } + } +} From 7cc72590c763920d35e8646ec04d00795fd16d0b Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 22 Apr 2010 12:45:36 +0800 Subject: [PATCH 03/23] 6856069: PrincipalName.clone() does not invoke super.clone() Reviewed-by: chegar --- .../sun/security/krb5/PrincipalName.java | 27 ++++++------ .../sun/security/krb5/ServiceNameClone.java | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+), 13 deletions(-) create mode 100644 jdk/test/sun/security/krb5/ServiceNameClone.java diff --git a/jdk/src/share/classes/sun/security/krb5/PrincipalName.java b/jdk/src/share/classes/sun/security/krb5/PrincipalName.java index 6705fd63e9a..91d5d8bb395 100644 --- a/jdk/src/share/classes/sun/security/krb5/PrincipalName.java +++ b/jdk/src/share/classes/sun/security/krb5/PrincipalName.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -101,7 +101,7 @@ public class PrincipalName private Realm nameRealm; // optional; a null realm means use default // Note: the nameRealm is not included in the default ASN.1 encoding - // salt for principal + // cached salt, might be changed by KDC info, not used in clone private String salt = null; protected PrincipalName() { @@ -123,18 +123,19 @@ public class PrincipalName } public Object clone() { - PrincipalName pName = new PrincipalName(); - pName.nameType = nameType; - if (nameStrings != null) { - pName.nameStrings = - new String[nameStrings.length]; - System.arraycopy(nameStrings,0,pName.nameStrings,0, - nameStrings.length); + try { + PrincipalName pName = (PrincipalName) super.clone(); + // Re-assign mutable fields + if (nameStrings != null) { + pName.nameStrings = nameStrings.clone(); + } + if (nameRealm != null) { + pName.nameRealm = (Realm)nameRealm.clone(); + } + return pName; + } catch (CloneNotSupportedException ex) { + throw new AssertionError("Should never happen"); } - if (nameRealm != null) { - pName.nameRealm = (Realm)nameRealm.clone(); - } - return pName; } /* diff --git a/jdk/test/sun/security/krb5/ServiceNameClone.java b/jdk/test/sun/security/krb5/ServiceNameClone.java new file mode 100644 index 00000000000..282712c032a --- /dev/null +++ b/jdk/test/sun/security/krb5/ServiceNameClone.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +/* + * @test + * @bug 6856069 + * @summary PrincipalName.clone() does not invoke super.clone() + */ + +import sun.security.krb5.ServiceName; + +public class ServiceNameClone { + public static void main(String[] args) throws Exception { + ServiceName sn = new ServiceName("me@HERE"); + if (sn.clone().getClass() != ServiceName.class) { + throw new Exception("ServiceName's clone is not a ServiceName"); + } + if (!sn.clone().equals(sn)) { + throw new Exception("ServiceName's clone changed"); + } + } +} From 77a56e5d33e82d4128ac36861c3704223821f888 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 27 Apr 2010 09:42:51 +0100 Subject: [PATCH 04/23] 6718504: IN6_IS_ADDR_ANY tests only 12 bytes of 16-byte address Reviewed-by: alanb --- jdk/src/windows/native/java/net/net_util_md.h | 3 +- .../DatagramSocket/LocalSocketAddress.java | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/net/DatagramSocket/LocalSocketAddress.java diff --git a/jdk/src/windows/native/java/net/net_util_md.h b/jdk/src/windows/native/java/net/net_util_md.h index 23574f1725f..679fbfc08d4 100644 --- a/jdk/src/windows/native/java/net/net_util_md.h +++ b/jdk/src/windows/native/java/net/net_util_md.h @@ -222,7 +222,8 @@ LPFN_GETNAMEINFO getnameinfo_ptr; #define IN6_IS_ADDR_ANY(a) \ (((a)->s6_words[0] == 0) && ((a)->s6_words[1] == 0) && \ ((a)->s6_words[2] == 0) && ((a)->s6_words[3] == 0) && \ - ((a)->s6_words[4] == 0) && ((a)->s6_words[5] == 0)) + ((a)->s6_words[4] == 0) && ((a)->s6_words[5] == 0) && \ + ((a)->s6_words[6] == 0) && ((a)->s6_words[7] == 0)) #endif #ifndef IPV6_V6ONLY diff --git a/jdk/test/java/net/DatagramSocket/LocalSocketAddress.java b/jdk/test/java/net/DatagramSocket/LocalSocketAddress.java new file mode 100644 index 00000000000..bf20cf17283 --- /dev/null +++ b/jdk/test/java/net/DatagramSocket/LocalSocketAddress.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6718504 + * @summary IN6_IS_ADDR_ANY tests only 12 bytes of 16-byte address + */ + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Inet6Address; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.*; + +public class LocalSocketAddress { + public static void main(String[] args) throws SocketException { + InetAddress IPv6LoopbackAddr = null; + DatagramSocket soc = null; + + try { + List nics = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface nic : nics) { + if (!nic.isLoopback()) + continue; + + List addrs = Collections.list(nic.getInetAddresses()); + for (InetAddress addr : addrs) { + if (addr instanceof Inet6Address) { + IPv6LoopbackAddr = addr; + break; + } + } + } + + if (IPv6LoopbackAddr == null) { + System.out.println("IPv6 is not available, exiting test."); + return; + } + + soc = new DatagramSocket(0, IPv6LoopbackAddr); + + if (!IPv6LoopbackAddr.equals(soc.getLocalAddress())) { + throw new RuntimeException("Bound address is " + soc.getLocalAddress() + + ", but should be " + IPv6LoopbackAddr); + } + } finally { + if (soc != null) { soc.close(); } + } + } +} From d052130c49573b0212a3cf1250284a7e6e6f605c Mon Sep 17 00:00:00 2001 From: Artem Ananiev Date: Tue, 27 Apr 2010 18:08:26 +0400 Subject: [PATCH 05/23] 6880336: SwingWorker deadlocks due one thread in the swingworker-pool Reviewed-by: dcherepanov, alexp --- .../classes/javax/swing/SwingWorker.java | 11 +-- .../SwingWorker/6880336/NestedWorkers.java | 72 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 jdk/test/javax/swing/SwingWorker/6880336/NestedWorkers.java diff --git a/jdk/src/share/classes/javax/swing/SwingWorker.java b/jdk/src/share/classes/javax/swing/SwingWorker.java index 263284acc4e..ebeeb639112 100644 --- a/jdk/src/share/classes/javax/swing/SwingWorker.java +++ b/jdk/src/share/classes/javax/swing/SwingWorker.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2010 Sun Microsystems, Inc. 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 @@ -42,9 +42,10 @@ import sun.awt.AppContext; import sun.swing.AccumulativeRunnable; /** - * An abstract class to perform lengthy GUI-interacting tasks in a - * dedicated thread. - * + * An abstract class to perform lengthy GUI-interaction tasks in a + * background thread. Several background threads can be used to execute such + * tasks. However, the exact strategy of choosing a thread for any particular + * {@code SwingWorker} is unspecified and should not be relied on. *

* When writing a multi-threaded application using Swing, there are * two constraints to keep in mind: @@ -772,7 +773,7 @@ public abstract class SwingWorker implements RunnableFuture { }; executorService = - new ThreadPoolExecutor(1, MAX_WORKER_THREADS, + new ThreadPoolExecutor(MAX_WORKER_THREADS, MAX_WORKER_THREADS, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue(), threadFactory); diff --git a/jdk/test/javax/swing/SwingWorker/6880336/NestedWorkers.java b/jdk/test/javax/swing/SwingWorker/6880336/NestedWorkers.java new file mode 100644 index 00000000000..1df1dbd1834 --- /dev/null +++ b/jdk/test/javax/swing/SwingWorker/6880336/NestedWorkers.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + * @bug 6880336 + * @summary Test for nested SwingWorkers, i.e. when the second worker is +started from the first's doInBackground() method. A timeout when running +* this test is an indication of failure. + * @author Artem Ananiev + * @run main/timeout=32 NestedWorkers + */ + +import javax.swing.*; + +public class NestedWorkers extends SwingWorker { + + private final static int MAX_LEVEL = 2; + + private int level; + + public NestedWorkers(int level) { + super(); + this.level = level; + } + + @Override + public String doInBackground() throws Exception { + if (level < MAX_LEVEL) { + SwingWorker nested = new NestedWorkers(level + 1); + nested.execute(); + nested.get(); + } + System.out.println("doInBackground " + level + " is complete"); + return String.valueOf(level); + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + SwingWorker sw = new NestedWorkers(0); + sw.execute(); + try { + System.err.println(sw.get()); + } catch (Exception z) { + throw new RuntimeException(z); + } + } + }); + } + +} From c21ea1a6d8cc5202eab80efca1d036e40e631aec Mon Sep 17 00:00:00 2001 From: Costantino Cerbo Date: Wed, 28 Apr 2010 17:16:05 +0400 Subject: [PATCH 06/23] 6913179: The java.awt.FileDialog should use native GTK file chooser on linux distros Introduce a GTK-based alternative implementation of the FileDialogPeer on X11 Reviewed-by: anthony, peterz --- jdk/make/sun/xawt/FILES_c_unix.gmk | 3 +- jdk/make/sun/xawt/FILES_export_unix.gmk | 3 +- jdk/make/sun/xawt/mapfile-vers | 4 + .../solaris/classes/sun/awt/UNIXToolkit.java | 23 ++ .../sun/awt/X11/GtkFileDialogPeer.java | 134 +++++++++++ .../solaris/classes/sun/awt/X11/XToolkit.java | 4 +- .../solaris/native/sun/awt/awt_UNIXToolkit.c | 20 ++ .../solaris/native/sun/awt/gtk2_interface.c | 87 ++++++- .../solaris/native/sun/awt/gtk2_interface.h | 133 ++++++++++- .../sun/awt/sun_awt_X11_GtkFileDialogPeer.c | 225 ++++++++++++++++++ .../sun/awt/sun_awt_X11_GtkFileDialogPeer.h | 31 +++ .../solaris/native/sun/awt/swing_GTKEngine.c | 44 +++- .../solaris/native/sun/awt/swing_GTKStyle.c | 30 ++- 13 files changed, 725 insertions(+), 16 deletions(-) create mode 100644 jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java create mode 100644 jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c create mode 100644 jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h diff --git a/jdk/make/sun/xawt/FILES_c_unix.gmk b/jdk/make/sun/xawt/FILES_c_unix.gmk index 604955e1e6e..5edc187388e 100644 --- a/jdk/make/sun/xawt/FILES_c_unix.gmk +++ b/jdk/make/sun/xawt/FILES_c_unix.gmk @@ -79,4 +79,5 @@ FILES_c = \ gtk2_interface.c \ swing_GTKEngine.c \ swing_GTKStyle.c \ - rect.c + rect.c \ + sun_awt_X11_GtkFileDialogPeer.c diff --git a/jdk/make/sun/xawt/FILES_export_unix.gmk b/jdk/make/sun/xawt/FILES_export_unix.gmk index f09f83242a9..bade1544e0e 100644 --- a/jdk/make/sun/xawt/FILES_export_unix.gmk +++ b/jdk/make/sun/xawt/FILES_export_unix.gmk @@ -33,4 +33,5 @@ FILES_export = \ sun/awt/X11/XDesktopPeer.java \ sun/awt/X11/XToolkit.java \ sun/awt/X11/XComponentPeer.java \ - sun/awt/X11/XInputMethod.java + sun/awt/X11/XInputMethod.java \ + sun/awt/X11/GtkFileDialogPeer.java diff --git a/jdk/make/sun/xawt/mapfile-vers b/jdk/make/sun/xawt/mapfile-vers index 82fe94f63ec..aee09457fb1 100644 --- a/jdk/make/sun/xawt/mapfile-vers +++ b/jdk/make/sun/xawt/mapfile-vers @@ -172,6 +172,7 @@ SUNWprivate_1.1 { Java_sun_awt_UNIXToolkit_load_1stock_1icon; Java_sun_awt_UNIXToolkit_load_1gtk_1icon; Java_sun_awt_UNIXToolkit_nativeSync; + Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl; Java_java_awt_AWTEvent_initIDs; Java_java_awt_event_InputEvent_initIDs; Java_java_awt_event_KeyEvent_initIDs; @@ -396,6 +397,9 @@ SUNWprivate_1.1 { Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetClassValue; Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetPangoFontName; + Java_sun_awt_X11_GtkFileDialogPeer_run; + Java_sun_awt_X11_GtkFileDialogPeer_quit; + Java_sun_print_CUPSPrinter_initIDs; Java_sun_print_CUPSPrinter_getCupsServer; Java_sun_print_CUPSPrinter_getCupsPort; diff --git a/jdk/src/solaris/classes/sun/awt/UNIXToolkit.java b/jdk/src/solaris/classes/sun/awt/UNIXToolkit.java index 23e39cabe49..c35e4859c80 100644 --- a/jdk/src/solaris/classes/sun/awt/UNIXToolkit.java +++ b/jdk/src/solaris/classes/sun/awt/UNIXToolkit.java @@ -314,4 +314,27 @@ public abstract class UNIXToolkit extends SunToolkit } return new RenderingHints(KEY_TEXT_ANTIALIASING, aaHint); } + + private native boolean gtkCheckVersionImpl(int major, int minor, + int micro); + + /** + * Returns {@code true} if the GTK+ library is compatible with the given + * version. + * + * @param major + * The required major version. + * @param minor + * The required minor version. + * @param micro + * The required micro version. + * @return {@code true} if the GTK+ library is compatible with the given + * version. + */ + public boolean checkGtkVersion(int major, int minor, int micro) { + if (loadGTK()) { + return gtkCheckVersionImpl(major, minor, micro); + } + return false; + } } diff --git a/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java b/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java new file mode 100644 index 00000000000..5860b396b61 --- /dev/null +++ b/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java @@ -0,0 +1,134 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package sun.awt.X11; + +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.peer.FileDialogPeer; +import java.io.File; +import java.io.FilenameFilter; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import sun.awt.AWTAccessor; + +/** + * FileDialogPeer for the GtkFileChooser. + * + * @author Costantino Cerbo (c.cerbo@gmail.com) + */ +class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { + + private FileDialog fd; + + public GtkFileDialogPeer(FileDialog fd) { + super((Dialog) fd); + this.fd = fd; + } + + private native void run(String title, int mode, String dir, String file, + FilenameFilter filter, boolean isMultipleMode); + + private native void quit(); + + /** + * Called exclusively by the native C code. + */ + private void setFileInternal(String directory, String[] filenames) { + AWTAccessor.FileDialogAccessor accessor = AWTAccessor + .getFileDialogAccessor(); + + if (filenames == null) { + accessor.setDirectory(fd, null); + accessor.setFile(fd, null); + accessor.setFiles(fd, null, null); + } else { + accessor.setDirectory(fd, directory); + accessor.setFile(fd, filenames[0]); + accessor.setFiles(fd, directory, filenames); + } + } + + /** + * Called exclusively by the native C code. + */ + private boolean filenameFilterCallback(String fullname) { + if (fd.getFilenameFilter() == null) { + // no filter, accept all. + return true; + } + + File filen = new File(fullname); + return fd.getFilenameFilter().accept(new File(filen.getParent()), + filen.getName()); + } + + @Override + public void setVisible(boolean b) { + XToolkit.awtLock(); + try { + if (b) { + Thread t = new Thread() { + public void run() { + GtkFileDialogPeer.this.run(fd.getTitle(), fd.getMode(), + fd.getDirectory(), fd.getFile(), fd + .getFilenameFilter(), fd + .isMultipleMode()); + fd.setVisible(false); + } + }; + t.start(); + } else { + quit(); + fd.setVisible(false); + } + } finally { + XToolkit.awtUnlock(); + } + } + + @Override + public void dispose() { + quit(); + super.dispose(); + } + + @Override + public void setDirectory(String dir) { + // We do not implement this method because we + // have delegated to FileDialog#setDirectory + } + + @Override + public void setFile(String file) { + // We do not implement this method because we + // have delegated to FileDialog#setFile + } + + @Override + public void setFilenameFilter(FilenameFilter filter) { + // We do not implement this method because we + // have delegated to FileDialog#setFilenameFilter + } +} diff --git a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java index 8676c6affb9..4ab6cd21960 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java @@ -1041,7 +1041,9 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } public FileDialogPeer createFileDialog(FileDialog target) { - FileDialogPeer peer = new XFileDialogPeer(target); + // The current GtkFileChooser is available from GTK+ 2.4 + FileDialogPeer peer = checkGtkVersion(2, 4, 0) ? new GtkFileDialogPeer( + target) : new XFileDialogPeer(target); targetCreatedPeer(target, peer); return peer; } diff --git a/jdk/src/solaris/native/sun/awt/awt_UNIXToolkit.c b/jdk/src/solaris/native/sun/awt/awt_UNIXToolkit.c index f802f9f7c68..b315832b106 100644 --- a/jdk/src/solaris/native/sun/awt/awt_UNIXToolkit.c +++ b/jdk/src/solaris/native/sun/awt/awt_UNIXToolkit.c @@ -260,3 +260,23 @@ Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jclass cls) } dlclose(hSplashLib); } + +/* + * Class: sun_awt_UNIXToolkit + * Method: gtkCheckVersionImpl + * Signature: (III)Ljava/lang/String; + */ +JNIEXPORT jboolean JNICALL +Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl(JNIEnv *env, jobject this, + jint major, jint minor, jint micro) +{ + char *ret; + + ret = fp_gtk_check_version(major, minor, micro); + if (ret == NULL) { + return TRUE; + } + + free(ret); + return FALSE; +} diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c index e6ede306824..dfa7ef1dfb4 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c @@ -32,6 +32,7 @@ #include "java_awt_Transparency.h" #define GTK2_LIB "libgtk-x11-2.0.so.0" +#define GTHREAD_LIB "libgthread-2.0.so.0" #define G_TYPE_INVALID G_TYPE_MAKE_FUNDAMENTAL (0) #define G_TYPE_NONE G_TYPE_MAKE_FUNDAMENTAL (1) @@ -75,6 +76,7 @@ const gint SELECTED = 1 << 9; const gint DEFAULT = 1 << 10; static void *gtk2_libhandle = NULL; +static void *gthread_libhandle = NULL; static jmp_buf j; /* Widgets */ @@ -150,7 +152,6 @@ static GtkWidget *gtk2_widgets[_GTK_WIDGET_TYPE_SIZE]; /************************* * Glib function pointers *************************/ -static void (*fp_g_free)(gpointer mem); static gboolean (*fp_g_main_context_iteration)(GMainContext *context, gboolean may_block); @@ -204,9 +205,6 @@ static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable, /************************ * Gtk function pointers ************************/ -static gchar* (*fp_gtk_check_version)(guint required_major, - guint required_minor, - guint required_micro); static gboolean (*fp_gtk_init_check)(int* argc, char** argv); /* Painting */ @@ -330,7 +328,6 @@ static void (*fp_gtk_menu_shell_append)(GtkMenuShell *menu_shell, static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item, GtkWidget *submenu); static void (*fp_gtk_widget_realize)(GtkWidget *widget); -static void (*fp_gtk_widget_destroy)(GtkWidget *widget); static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget, const gchar *stock_id, GtkIconSize size, const gchar *detail); static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name); @@ -388,6 +385,15 @@ static void* dl_symbol(const char* name) return result; } +static void* dl_symbol_gthread(const char* name) +{ + void* result = dlsym(gthread_libhandle, name); + if (!result) + longjmp(j, NO_SYMBOL_EXCEPTION); + + return result; +} + gboolean gtk2_check_version() { if (gtk2_libhandle != NULL) { @@ -414,6 +420,33 @@ gboolean gtk2_check_version() } } +/** + * Functions for sun_awt_X11_GtkFileDialogPeer.c + */ +void gtk2_file_chooser_load() +{ + fp_gtk_file_chooser_get_filename = dl_symbol( + "gtk_file_chooser_get_filename"); + fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new"); + fp_gtk_file_chooser_set_current_folder = dl_symbol( + "gtk_file_chooser_set_current_folder"); + fp_gtk_file_chooser_set_filename = dl_symbol( + "gtk_file_chooser_set_filename"); + fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom"); + fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter"); + fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type"); + fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new"); + fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol( + "gtk_file_chooser_set_do_overwrite_confirmation"); + fp_gtk_file_chooser_set_select_multiple = dl_symbol( + "gtk_file_chooser_set_select_multiple"); + fp_gtk_file_chooser_get_current_folder = dl_symbol( + "gtk_file_chooser_get_current_folder"); + fp_gtk_file_chooser_get_filenames = dl_symbol( + "gtk_file_chooser_get_filenames"); + fp_gtk_g_slist_length = dl_symbol("g_slist_length"); +} + gboolean gtk2_load() { gboolean result; @@ -423,7 +456,9 @@ gboolean gtk2_load() char *gtk_modules_env; gtk2_libhandle = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gtk2_libhandle == NULL) + gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); + + if (gtk2_libhandle == NULL || gthread_libhandle == NULL) return FALSE; if (setjmp(j) == 0) @@ -597,6 +632,30 @@ gboolean gtk2_load() fp_gtk_range_get_adjustment = dl_symbol("gtk_range_get_adjustment"); + fp_gtk_widget_hide = dl_symbol("gtk_widget_hide"); + fp_gtk_main_quit = dl_symbol("gtk_main_quit"); + fp_g_signal_connect_data = dl_symbol("g_signal_connect_data"); + fp_gtk_widget_show = dl_symbol("gtk_widget_show"); + fp_gtk_main = dl_symbol("gtk_main"); + + /** + * GLib thread system + */ + fp_g_thread_get_initialized = dl_symbol_gthread( + "g_thread_get_initialized"); + fp_g_thread_init = dl_symbol_gthread("g_thread_init"); + fp_gdk_threads_init = dl_symbol("gdk_threads_init"); + fp_gdk_threads_enter = dl_symbol("gdk_threads_enter"); + fp_gdk_threads_leave = dl_symbol("gdk_threads_leave"); + + /** + * Functions for sun_awt_X11_GtkFileDialogPeer.c + */ + if (fp_gtk_check_version(2, 4, 0) == NULL) { + // The current GtkFileChooser is available from GTK+ 2.4 + gtk2_file_chooser_load(); + } + /* Some functions may be missing in pre-2.4 GTK. We handle them specially here. */ @@ -626,6 +685,10 @@ gboolean gtk2_load() { dlclose(gtk2_libhandle); gtk2_libhandle = NULL; + + dlclose(gthread_libhandle); + gthread_libhandle = NULL; + return FALSE; } @@ -678,6 +741,17 @@ gboolean gtk2_load() */ handler = XSetErrorHandler(NULL); io_handler = XSetIOErrorHandler(NULL); + + if (fp_gtk_check_version(2, 2, 0) == NULL) { + // Init the thread system to use GLib in a thread-safe mode + if (!fp_g_thread_get_initialized()) { + fp_g_thread_init(NULL); + + //According the GTK documentation, gdk_threads_init() should be + //called before gtk_init() or gtk_init_check() + fp_gdk_threads_init(); + } + } result = (*fp_gtk_init_check)(NULL, NULL); XSetErrorHandler(handler); @@ -722,6 +796,7 @@ int gtk2_unload() dlerror(); dlclose(gtk2_libhandle); + dlclose(gthread_libhandle); if ((gtk2_error = dlerror()) != NULL) { return FALSE; diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.h b/jdk/src/solaris/native/sun/awt/gtk2_interface.h index bde5ec1bc19..95ca3cecaad 100644 --- a/jdk/src/solaris/native/sun/awt/gtk2_interface.h +++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.h @@ -28,6 +28,21 @@ #include #include +#define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) +#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) (_G_TYPE_CIC ((instance), (g_type), c_type)) +#define GTK_TYPE_FILE_CHOOSER (fp_gtk_file_chooser_get_type ()) +#define GTK_FILE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_CHOOSER, GtkFileChooser)) +#define fp_g_signal_connect(instance, detailed_signal, c_handler, data) \ + fp_g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0) +#define G_CALLBACK(f) ((GCallback) (f)) +#define G_TYPE_FUNDAMENTAL_SHIFT (2) +#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) +#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20) +#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject)) +#define GTK_STOCK_CANCEL "gtk-cancel" +#define GTK_STOCK_SAVE "gtk-save" +#define GTK_STOCK_OPEN "gtk-open" + typedef enum _WidgetType { BUTTON, /* GtkButton */ @@ -254,7 +269,13 @@ typedef enum /* We define all structure pointers to be void* */ typedef void GError; typedef void GMainContext; -typedef void GSList; + +typedef struct _GSList GSList; +struct _GSList +{ + gpointer data; + GSList *next; +}; typedef void GdkColormap; typedef void GdkDrawable; @@ -556,6 +577,65 @@ struct _GtkProgressBar guint ellipsize : 3; }; +typedef enum { + GTK_RESPONSE_NONE = -1, + GTK_RESPONSE_REJECT = -2, + GTK_RESPONSE_ACCEPT = -3, + GTK_RESPONSE_DELETE_EVENT = -4, + GTK_RESPONSE_OK = -5, + GTK_RESPONSE_CANCEL = -6, + GTK_RESPONSE_CLOSE = -7, + GTK_RESPONSE_YES = -8, + GTK_RESPONSE_NO = -9, + GTK_RESPONSE_APPLY = -10, + GTK_RESPONSE_HELP = -11 +} GtkResponseType; + +typedef struct _GtkWindow GtkWindow; + +typedef struct _GtkFileChooser GtkFileChooser; + +typedef enum { + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER +} GtkFileChooserAction; + +typedef struct _GtkFileFilter GtkFileFilter; + +typedef enum { + GTK_FILE_FILTER_FILENAME = 1 << 0, + GTK_FILE_FILTER_URI = 1 << 1, + GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2, + GTK_FILE_FILTER_MIME_TYPE = 1 << 3 +} GtkFileFilterFlags; + +typedef struct { + GtkFileFilterFlags contains; + const gchar *filename; + const gchar *uri; + const gchar *display_name; + const gchar *mime_type; +} GtkFileFilterInfo; + +typedef gboolean (*GtkFileFilterFunc)(const GtkFileFilterInfo *filter_info, + gpointer data); + +typedef void (*GDestroyNotify)(gpointer data); + +typedef void (*GCallback)(void); + +typedef struct _GClosure GClosure; + +typedef void (*GClosureNotify)(gpointer data, GClosure *closure); + +typedef enum { + G_CONNECT_AFTER = 1 << 0, G_CONNECT_SWAPPED = 1 << 1 +} GConnectFlags; + +typedef struct _GThreadFunctions GThreadFunctions; + /* * Converts java.lang.String object to UTF-8 character string. */ @@ -569,6 +649,13 @@ const char *getStrFor(JNIEnv *env, jstring value); */ gboolean gtk2_check_version(); +/** + * Returns : + * NULL if the GTK+ library is compatible with the given version, or a string + * describing the version mismatch. + */ +gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor, + guint required_micro); /* * Load the gtk2 library. If the library is already loaded this method has no * effect and returns success. @@ -651,6 +738,7 @@ jobject gtk2_get_setting(JNIEnv *env, Setting property); void gtk2_set_range_value(WidgetType widget_type, jdouble value, jdouble min, jdouble max, jdouble visible); +void (*fp_g_free)(gpointer mem); void (*fp_g_object_unref)(gpointer object); int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf); guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf); @@ -660,5 +748,48 @@ int (*fp_gdk_pixbuf_get_n_channels)(const GdkPixbuf *pixbuf); int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf); int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf); GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error); +void (*fp_gtk_widget_destroy)(GtkWidget *widget); + + +/** + * Function Pointers for GtkFileChooser + */ +gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); +void (*fp_gtk_widget_hide)(GtkWidget *widget); +void (*fp_gtk_main_quit)(void); +GtkWidget* (*fp_gtk_file_chooser_dialog_new)(const gchar *title, + GtkWindow *parent, GtkFileChooserAction action, + const gchar *first_button_text, ...); +gboolean (*fp_gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser, + const gchar *filename); +gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser, + const char *filename); +void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter, + GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data, + GDestroyNotify notify); +void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, + GtkFileFilter *filter); +GType (*fp_gtk_file_chooser_get_type)(void); +GtkFileFilter* (*fp_gtk_file_filter_new)(void); +void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)( + GtkFileChooser *chooser, gboolean do_overwrite_confirmation); +void (*fp_gtk_file_chooser_set_select_multiple)( + GtkFileChooser *chooser, gboolean select_multiple); +gchar* (*fp_gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); +GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); +guint (*fp_gtk_g_slist_length)(GSList *list); +gulong (*fp_g_signal_connect_data)(gpointer instance, + const gchar *detailed_signal, GCallback c_handler, gpointer data, + GClosureNotify destroy_data, GConnectFlags connect_flags); +void (*fp_gtk_widget_show)(GtkWidget *widget); +void (*fp_gtk_main)(void); +guint (*fp_gtk_main_level)(void); + + +gboolean (*fp_g_thread_get_initialized)(void); +void (*fp_g_thread_init)(GThreadFunctions *vtable); +void (*fp_gdk_threads_init)(void); +void (*fp_gdk_threads_enter)(void); +void (*fp_gdk_threads_leave)(void); #endif /* !_GTK2_INTERFACE_H */ diff --git a/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c b/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c new file mode 100644 index 00000000000..717a38382d7 --- /dev/null +++ b/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include "gtk2_interface.h" +#include "sun_awt_X11_GtkFileDialogPeer.h" + +static JavaVM *jvm; +static GtkWidget *dialog = NULL; + +/* To cache some method IDs */ +static jmethodID filenameFilterCallbackMethodID = NULL; +static jmethodID setFileInternalMethodID = NULL; + +static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gpointer obj) +{ + JNIEnv *env; + jclass cx; + jstring filename; + + env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2); + + if (filenameFilterCallbackMethodID == NULL) { + cx = (*env)->GetObjectClass(env, (jobject) obj); + if (cx == NULL) { + JNU_ThrowInternalError(env, "Could not get file filter class"); + return 0; + } + + filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx, + "filenameFilterCallback", "(Ljava/lang/String;)Z"); + if (filenameFilterCallbackMethodID == NULL) { + JNU_ThrowInternalError(env, + "Could not get filenameFilterCallback method id"); + return 0; + } + } + + filename = (*env)->NewStringUTF(env, filter_info->filename); + + return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID, + filename); +} + +/* + * Class: sun_awt_X11_GtkFileDialogPeer + * Method: quit + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit +(JNIEnv * env, jobject jpeer) +{ + if (dialog != NULL) + { + fp_gtk_widget_hide (dialog); + fp_gtk_widget_destroy (dialog); + + fp_gtk_main_quit (); + dialog = NULL; + } +} + +/** + * Convert a GSList to an array of filenames (without the parent folder) + */ +static jobjectArray toFilenamesArray(JNIEnv *env, GSList* list) +{ + jstring str; + jclass stringCls; + GSList *iterator; + jobjectArray array; + int i; + char* entry; + + if (NULL == list) { + return NULL; + } + + stringCls = (*env)->FindClass(env, "java/lang/String"); + if (stringCls == NULL) { + JNU_ThrowInternalError(env, "Could not get java.lang.String class"); + return NULL; + } + + array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls, + NULL); + if (array == NULL) { + JNU_ThrowInternalError(env, "Could not instantiate array files array"); + return NULL; + } + + i = 0; + for (iterator = list; iterator; iterator = iterator->next) { + entry = (char*) iterator->data; + entry = strrchr(entry, '/') + 1; + str = (*env)->NewStringUTF(env, entry); + (*env)->SetObjectArrayElement(env, array, i, str); + i++; + } + + return array; +} + +static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj) +{ + JNIEnv *env; + char *current_folder; + GSList *filenames; + jclass cx; + jstring jcurrent_folder; + jobjectArray jfilenames; + + env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2); + current_folder = NULL; + filenames = NULL; + + if (responseId == GTK_RESPONSE_ACCEPT) { + current_folder = fp_gtk_file_chooser_get_current_folder( + GTK_FILE_CHOOSER(dialog)); + filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + } + + if (setFileInternalMethodID == NULL) { + cx = (*env)->GetObjectClass(env, (jobject) obj); + if (cx == NULL) { + JNU_ThrowInternalError(env, "Could not get GTK peer class"); + return; + } + + setFileInternalMethodID = (*env)->GetMethodID(env, cx, + "setFileInternal", "(Ljava/lang/String;[Ljava/lang/String;)V"); + if (setFileInternalMethodID == NULL) { + JNU_ThrowInternalError(env, + "Could not get setFileInternalMethodID method id"); + return; + } + } + + jcurrent_folder = (*env)->NewStringUTF(env, current_folder); + jfilenames = toFilenamesArray(env, filenames); + + (*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jcurrent_folder, + jfilenames); + fp_g_free(current_folder); + + Java_sun_awt_X11_GtkFileDialogPeer_quit(NULL, NULL); +} + +/* + * Class: sun_awt_X11_GtkFileDialogPeer + * Method: run + * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V + */ +JNIEXPORT void JNICALL +Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer, + jstring jtitle, jint mode, jstring jdir, jstring jfile, + jobject jfilter, jboolean multiple) +{ + GtkFileFilter *filter; + + if (jvm == NULL) { + (*env)->GetJavaVM(env, &jvm); + } + + fp_gdk_threads_init(); + fp_gdk_threads_enter(); + + const char *title = (*env)->GetStringUTFChars(env, jtitle, 0); + + if (mode == 1) { + /* Save action */ + dialog = fp_gtk_file_chooser_dialog_new(title, NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + } + else { + /* Default action OPEN */ + dialog = fp_gtk_file_chooser_dialog_new(title, NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); + + /* Set multiple selection mode, that is allowed only in OPEN action */ + if (multiple) { + fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), + multiple); + } + } + + (*env)->ReleaseStringUTFChars(env, jtitle, title); + + /* Set the directory */ + if (jdir != NULL) { + const char *dir = (*env)->GetStringUTFChars(env, jdir, 0); + fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir); + (*env)->ReleaseStringUTFChars(env, jdir, dir); + } + + /* Set the filename */ + if (jfile != NULL) { + const char *filename = (*env)->GetStringUTFChars(env, jfile, 0); + fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename); + (*env)->ReleaseStringUTFChars(env, jfile, filename); + } + + /* Set the file filter */ + if (jfilter != NULL) { + filter = fp_gtk_file_filter_new(); + fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME, + filenameFilterCallback, jpeer, NULL); + fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); + } + + /* Other Properties */ + if (fp_gtk_check_version(2, 8, 0) == NULL) { + fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER( + dialog), TRUE); + } + + fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( + handle_response), jpeer); + fp_gtk_widget_show(dialog); + + fp_gtk_main(); + fp_gdk_threads_leave(); +} diff --git a/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h b/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h new file mode 100644 index 00000000000..91334b4ebee --- /dev/null +++ b/jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h @@ -0,0 +1,31 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class sun_awt_X11_GtkFileDialogPeer */ + +#ifndef _Included_sun_awt_X11_GtkFileDialogPeer +#define _Included_sun_awt_X11_GtkFileDialogPeer +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + * Class: sun_awt_X11_GtkFileDialogPeer + * Method: run + * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V + */ +JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_run +(JNIEnv *, jobject, jstring, jint, jstring, jstring, jobject, jboolean); + +/* + * Class: sun_awt_X11_GtkFileDialogPeer + * Method: quit + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit +(JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/jdk/src/solaris/native/sun/awt/swing_GTKEngine.c b/jdk/src/solaris/native/sun/awt/swing_GTKEngine.c index c213a17c62d..d0a4aa864fb 100644 --- a/jdk/src/solaris/native/sun/awt/swing_GTKEngine.c +++ b/jdk/src/solaris/native/sun/awt/swing_GTKEngine.c @@ -38,8 +38,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1arrow( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint arrow_type) { + fp_gdk_threads_enter(); gtk2_paint_arrow(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, arrow_type, TRUE); + fp_gdk_threads_leave(); } /* @@ -54,8 +56,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box( jint x, jint y, jint w, jint h, jint synth_state, jint dir) { + fp_gdk_threads_enter(); gtk2_paint_box(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, synth_state, dir); + fp_gdk_threads_leave(); } /* @@ -70,8 +74,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1box_1gap( jint x, jint y, jint w, jint h, jint gap_side, jint gap_x, jint gap_w) { + fp_gdk_threads_enter(); gtk2_paint_box_gap(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, gap_side, gap_x, gap_w); + fp_gdk_threads_leave(); } /* @@ -85,8 +91,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1check( jint widget_type, jint synth_state, jstring detail, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_paint_check(widget_type, synth_state, getStrFor(env, detail), x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -100,8 +108,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1expander( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h, jint expander_style) { + fp_gdk_threads_enter(); gtk2_paint_expander(widget_type, state, getStrFor(env, detail), x, y, w, h, expander_style); + fp_gdk_threads_leave(); } /* @@ -115,8 +125,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1extension( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint placement) { + fp_gdk_threads_enter(); gtk2_paint_extension(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, placement); + fp_gdk_threads_leave(); } /* @@ -130,8 +142,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1flat_1box( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jboolean has_focus) { + fp_gdk_threads_enter(); gtk2_paint_flat_box(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, has_focus); + fp_gdk_threads_leave(); } /* @@ -145,8 +159,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1focus( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_paint_focus(widget_type, state, getStrFor(env, detail), x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -160,8 +176,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1handle( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint orientation) { + fp_gdk_threads_enter(); gtk2_paint_handle(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, orientation); + fp_gdk_threads_leave(); } /* @@ -175,8 +193,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1hline( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_paint_hline(widget_type, state, getStrFor(env, detail), x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -190,8 +210,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1option( jint widget_type, jint synth_state, jstring detail, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_paint_option(widget_type, synth_state, getStrFor(env, detail), x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -206,8 +228,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1shadow( jint x, jint y, jint w, jint h, jint synth_state, jint dir) { + fp_gdk_threads_enter(); gtk2_paint_shadow(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, synth_state, dir); + fp_gdk_threads_leave(); } /* @@ -221,8 +245,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1slider( jint widget_type, jint state, jint shadow_type, jstring detail, jint x, jint y, jint w, jint h, jint orientation) { + fp_gdk_threads_enter(); gtk2_paint_slider(widget_type, state, shadow_type, getStrFor(env, detail), x, y, w, h, orientation); + fp_gdk_threads_leave(); } /* @@ -236,8 +262,10 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1vline( jint widget_type, jint state, jstring detail, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_paint_vline(widget_type, state, getStrFor(env, detail), x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -250,7 +278,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1paint_1background( JNIEnv *env, jobject this, jint widget_type, jint state, jint x, jint y, jint w, jint h) { + fp_gdk_threads_enter(); gtk_paint_background(widget_type, state, x, y, w, h); + fp_gdk_threads_leave(); } /* @@ -262,7 +292,9 @@ JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeStartPainting( JNIEnv *env, jobject this, jint w, jint h) { + fp_gdk_threads_enter(); gtk2_init_painting(w, h); + fp_gdk_threads_leave(); } /* @@ -276,7 +308,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeFinishPainting( { jint transparency; gint *buffer = (gint*) (*env)->GetPrimitiveArrayCritical(env, dest, 0); + fp_gdk_threads_enter(); transparency = gtk2_copy_image(buffer, width, height); + fp_gdk_threads_leave(); (*env)->ReleasePrimitiveArrayCritical(env, dest, buffer, 0); return transparency; } @@ -289,7 +323,9 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeFinishPainting( JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1switch_1theme( JNIEnv *env, jobject this) { + fp_gdk_threads_enter(); flush_gtk_event_loop(); + fp_gdk_threads_leave(); } /* @@ -300,7 +336,11 @@ JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1switch JNIEXPORT jobject JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1get_1gtk_1setting( JNIEnv *env, jobject this, jint property) { - return gtk2_get_setting(env, property); + jobject obj; + fp_gdk_threads_enter(); + obj = gtk2_get_setting(env, property); + fp_gdk_threads_leave(); + return obj; } /* @@ -313,5 +353,7 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeSetRangeValue( JNIEnv *env, jobject this, jint widget_type, jdouble value, jdouble min, jdouble max, jdouble visible) { + fp_gdk_threads_enter(); gtk2_set_range_value(widget_type, value, min, max, visible); + fp_gdk_threads_leave(); } diff --git a/jdk/src/solaris/native/sun/awt/swing_GTKStyle.c b/jdk/src/solaris/native/sun/awt/swing_GTKStyle.c index 111ae47b311..076e701681b 100644 --- a/jdk/src/solaris/native/sun/awt/swing_GTKStyle.c +++ b/jdk/src/solaris/native/sun/awt/swing_GTKStyle.c @@ -36,7 +36,11 @@ JNIEXPORT jint JNICALL Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetXThickness( JNIEnv *env, jclass klass, jint widget_type) { - return gtk2_get_xthickness(env, widget_type); + jint ret; + fp_gdk_threads_enter(); + ret = gtk2_get_xthickness(env, widget_type); + fp_gdk_threads_leave(); + return ret; } /* @@ -48,7 +52,11 @@ JNIEXPORT jint JNICALL Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetYThickness( JNIEnv *env, jclass klass, jint widget_type) { - return gtk2_get_ythickness(env, widget_type); + jint ret; + fp_gdk_threads_enter(); + ret = gtk2_get_ythickness(env, widget_type); + fp_gdk_threads_leave(); + return ret; } /* @@ -61,7 +69,11 @@ Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetColorForState( JNIEnv *env, jclass klass, jint widget_type, jint state_type, jint type_id) { - return gtk2_get_color_for_state(env, widget_type, state_type, type_id); + jint ret; + fp_gdk_threads_enter(); + ret = gtk2_get_color_for_state(env, widget_type, state_type, type_id); + fp_gdk_threads_leave(); + return ret; } /* @@ -73,7 +85,11 @@ JNIEXPORT jobject JNICALL Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetClassValue( JNIEnv *env, jclass klass, jint widget_type, jstring key) { - return gtk2_get_class_value(env, widget_type, key); + jobject ret; + fp_gdk_threads_enter(); + ret = gtk2_get_class_value(env, widget_type, key); + fp_gdk_threads_leave(); + return ret; } /* @@ -85,5 +101,9 @@ JNIEXPORT jstring JNICALL Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetPangoFontName( JNIEnv *env, jclass klass, jint widget_type) { - return gtk2_get_pango_font_name(env, widget_type); + jstring ret; + fp_gdk_threads_enter(); + ret = gtk2_get_pango_font_name(env, widget_type); + fp_gdk_threads_leave(); + return ret; } From 46ebf10e260dbc24210c4dd6cf8f2cde166ff40b Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 29 Apr 2010 15:50:40 +0800 Subject: [PATCH 07/23] 6947487: use HexDumpEncoder.encodeBuffer() Reviewed-by: mullan --- .../com/sun/security/auth/module/Krb5LoginModule.java | 4 ++-- .../com/sun/security/jgss/AuthorizationDataEntry.java | 4 ++-- .../classes/javax/security/auth/kerberos/KeyImpl.java | 4 ++-- jdk/src/share/classes/sun/security/krb5/EncryptionKey.java | 7 ++++--- .../classes/sun/security/provider/certpath/CertId.java | 6 +++--- jdk/src/share/classes/sun/security/tools/KeyTool.java | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 55972eefe89..8e16c4d4a55 100644 --- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -717,7 +717,7 @@ public class Krb5LoginModule implements LoginModule { for (int i = 0; i < encKeys.length; i++) { System.out.println("EncryptionKey: keyType=" + encKeys[i].getEType() + " keyBytes (hex dump)=" + - hd.encode(encKeys[i].getBytes())); + hd.encodeBuffer(encKeys[i].getBytes())); } } diff --git a/jdk/src/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java b/jdk/src/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java index 0386792a7c2..b885b037d50 100644 --- a/jdk/src/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java +++ b/jdk/src/share/classes/com/sun/security/jgss/AuthorizationDataEntry.java @@ -1,5 +1,5 @@ /* - * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2009-2010 Sun Microsystems, Inc. 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 @@ -63,6 +63,6 @@ final public class AuthorizationDataEntry { public String toString() { return "AuthorizationDataEntry: type="+type+", data=" + data.length + " bytes:\n" + - new sun.misc.HexDumpEncoder().encode(data); + new sun.misc.HexDumpEncoder().encodeBuffer(data); } } diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java index a91f3925267..f7a724b146b 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -205,7 +205,7 @@ class KeyImpl implements SecretKey, Destroyable, Serializable { + " keyBytes (hex dump)=" + (keyBytes == null || keyBytes.length == 0 ? " Empty Key" : - '\n' + hd.encode(keyBytes) + '\n' + hd.encodeBuffer(keyBytes) + '\n'); diff --git a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java index 15d6d78c04d..e67d504f617 100644 --- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java +++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -499,8 +499,9 @@ public class EncryptionKey + " kvno=" + kvno + " keyValue (hex dump)=" + (keyValue == null || keyValue.length == 0 ? - " Empty Key" : '\n' + Krb5.hexDumper.encode(keyValue) - + '\n')); + " Empty Key" : '\n' + + Krb5.hexDumper.encodeBuffer(keyValue) + + '\n')); } /** diff --git a/jdk/src/share/classes/sun/security/provider/certpath/CertId.java b/jdk/src/share/classes/sun/security/provider/certpath/CertId.java index 20e9aa2a789..e85ed531b99 100644 --- a/jdk/src/share/classes/sun/security/provider/certpath/CertId.java +++ b/jdk/src/share/classes/sun/security/provider/certpath/CertId.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. 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 @@ -96,9 +96,9 @@ public class CertId { HexDumpEncoder encoder = new HexDumpEncoder(); System.out.println("Issuer Certificate is " + issuerCert); System.out.println("issuerNameHash is " + - encoder.encode(issuerNameHash)); + encoder.encodeBuffer(issuerNameHash)); System.out.println("issuerKeyHash is " + - encoder.encode(issuerKeyHash)); + encoder.encodeBuffer(issuerKeyHash)); System.out.println("SerialNumber is " + serialNumber.getNumber()); } } diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index bd03c696e0e..2539d43e14b 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -2620,7 +2620,7 @@ public final class KeyTool { if (v.length == 0) { out.println(rb.getString("(Empty value)")); } else { - new sun.misc.HexDumpEncoder().encode(ext.getExtensionValue(), out); + new sun.misc.HexDumpEncoder().encodeBuffer(ext.getExtensionValue(), out); out.println(); } } From 20fbeb53cdd1dacc3f5967842aa782a4eb872e0a Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 29 Apr 2010 15:51:10 +0800 Subject: [PATCH 08/23] 6844193: support max_retries in krb5.conf Reviewed-by: valeriep --- .../classes/sun/security/krb5/Config.java | 4 +- .../classes/sun/security/krb5/KrbKdcReq.java | 141 +++++++----- .../sun/security/krb5/auto/MaxRetries.java | 203 ++++++++++++++++++ 3 files changed, 293 insertions(+), 55 deletions(-) create mode 100644 jdk/test/sun/security/krb5/auto/MaxRetries.java diff --git a/jdk/src/share/classes/sun/security/krb5/Config.java b/jdk/src/share/classes/sun/security/krb5/Config.java index 3cc209c9f21..3980deb8e2d 100644 --- a/jdk/src/share/classes/sun/security/krb5/Config.java +++ b/jdk/src/share/classes/sun/security/krb5/Config.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -109,7 +109,7 @@ public class Config { public static synchronized void refresh() throws KrbException { singleton = new Config(); KeyTab.refresh(); - KrbKdcReq.KdcAccessibility.reset(); + KrbKdcReq.initStatic(); } diff --git a/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java b/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java index 389fd04be4e..74c5edab291 100644 --- a/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java +++ b/jdk/src/share/classes/sun/security/krb5/KrbKdcReq.java @@ -1,5 +1,5 @@ /* - * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Portions Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -51,28 +51,31 @@ import java.util.HashSet; public abstract class KrbKdcReq { - // Currently there is no option to specify retries - // in the kerberos configuration file - - private static final int DEFAULT_KDC_RETRY_LIMIT = Krb5.KDC_RETRY_LIMIT; + // The following settings can be configured in [libdefaults] + // section of krb5.conf, which are global for all realms. Each of + // them can also be defined in a realm, which overrides value here. /** - * Default timeout period when requesting a ticket from a KDC. - * If not specified in the configuration file, - * a value of 30 seconds is used. + * max retry time for a single KDC, default Krb5.KDC_RETRY_LIMIT (3) */ - public static final int DEFAULT_KDC_TIMEOUT; // milliseconds + private static int defaultKdcRetryLimit; + /** + * timeout requesting a ticket from KDC, in millisec, default 30 sec + */ + private static int defaultKdcTimeout; + /** + * max UDP packet size, default unlimited (-1) + */ + private static int defaultUdpPrefLimit; private static final boolean DEBUG = Krb5.DEBUG; - private static int udpPrefLimit = -1; - private static final String BAD_POLICY_KEY = "krb5.kdc.bad.policy"; /** * What to do when a KDC is unavailable, specified in the * java.security file with key krb5.kdc.bad.policy. - * Possible values can be TRY_LAST or TRY_LESS + * Possible values can be TRY_LAST or TRY_LESS. Reloaded when refreshed. */ private enum BpType { NONE, TRY_LAST, TRY_LESS @@ -80,9 +83,16 @@ public abstract class KrbKdcReq { private static int tryLessMaxRetries = 1; private static int tryLessTimeout = 5000; - private static final BpType badPolicy; + private static BpType badPolicy; static { + initStatic(); + } + + /** + * Read global settings + */ + public static void initStatic() { String value = AccessController.doPrivileged( new PrivilegedAction() { public String run() { @@ -95,9 +105,21 @@ public abstract class KrbKdcReq { if ("tryless".equals(ss[0])) { if (ss.length > 1) { String[] params = ss[1].split(","); - tryLessMaxRetries = Integer.parseInt(params[0]); - if (params.length > 1) { - tryLessTimeout = Integer.parseInt(params[1]); + try { + int tmp0 = Integer.parseInt(params[0]); + if (params.length > 1) { + tryLessTimeout = Integer.parseInt(params[1]); + } + // Assign here in case of exception at params[1] + tryLessMaxRetries = tmp0; + } catch (NumberFormatException nfe) { + // Ignored. Please note that tryLess is recognized and + // used, parameters using default values + if (DEBUG) { + System.out.println("Invalid " + BAD_POLICY_KEY + + " parameter for tryLess: " + + value + ", use default"); + } } } badPolicy = BpType.TRY_LESS; @@ -110,30 +132,33 @@ public abstract class KrbKdcReq { badPolicy = BpType.NONE; } - /* - * Get default timeout. - */ int timeout = -1; + int max_retries = -1; + int udf_pref_limit = -1; + try { Config cfg = Config.getInstance(); String temp = cfg.getDefault("kdc_timeout", "libdefaults"); timeout = parsePositiveIntString(temp); + temp = cfg.getDefault("max_retries", "libdefaults"); + max_retries = parsePositiveIntString(temp); temp = cfg.getDefault("udp_preference_limit", "libdefaults"); - udpPrefLimit = parsePositiveIntString(temp); + udf_pref_limit = parsePositiveIntString(temp); } catch (Exception exc) { - // ignore any exceptions; use the default time out values + // ignore any exceptions; use default values if (DEBUG) { - System.out.println ("Exception in getting kdc_timeout value, " + - "using default value " + + System.out.println ("Exception in getting KDC communication " + + "settings, using default value " + exc.getMessage()); } } + defaultKdcTimeout = timeout > 0 ? timeout : 30*1000; // 30 seconds + defaultKdcRetryLimit = + max_retries > 0 ? max_retries : Krb5.KDC_RETRY_LIMIT; + defaultUdpPrefLimit = udf_pref_limit; - if (timeout > 0) - DEFAULT_KDC_TIMEOUT = timeout; - else - DEFAULT_KDC_TIMEOUT = 30*1000; // 30 seconds + KdcAccessibility.reset(); } protected byte[] obuf; @@ -151,6 +176,9 @@ public abstract class KrbKdcReq { public String send(String realm) throws IOException, KrbException { + int udpPrefLimit = getRealmSpecificValue( + realm, "udp_preference_limit", defaultUdpPrefLimit); + boolean useTCP = (udpPrefLimit > 0 && (obuf != null && obuf.length > udpPrefLimit)); @@ -213,9 +241,10 @@ public abstract class KrbKdcReq { return; int port = Krb5.KDC_INET_DEFAULT_PORT; - int retries = DEFAULT_KDC_RETRY_LIMIT; - int timeout = getKdcTimeout(realm); - + int retries = getRealmSpecificValue( + realm, "max_retries", defaultKdcRetryLimit); + int timeout = getRealmSpecificValue( + realm, "kdc_timeout", defaultKdcTimeout); if (badPolicy == BpType.TRY_LESS && KdcAccessibility.isBad(tempKdc)) { if (retries > tryLessMaxRetries) { @@ -322,6 +351,12 @@ public abstract class KrbKdcReq { if (useTCP) { TCPClient kdcClient = new TCPClient(kdc, port); + if (DEBUG) { + System.out.println(">>> KDCCommunication: kdc=" + kdc + + " TCP:" + + port + + ", #bytes=" + obuf.length); + } try { /* * Send the data to the kdc. @@ -336,7 +371,7 @@ public abstract class KrbKdcReq { } } else { - // For each KDC we try DEFAULT_KDC_RETRY_LIMIT (3) times to + // For each KDC we try defaultKdcRetryLimit times to // get the response for (int i=1; i <= retries; i++) { UDPClient kdcClient = new UDPClient(kdc, port, timeout); @@ -382,37 +417,37 @@ public abstract class KrbKdcReq { } /** - * Returns a timeout value for the KDC of the given realm. - * A KDC-specific timeout, if specified in the config file, - * overrides the default timeout (which may also be specified - * in the config file). Default timeout is returned if null - * is specified for realm. - * @param realm the realm which kdc's timeout is requested - * @return KDC timeout + * Returns krb5.conf setting of {@code key} for a specfic realm, + * which can be: + * 1. defined in the sub-stanza for the given realm inside [realms], or + * 2. defined in [libdefaults], or + * 3. defValue + * @param realm the given realm in which the setting is requested. Returns + * the global setting if null + * @param key the key for the setting + * @param defValue default value + * @return a value for the key */ - private int getKdcTimeout(String realm) - { - int timeout = DEFAULT_KDC_TIMEOUT; + private int getRealmSpecificValue(String realm, String key, int defValue) { + int v = defValue; - if (realm == null) - return timeout; + if (realm == null) return v; - int tempTimeout = -1; + int temp = -1; try { - String temp = - Config.getInstance().getDefault("kdc_timeout", realm); - tempTimeout = parsePositiveIntString(temp); + String value = + Config.getInstance().getDefault(key, realm); + temp = parsePositiveIntString(value); } catch (Exception exc) { + // Ignored, defValue will be picked up } - if (tempTimeout > 0) - timeout = tempTimeout; + if (temp > 0) v = temp; - return timeout; + return v; } - private static int parsePositiveIntString(String intString) - { + private static int parsePositiveIntString(String intString) { if (intString == null) return -1; @@ -461,7 +496,7 @@ public abstract class KrbKdcReq { return bads.contains(kdc); } - public static synchronized void reset() { + private static synchronized void reset() { if (DEBUG) { System.out.println(">>> KdcAccessibility: reset"); } diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java new file mode 100644 index 00000000000..4a995bb7f3e --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -0,0 +1,203 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6844193 + * @run main/timeout=300 MaxRetries + * @summary support max_retries in krb5.conf + */ + +import java.io.*; +import java.security.Security; + +public class MaxRetries { + public static void main(String[] args) + throws Exception { + + System.setProperty("sun.security.krb5.debug", "true"); + new OneKDC(null).writeJAASConf(); + System.setProperty("java.security.krb5.conf", "alternative-krb5.conf"); + + // For tryLast + Security.setProperty("krb5.kdc.bad.policy", "trylast"); + rewriteMaxRetries(4); + test1(4000, 6); // 1 1 1 1 2 2 + test1(4000, 2); // 2 2 + + rewriteMaxRetries(1); + test1(1000, 3); // 1 2 2 + test1(1000, 2); // 2 2 + + rewriteMaxRetries(-1); + test1(5000, 4); // 1 1 2 2 + test1(5000, 2); // 2 2 + + // For tryLess + Security.setProperty("krb5.kdc.bad.policy", "tryless"); + rewriteMaxRetries(4); + test1(4000, 7); // 1 1 1 1 2 1 2 + test1(4000, 4); // 1 2 1 2 + + rewriteMaxRetries(1); + test1(1000, 4); // 1 2 1 2 + test1(1000, 4); // 1 2 1 2 + + rewriteMaxRetries(-1); + test1(5000, 5); // 1 1 2 1 2 + test1(5000, 4); // 1 2 1 2 + + rewriteUdpPrefLimit(-1, -1); // default, no limit + test2("UDP"); + + rewriteUdpPrefLimit(10, -1); // global rules + test2("TCP"); + + rewriteUdpPrefLimit(10, 10000); // realm rules + test2("UDP"); + + rewriteUdpPrefLimit(10000, 10); // realm rules + test2("TCP"); + } + + /** + * One round of test for max_retries and timeout. + * @param timeout the expected timeout + * @param count the expected total try + */ + private static void test1(int timeout, int count) throws Exception { + String timeoutTag = "timeout=" + timeout; + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context c = Context.fromJAAS("client"); + System.setOut(oldout); + + String[] lines = new String(bo.toByteArray()).split("\n"); + System.out.println("----------------- TEST (" + timeout + "," + + count + ") -----------------"); + for (String line: lines) { + if (line.startsWith(">>> KDCCommunication")) { + System.out.println(line); + if (line.indexOf(timeoutTag) < 0) { + throw new Exception("Wrong timeout value"); + } + count--; + } + } + if (count != 0) { + throw new Exception("Retry count is " + count + " less"); + } + } + + /** + * One round of test for udp_preference_limit. + * @param proto the expected protocol used + */ + private static void test2(String proto) throws Exception { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + PrintStream oldout = System.out; + System.setOut(new PrintStream(bo)); + Context c = Context.fromJAAS("client"); + System.setOut(oldout); + + int count = 2; + String[] lines = new String(bo.toByteArray()).split("\n"); + System.out.println("----------------- TEST -----------------"); + for (String line: lines) { + if (line.startsWith(">>> KDCCommunication")) { + System.out.println(line); + count--; + if (line.indexOf(proto) < 0) { + throw new Exception("Wrong timeout value"); + } + } + } + if (count != 0) { + throw new Exception("Retry count is " + count + " less"); + } + } + + /** + * Set udp_preference_limit for global and realm + */ + private static void rewriteUdpPrefLimit(int global, int realm) + throws Exception { + BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF)); + FileWriter fw = new FileWriter("alternative-krb5.conf"); + while (true) { + String s = fr.readLine(); + if (s == null) { + break; + } + if (s.startsWith("[realms]")) { + // Reconfig global setting + if (global != -1) { + fw.write("udp_preference_limit = " + global + "\n"); + } + } else if (s.trim().startsWith("kdc = ")) { + if (realm != -1) { + // Reconfig for realm + fw.write(" udp_preference_limit = " + realm + "\n"); + } + } + fw.write(s + "\n"); + } + fr.close(); + fw.close(); + sun.security.krb5.Config.refresh(); + } + + /** + * Set max_retries and timeout value for realm. The global value is always + * 2 and 5000. + * @param value max_retries and timeout/1000 for a realm, -1 means none. + */ + private static void rewriteMaxRetries(int value) throws Exception { + BufferedReader fr = new BufferedReader(new FileReader(OneKDC.KRB5_CONF)); + FileWriter fw = new FileWriter("alternative-krb5.conf"); + while (true) { + String s = fr.readLine(); + if (s == null) { + break; + } + if (s.startsWith("[realms]")) { + // Reconfig global setting + fw.write("max_retries = 2\n"); + fw.write("kdc_timeout = 5000\n"); + } else if (s.trim().startsWith("kdc = ")) { + if (value != -1) { + // Reconfig for realm + fw.write(" max_retries = " + value + "\n"); + fw.write(" kdc_timeout = " + (value*1000) + "\n"); + } + // Add a bad KDC as the first candidate + fw.write(" kdc = localhost:33333\n"); + } + fw.write(s + "\n"); + } + fr.close(); + fw.close(); + sun.security.krb5.Config.refresh(); + } +} From ac7a6db631d1bb905a0be8b53eafb29cc3a85286 Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Thu, 29 Apr 2010 18:38:25 +0400 Subject: [PATCH 09/23] 6899413: Fix for CR #6878399 should be refactored Reviewed-by: peterz --- .../classes/javax/swing/JEditorPane.java | 15 +++-- jdk/src/share/classes/javax/swing/JList.java | 24 +++---- jdk/src/share/classes/javax/swing/JTable.java | 21 ++++--- .../share/classes/javax/swing/JTextField.java | 2 +- jdk/src/share/classes/javax/swing/JTree.java | 12 ++-- .../classes/javax/swing/SwingUtilities.java | 63 +++++++++---------- .../javax/swing/text/JTextComponent.java | 12 ++-- 7 files changed, 70 insertions(+), 79 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JEditorPane.java b/jdk/src/share/classes/javax/swing/JEditorPane.java index eaf61f1e60e..acd825c1d96 100644 --- a/jdk/src/share/classes/javax/swing/JEditorPane.java +++ b/jdk/src/share/classes/javax/swing/JEditorPane.java @@ -1330,8 +1330,9 @@ public class JEditorPane extends JTextComponent { */ public Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; TextUI ui = getUI(); int prefWidth = d.width; int prefHeight = d.height; @@ -1452,8 +1453,9 @@ public class JEditorPane extends JTextComponent { * match its own, false otherwise */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; TextUI ui = getUI(); int w = port.getWidth(); Dimension min = ui.getMinimumSize(this); @@ -1474,8 +1476,9 @@ public class JEditorPane extends JTextComponent { * false otherwise */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; TextUI ui = getUI(); int h = port.getHeight(); Dimension min = ui.getMinimumSize(this); diff --git a/jdk/src/share/classes/javax/swing/JList.java b/jdk/src/share/classes/javax/swing/JList.java index 8a86bda547d..10aa3adf93d 100644 --- a/jdk/src/share/classes/javax/swing/JList.java +++ b/jdk/src/share/classes/javax/swing/JList.java @@ -25,17 +25,7 @@ package javax.swing; -import java.awt.Color; -import java.awt.Component; -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.GraphicsEnvironment; -import java.awt.HeadlessException; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; +import java.awt.*; import java.awt.event.*; import java.util.Vector; @@ -2779,9 +2769,9 @@ public class JList extends JComponent implements Scrollable, Accessible getVisibleRowCount() <= 0) { return true; } - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return port.getWidth() > getPreferredSize().width; + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getWidth() > getPreferredSize().width; } return false; } @@ -2805,9 +2795,9 @@ public class JList extends JComponent implements Scrollable, Accessible getVisibleRowCount() <= 0) { return true; } - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return port.getHeight() > getPreferredSize().height; + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getHeight() > getPreferredSize().height; } return false; } diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index 236e59102c1..09157ca93f8 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -719,8 +719,9 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #addNotify */ protected void configureEnclosingScrollPane() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; Container gp = port.getParent(); if (gp instanceof JScrollPane) { JScrollPane scrollPane = (JScrollPane)gp; @@ -752,8 +753,9 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * from configureEnclosingScrollPane() and updateUI() in a safe manor. */ private void configureEnclosingScrollPaneUI() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; Container gp = port.getParent(); if (gp instanceof JScrollPane) { JScrollPane scrollPane = (JScrollPane)gp; @@ -822,8 +824,9 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @since 1.3 */ protected void unconfigureEnclosingScrollPane() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + JViewport port = (JViewport) parent; Container gp = port.getParent(); if (gp instanceof JScrollPane) { JScrollPane scrollPane = (JScrollPane)gp; @@ -5217,10 +5220,10 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @see #getFillsViewportHeight */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities.getParentViewport(this); + Container parent = SwingUtilities.getUnwrappedParent(this); return getFillsViewportHeight() - && port != null - && port.getHeight() > getPreferredSize().height; + && parent instanceof JViewport + && parent.getHeight() > getPreferredSize().height; } /** diff --git a/jdk/src/share/classes/javax/swing/JTextField.java b/jdk/src/share/classes/javax/swing/JTextField.java index 24a3408d1b4..e1e6b640c65 100644 --- a/jdk/src/share/classes/javax/swing/JTextField.java +++ b/jdk/src/share/classes/javax/swing/JTextField.java @@ -292,7 +292,7 @@ public class JTextField extends JTextComponent implements SwingConstants { */ @Override public boolean isValidateRoot() { - return SwingUtilities.getParentViewport(this) == null; + return !(SwingUtilities.getUnwrappedParent(this) instanceof JViewport); } diff --git a/jdk/src/share/classes/javax/swing/JTree.java b/jdk/src/share/classes/javax/swing/JTree.java index 55815b81dc2..788aeab1fc1 100644 --- a/jdk/src/share/classes/javax/swing/JTree.java +++ b/jdk/src/share/classes/javax/swing/JTree.java @@ -3498,9 +3498,9 @@ public class JTree extends JComponent implements Scrollable, Accessible * @see Scrollable#getScrollableTracksViewportWidth */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return port.getWidth() > getPreferredSize().width; + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getWidth() > getPreferredSize().width; } return false; } @@ -3515,9 +3515,9 @@ public class JTree extends JComponent implements Scrollable, Accessible * @see Scrollable#getScrollableTracksViewportHeight */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return port.getHeight() > getPreferredSize().height; + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getHeight() > getPreferredSize().height; } return false; } diff --git a/jdk/src/share/classes/javax/swing/SwingUtilities.java b/jdk/src/share/classes/javax/swing/SwingUtilities.java index 1221c4bce74..65b267eb8f3 100644 --- a/jdk/src/share/classes/javax/swing/SwingUtilities.java +++ b/jdk/src/share/classes/javax/swing/SwingUtilities.java @@ -1969,58 +1969,53 @@ public class SwingUtilities implements SwingConstants } /** - * Looks for the first ancestor of the {@code component} + * Returns the first ancestor of the {@code component} * which is not an instance of {@link JLayer}. - * If this ancestor is an instance of {@code JViewport}, - * this {@code JViewport} is returned, otherwise returns {@code null}. - * The following way of obtaining the parent {@code JViewport} - * is not recommended any more: - *

-     * JViewport port = null;
-     * Container parent = component.getParent();
-     * // not recommended any more
-     * if(parent instanceof JViewport) {
-     *     port = (JViewport) parent;
-     * }
-     * 
- * Here is the way to go: - *
-     * // the correct way:
-     * JViewport port = SwingUtilities.getParentViewport(component);
-     * 
- * @param component {@code Component} to get the parent {@code JViewport} of. - * @return the {@code JViewport} instance for the {@code component} - * or {@code null} + * + * @param component {@code Component} to get + * the first ancestor of, which is not a {@link JLayer} instance. + * + * @return the first ancestor of the {@code component} + * which is not an instance of {@link JLayer}. + * If such an ancestor can not be found, {@code null} is returned. + * * @throws NullPointerException if {@code component} is {@code null} + * @see JLayer * * @since 1.7 */ - public static JViewport getParentViewport(Component component) { - do { - component = component.getParent(); - if (component instanceof JViewport) { - return (JViewport) component; - } - } while(component instanceof JLayer); - return null; + public static Container getUnwrappedParent(Component component) { + Container parent = component.getParent(); + while(parent instanceof JLayer) { + parent = parent.getParent(); + } + return parent; } /** * Returns the first {@code JViewport}'s descendant - * which is not an instance of {@code JLayer} or {@code null}. + * which is not an instance of {@code JLayer}. + * If such a descendant can not be found, {@code null} is returned. * * If the {@code viewport}'s view component is not a {@code JLayer}, - * this method is equal to {@link JViewport#getView()} - * otherwise {@link JLayer#getView()} will be recursively tested + * this method is equivalent to {@link JViewport#getView()} + * otherwise {@link JLayer#getView()} will be recursively + * called on all descending {@code JLayer}s. + * + * @param viewport {@code JViewport} to get the first descendant of, + * which in not a {@code JLayer} instance. * * @return the first {@code JViewport}'s descendant - * which is not an instance of {@code JLayer} or {@code null}. + * which is not an instance of {@code JLayer}. + * If such a descendant can not be found, {@code null} is returned. * * @throws NullPointerException if {@code viewport} is {@code null} * @see JViewport#getView() * @see JLayer + * + * @since 1.7 */ - static Component getUnwrappedView(JViewport viewport) { + public static Component getUnwrappedView(JViewport viewport) { Component view = viewport.getView(); while (view instanceof JLayer) { view = ((JLayer)view).getView(); diff --git a/jdk/src/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/share/classes/javax/swing/text/JTextComponent.java index 25ddaf9e3cc..832c6095ec2 100644 --- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java @@ -2069,9 +2069,9 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * width to match its own */ public boolean getScrollableTracksViewportWidth() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return port.getWidth() > getPreferredSize().width; + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getWidth() > getPreferredSize().width; } return false; } @@ -2090,9 +2090,9 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * to match its own */ public boolean getScrollableTracksViewportHeight() { - JViewport port = SwingUtilities.getParentViewport(this); - if (port != null) { - return (port.getHeight() > getPreferredSize().height); + Container parent = SwingUtilities.getUnwrappedParent(this); + if (parent instanceof JViewport) { + return parent.getHeight() > getPreferredSize().height; } return false; } From 98a42c6444e70321355a2153f2979d9271ef6982 Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Thu, 29 Apr 2010 18:56:26 +0400 Subject: [PATCH 10/23] 6899453: Remove unnecessary methods from LayerUI Reviewed-by: peterz --- .../classes/javax/swing/plaf/LayerUI.java | 62 ++----------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java index 7f2967bf465..e088db33738 100644 --- a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java @@ -72,53 +72,13 @@ public class LayerUI * the specified {@code Graphics} object to * render the content of the component. *

- * If {@code g} is not an instance of {@code Graphics2D}, - * this method is no-op. + * The default implementation paints the passed component as is. * - * @param g the {@code Graphics} context in which to paint; - * @param c the component being painted; - * it can be safely cast to {@code JLayer} - * - * @see #configureGraphics(Graphics2D, JLayer) - * @see #paintLayer(Graphics2D, JLayer) + * @param g the {@code Graphics} context in which to paint + * @param c the component being painted */ public void paint(Graphics g, JComponent c) { - if (g instanceof Graphics2D) { - Graphics2D g2 = (Graphics2D) g.create(); - JLayer l = (JLayer) c; - configureGraphics(g2, l); - paintLayer(g2, l); - g2.dispose(); - } - } - - /** - * This method is called by the {@link #paint} method prior to - * {@link #paintLayer} to configure the {@code Graphics2D} object. - * The default implementation is empty. - * - * @param g2 the {@code Graphics2D} object to configure - * @param l the {@code JLayer} being painted - * - * @see #paintLayer(Graphics2D, JLayer) - */ - protected void configureGraphics(Graphics2D g2, JLayer l) { - } - - /** - * Called by the {@link #paint} method, - * subclasses should override this method - * to perform any custom painting operations. - *

- * The default implementation paints the passed {@code JLayer} as is. - * - * @param g2 the {@code Graphics2D} context in which to paint - * @param l the {@code JLayer} being painted - * - * @see #configureGraphics(Graphics2D, JLayer) - */ - protected void paintLayer(Graphics2D g2, JLayer l) { - l.paint(g2); + c.paint(g); } /** @@ -627,17 +587,6 @@ public class LayerUI propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } - /** - * Repaints all {@code JLayer} instances this {@code LayerUI} is set to. - * Call this method when the state of this {@code LayerUI} is changed - * and the visual appearance of its {@code JLayer} objects needs to be updated. - * - * @see Component#repaint() - */ - protected void repaintLayer() { - firePropertyChange("dirty", null, null); - } - /** * Notifies the {@code LayerUI} when any of its property are changed * and enables updating every {@code JLayer} @@ -647,9 +596,6 @@ public class LayerUI * @param l the {@code JLayer} this LayerUI is set to */ public void applyPropertyChange(PropertyChangeEvent evt, JLayer l) { - if ("dirty".equals(evt.getPropertyName())) { - l.repaint(); - } } /** From 16e7bb5c198f60d9d0ae7643c3b3f7b21df87127 Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Thu, 29 Apr 2010 19:07:26 +0400 Subject: [PATCH 11/23] 6899405: Specification for JLayer.setLayerEventMask() should mention that eventDispatch() might not be called Reviewed-by: peterz --- jdk/src/share/classes/javax/swing/JLayer.java | 60 ++++++++----------- .../classes/javax/swing/plaf/LayerUI.java | 9 +-- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/JLayer.java b/jdk/src/share/classes/javax/swing/JLayer.java index 93f4b799722..ab082cfc588 100644 --- a/jdk/src/share/classes/javax/swing/JLayer.java +++ b/jdk/src/share/classes/javax/swing/JLayer.java @@ -163,18 +163,6 @@ public final class JLayer private static final LayerEventController eventController = new LayerEventController(); - private static final long ACCEPTED_EVENTS = - AWTEvent.COMPONENT_EVENT_MASK | - AWTEvent.CONTAINER_EVENT_MASK | - AWTEvent.FOCUS_EVENT_MASK | - AWTEvent.KEY_EVENT_MASK | - AWTEvent.MOUSE_WHEEL_EVENT_MASK | - AWTEvent.MOUSE_MOTION_EVENT_MASK | - AWTEvent.MOUSE_EVENT_MASK | - AWTEvent.INPUT_METHOD_EVENT_MASK | - AWTEvent.HIERARCHY_EVENT_MASK | - AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; - /** * Creates a new {@code JLayer} object with a {@code null} view component * and {@code null} {@link javax.swing.plaf.LayerUI}. @@ -396,24 +384,14 @@ public final class JLayer } /** - * Sets the bitmask of event types to receive by this {@code JLayer}. - * Here is the list of the supported event types: - *

    - *
  • AWTEvent.COMPONENT_EVENT_MASK
  • - *
  • AWTEvent.CONTAINER_EVENT_MASK
  • - *
  • AWTEvent.FOCUS_EVENT_MASK
  • - *
  • AWTEvent.KEY_EVENT_MASK
  • - *
  • AWTEvent.MOUSE_WHEEL_EVENT_MASK
  • - *
  • AWTEvent.MOUSE_MOTION_EVENT_MASK
  • - *
  • AWTEvent.MOUSE_EVENT_MASK
  • - *
  • AWTEvent.INPUT_METHOD_EVENT_MASK
  • - *
  • AWTEvent.HIERARCHY_EVENT_MASK
  • - *
  • AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK
  • - *
+ * Enables the events from JLayer and all its descendants + * defined by the specified event mask parameter + * to be delivered to the + * {@link LayerUI#eventDispatched(AWTEvent, JLayer)} method. *

- * If {@code LayerUI} is installed, - * {@link javax.swing.plaf.LayerUI#eventDispatched(AWTEvent, JLayer)} method - * will only receive events that match the event mask. + * Events are delivered provided that {@code LayerUI} is set + * for this {@code JLayer} and the {@code JLayer} + * is displayable. *

* The following example shows how to correclty use this method * in the {@code LayerUI} implementations: @@ -433,19 +411,15 @@ public final class JLayer * } * * - * By default {@code JLayer} receives no events. + * By default {@code JLayer} receives no events and its event mask is {@code 0}. * * @param layerEventMask the bitmask of event types to receive * - * @throws IllegalArgumentException if the {@code layerEventMask} parameter - * contains unsupported event types * @see #getLayerEventMask() + * @see LayerUI#eventDispatched(AWTEvent, JLayer) + * @see Component#isDisplayable() */ public void setLayerEventMask(long layerEventMask) { - if (layerEventMask != (layerEventMask & ACCEPTED_EVENTS)) { - throw new IllegalArgumentException( - "The event bitmask contains unsupported event types"); - } long oldEventMask = getLayerEventMask(); this.eventMask = layerEventMask; firePropertyChange("layerEventMask", oldEventMask, layerEventMask); @@ -629,6 +603,18 @@ public final class JLayer private long currentEventMask; + private static final long ACCEPTED_EVENTS = + AWTEvent.COMPONENT_EVENT_MASK | + AWTEvent.CONTAINER_EVENT_MASK | + AWTEvent.FOCUS_EVENT_MASK | + AWTEvent.KEY_EVENT_MASK | + AWTEvent.MOUSE_WHEEL_EVENT_MASK | + AWTEvent.MOUSE_MOTION_EVENT_MASK | + AWTEvent.MOUSE_EVENT_MASK | + AWTEvent.INPUT_METHOD_EVENT_MASK | + AWTEvent.HIERARCHY_EVENT_MASK | + AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; + @SuppressWarnings("unchecked") public void eventDispatched(AWTEvent event) { Object source = event.getSource(); @@ -660,6 +646,8 @@ public final class JLayer for (Long mask : layerMaskList) { combinedMask |= mask; } + // filter out all unaccepted events + combinedMask &= ACCEPTED_EVENTS; if (combinedMask == 0) { removeAWTEventListener(); } else if (getCurrentEventMask() != combinedMask) { diff --git a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java index e088db33738..07df96cd411 100644 --- a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java @@ -82,8 +82,8 @@ public class LayerUI } /** - * Dispatches {@code AWTEvent}s for {@code JLayer} - * and all its subcomponents to this {@code LayerUI} instance. + * Processes {@code AWTEvent}s for {@code JLayer} + * and all its descendants to this {@code LayerUI} instance. *

* To enable the {@code AWTEvent}s of a particular type, * you call {@link JLayer#setLayerEventMask} @@ -93,13 +93,14 @@ public class LayerUI * By default this method calls the appropriate * {@code process<event type>Event} * method for the given class of event. + *

+ * Note: Events are processed only for displayable {@code JLayer}s. * * @param e the event to be dispatched * @param l the layer this LayerUI is set to * * @see JLayer#setLayerEventMask(long) - * @see #installUI(javax.swing.JComponent) - * @see #uninstallUI(javax.swing.JComponent) + * @see Component#isDisplayable() * @see #processComponentEvent * @see #processFocusEvent * @see #processKeyEvent From e3e5b8ad72dab169c4353988d3ffb9f2c7a44c89 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Wed, 5 May 2010 13:18:31 +0100 Subject: [PATCH 12/23] 6886723: light weight http server doesn't return correct status code for HEAD requests Reviewed-by: michaelm --- .../sun/net/httpserver/ExchangeImpl.java | 54 +++++--- .../com/sun/net/httpserver/bugs/HeadTest.java | 117 ++++++++++++++++++ 2 files changed, 151 insertions(+), 20 deletions(-) create mode 100644 jdk/test/com/sun/net/httpserver/bugs/HeadTest.java diff --git a/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java b/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java index ccb9151b69c..69ed824f67f 100644 --- a/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java +++ b/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java @@ -26,16 +26,12 @@ package sun.net.httpserver; import java.io.*; -import java.nio.*; -import java.nio.channels.*; import java.net.*; import javax.net.ssl.*; import java.util.*; import java.util.logging.Logger; import java.text.*; -import sun.net.www.MessageHeader; import com.sun.net.httpserver.*; -import com.sun.net.httpserver.spi.*; class ExchangeImpl { @@ -65,6 +61,8 @@ class ExchangeImpl { df.setTimeZone (tz); } + private static final String HEAD = "HEAD"; + /* streams which take care of the HTTP protocol framing * and are passed up to higher layers */ @@ -116,6 +114,10 @@ class ExchangeImpl { return connection.getHttpContext(); } + private boolean isHeadRequest() { + return HEAD.equals(getRequestMethod()); + } + public void close () { if (closed) { return; @@ -220,24 +222,36 @@ class ExchangeImpl { } contentLen = -1; } - if (contentLen == 0) { - if (http10) { - o.setWrappedStream (new UndefLengthOutputStream (this, ros)); - close = true; + + if (isHeadRequest()) { + /* HEAD requests should not set a content length by passing it + * through this API, but should instead manually set the required + * headers.*/ + if (contentLen >= 0) { + final Logger logger = server.getLogger(); + String msg = + "sendResponseHeaders: being invoked with a content length for a HEAD request"; + logger.warning (msg); + } + noContentToSend = true; + contentLen = 0; + } else { /* not a HEAD request */ + if (contentLen == 0) { + if (http10) { + o.setWrappedStream (new UndefLengthOutputStream (this, ros)); + close = true; + } else { + rspHdrs.set ("Transfer-encoding", "chunked"); + o.setWrappedStream (new ChunkedOutputStream (this, ros)); + } } else { - rspHdrs.set ("Transfer-encoding", "chunked"); - o.setWrappedStream (new ChunkedOutputStream (this, ros)); + if (contentLen == -1) { + noContentToSend = true; + contentLen = 0; + } + rspHdrs.set("Content-length", Long.toString(contentLen)); + o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen)); } - } else { - if (contentLen == -1) { - noContentToSend = true; - contentLen = 0; - } - /* content len might already be set, eg to implement HEAD resp */ - if (rspHdrs.getFirst ("Content-length") == null) { - rspHdrs.set ("Content-length", Long.toString(contentLen)); - } - o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen)); } write (rspHdrs, tmpout); this.rspContentLen = contentLen; diff --git a/jdk/test/com/sun/net/httpserver/bugs/HeadTest.java b/jdk/test/com/sun/net/httpserver/bugs/HeadTest.java new file mode 100644 index 00000000000..8b7055338a1 --- /dev/null +++ b/jdk/test/com/sun/net/httpserver/bugs/HeadTest.java @@ -0,0 +1,117 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6886723 + * @summary light weight http server doesn't return correct status code for HEAD requests + */ + +import java.net.InetSocketAddress; +import java.net.HttpURLConnection; +import java.net.URL; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +public class HeadTest { + + public static void main(String[] args) throws Exception { + server(); + } + + static void server() throws Exception { + InetSocketAddress inetAddress = new InetSocketAddress(0); + HttpServer server = HttpServer.create(inetAddress, 5); + try { + server.setExecutor(Executors.newFixedThreadPool(5)); + HttpContext chunkedContext = server.createContext("/chunked"); + chunkedContext.setHandler(new HttpHandler() { + @Override + public void handle(HttpExchange msg) { + try { + try { + if (msg.getRequestMethod().equals("HEAD")) { + msg.getRequestBody().close(); + msg.getResponseHeaders().add("Transfer-encoding", "chunked"); + msg.sendResponseHeaders(200, -1); + } + } catch(IOException ioe) { + ioe.printStackTrace(); + } + } finally { + msg.close(); + } + } + }); + HttpContext clContext = server.createContext("/content"); + clContext.setHandler(new HttpHandler() { + @Override + public void handle(HttpExchange msg) { + try { + try { + if (msg.getRequestMethod().equals("HEAD")) { + msg.getRequestBody().close(); + msg.getResponseHeaders().add("Content-length", "1024"); + msg.sendResponseHeaders(200, -1); + } + } catch(IOException ioe) { + ioe.printStackTrace(); + } + } finally { + msg.close(); + } + } + }); + server.start(); + String urlStr = "http://localhost:" + server.getAddress().getPort() + "/"; + System.out.println("Server is at " + urlStr); + + // Run the chunked client + for(int i=0; i < 10; i++) { + runClient(urlStr + "chunked/"); + } + // Run the content length client + for(int i=0; i < 10; i++) { + runClient(urlStr + "content/"); + } + } finally { + // Stop the server + ((ExecutorService)server.getExecutor()).shutdown(); + server.stop(0); + } + } + + static void runClient(String urlStr) throws Exception { + HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection(); + conn.setRequestMethod("HEAD"); + int status = conn.getResponseCode(); + if (status != 200) { + throw new RuntimeException("HEAD request doesn't return 200, but returns " + status); + } + } +} From a94d06f6b77fe7384c8c47b47022115c71bb41d3 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 6 May 2010 11:26:16 +0800 Subject: [PATCH 13/23] 6948909: Jarsigner removes MANIFEST.MF info for badly packages jar's Reviewed-by: mullan, xuelei --- .../classes/sun/security/tools/JarSigner.java | 99 ++++++++------- .../sun/security/tools/jarsigner/diffend.sh | 113 ++++++++++++++++++ 2 files changed, 172 insertions(+), 40 deletions(-) create mode 100644 jdk/test/sun/security/tools/jarsigner/diffend.sh diff --git a/jdk/src/share/classes/sun/security/tools/JarSigner.java b/jdk/src/share/classes/sun/security/tools/JarSigner.java index 5c824c5712f..0f7324d7c19 100644 --- a/jdk/src/share/classes/sun/security/tools/JarSigner.java +++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. 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 @@ -1123,6 +1123,8 @@ public class JarSigner { BASE64Encoder encoder = new JarBASE64Encoder(); Vector mfFiles = new Vector(); + boolean wasSigned = false; + for (Enumeration enum_=zipFile.entries(); enum_.hasMoreElements();) { ZipEntry ze = enum_.nextElement(); @@ -1132,6 +1134,11 @@ public class JarSigner { // out first mfFiles.addElement(ze); + if (SignatureFileVerifier.isBlockOrSF( + ze.getName().toUpperCase(Locale.ENGLISH))) { + wasSigned = true; + } + if (signatureRelated(ze.getName())) { // ignore signature-related and manifest files continue; @@ -1159,37 +1166,41 @@ public class JarSigner { if (mfModified) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); manifest.write(baos); - byte[] newBytes = baos.toByteArray(); - if (mfRawBytes != null - && oldAttr.equals(manifest.getMainAttributes())) { + if (wasSigned) { + byte[] newBytes = baos.toByteArray(); + if (mfRawBytes != null + && oldAttr.equals(manifest.getMainAttributes())) { - /* - * Note: - * - * The Attributes object is based on HashMap and can handle - * continuation columns. Therefore, even if the contents are - * not changed (in a Map view), the bytes that it write() - * may be different from the original bytes that it read() - * from. Since the signature on the main attributes is based - * on raw bytes, we must retain the exact bytes. - */ + /* + * Note: + * + * The Attributes object is based on HashMap and can handle + * continuation columns. Therefore, even if the contents are + * not changed (in a Map view), the bytes that it write() + * may be different from the original bytes that it read() + * from. Since the signature on the main attributes is based + * on raw bytes, we must retain the exact bytes. + */ - int newPos = findHeaderEnd(newBytes); - int oldPos = findHeaderEnd(mfRawBytes); + int newPos = findHeaderEnd(newBytes); + int oldPos = findHeaderEnd(mfRawBytes); - if (newPos == oldPos) { - System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos); - } else { - // cat oldHead newTail > newBytes - byte[] lastBytes = new byte[oldPos + - newBytes.length - newPos]; - System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos); - System.arraycopy(newBytes, newPos, lastBytes, oldPos, - newBytes.length - newPos); - newBytes = lastBytes; + if (newPos == oldPos) { + System.arraycopy(mfRawBytes, 0, newBytes, 0, oldPos); + } else { + // cat oldHead newTail > newBytes + byte[] lastBytes = new byte[oldPos + + newBytes.length - newPos]; + System.arraycopy(mfRawBytes, 0, lastBytes, 0, oldPos); + System.arraycopy(newBytes, newPos, lastBytes, oldPos, + newBytes.length - newPos); + newBytes = lastBytes; + } } + mfRawBytes = newBytes; + } else { + mfRawBytes = baos.toByteArray(); } - mfRawBytes = newBytes; } // Write out the manifest @@ -1411,23 +1422,31 @@ public class JarSigner { } /** - * Find the position of an empty line inside bs + * Find the length of header inside bs. The header is a multiple (>=0) + * lines of attributes plus an empty line. The empty line is included + * in the header. */ private int findHeaderEnd(byte[] bs) { - // An empty line can be at the beginning... - if (bs.length > 1 && bs[0] == '\r' && bs[1] == '\n') { - return 0; - } - // ... or after another line - for (int i=0; i 1 +mkdir META-INF + +# Create a fake .RSA file so that jarsigner believes it's signed + +touch META-INF/x.RSA + +# A MANIFEST.MF using \n as newlines and no double newlines at the end + +cat > META-INF/MANIFEST.MF < Date: Thu, 6 May 2010 13:42:52 +0800 Subject: [PATCH 14/23] 6890876: jarsigner can add CRL info into signed jar Reviewed-by: mullan --- .../jarsigner/ContentSignerParameters.java | 11 +- .../classes/java/security/CodeSigner.java | 44 +- .../classes/java/util/jar/JarVerifier.java | 3 +- .../misc/JavaSecurityCodeSignerAccess.java | 33 ++ .../share/classes/sun/misc/SharedSecrets.java | 15 +- .../classes/sun/security/pkcs/PKCS7.java | 40 +- .../classes/sun/security/tools/JarSigner.java | 79 +++- .../security/tools/JarSignerResources.java | 5 +- .../classes/sun/security/tools/KeyTool.java | 384 ++++++++++++++++-- .../sun/security/tools/TimestampedSigner.java | 3 +- .../classes/sun/security/util/Resources.java | 9 +- .../security/util/SignatureFileVerifier.java | 12 +- .../sun/security/x509/X509CRLImpl.java | 11 +- jdk/test/sun/security/tools/jarsigner/crl.sh | 91 +++++ 14 files changed, 683 insertions(+), 57 deletions(-) create mode 100644 jdk/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java create mode 100644 jdk/test/sun/security/tools/jarsigner/crl.sh diff --git a/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java b/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java index 5ef30e031fa..942d29070da 100644 --- a/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java +++ b/jdk/src/share/classes/com/sun/jarsigner/ContentSignerParameters.java @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. 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 @@ -26,7 +26,9 @@ package com.sun.jarsigner; import java.net.URI; +import java.security.cert.X509CRL; import java.security.cert.X509Certificate; +import java.util.Set; import java.util.zip.ZipFile; /** @@ -80,6 +82,13 @@ public interface ContentSignerParameters { */ public X509Certificate[] getSignerCertificateChain(); + /** + * Retrieves the signer's X.509 CRLs. + * + * @return An unmodifiable set of X.509 CRLs (never null) + */ + public Set getCRLs(); + /** * Retrieves the content that was signed. * The content is the JAR file's signature file. diff --git a/jdk/src/share/classes/java/security/CodeSigner.java b/jdk/src/share/classes/java/security/CodeSigner.java index a5ef70b7dce..b7abdf06fb8 100644 --- a/jdk/src/share/classes/java/security/CodeSigner.java +++ b/jdk/src/share/classes/java/security/CodeSigner.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2010 Sun Microsystems, Inc. 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 @@ -26,7 +26,10 @@ package java.security; import java.io.Serializable; +import java.security.cert.CRL; import java.security.cert.CertPath; +import sun.misc.JavaSecurityCodeSignerAccess; +import sun.misc.SharedSecrets; /** * This class encapsulates information about a code signer. @@ -163,4 +166,43 @@ public final class CodeSigner implements Serializable { sb.append(")"); return sb.toString(); } + + // A private attribute attached to this CodeSigner object. Can be accessed + // through SharedSecrets.getJavaSecurityCodeSignerAccess().[g|s]etCRLs + // + // Currently called in SignatureFileVerifier.getSigners + private transient CRL[] crls; + + /** + * Sets the CRLs attached + * @param crls, null to clear + */ + void setCRLs(CRL[] crls) { + this.crls = crls; + } + + /** + * Returns the CRLs attached + * @return the crls, initially null + */ + CRL[] getCRLs() { + return crls; + } + + // Set up JavaSecurityCodeSignerAccess in SharedSecrets + static { + SharedSecrets.setJavaSecurityCodeSignerAccess( + new JavaSecurityCodeSignerAccess() { + @Override + public void setCRLs(CodeSigner signer, CRL[] crls) { + signer.setCRLs(crls); + } + + @Override + public CRL[] getCRLs(CodeSigner signer) { + return signer.getCRLs(); + } + }); + } + } diff --git a/jdk/src/share/classes/java/util/jar/JarVerifier.java b/jdk/src/share/classes/java/util/jar/JarVerifier.java index a4ceaa790fd..1c88d226e28 100644 --- a/jdk/src/share/classes/java/util/jar/JarVerifier.java +++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. 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 @@ -27,7 +27,6 @@ package java.util.jar; import java.io.*; import java.util.*; -import java.util.zip.*; import java.security.*; import java.security.cert.CertificateException; diff --git a/jdk/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java b/jdk/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java new file mode 100644 index 00000000000..4543b00da5f --- /dev/null +++ b/jdk/src/share/classes/sun/misc/JavaSecurityCodeSignerAccess.java @@ -0,0 +1,33 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package sun.misc; + +import java.security.CodeSigner; +import java.security.cert.CRL; + +public interface JavaSecurityCodeSignerAccess { + void setCRLs(CodeSigner signer, CRL[] crls); + CRL[] getCRLs(CodeSigner signer); +} diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java index c9f50728860..76ae42f673a 100644 --- a/jdk/src/share/classes/sun/misc/SharedSecrets.java +++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java @@ -27,8 +27,8 @@ package sun.misc; import java.util.jar.JarFile; import java.io.Console; -import java.io.File; import java.io.FileDescriptor; +import java.security.CodeSigner; import java.security.ProtectionDomain; /** A repository of "shared secrets", which are a mechanism for @@ -49,6 +49,7 @@ public class SharedSecrets { private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess; + private static JavaSecurityCodeSignerAccess javaSecurityCodeSignerAccess; public static JavaUtilJarAccess javaUtilJarAccess() { if (javaUtilJarAccess == null) { @@ -126,4 +127,16 @@ public class SharedSecrets { unsafe.ensureClassInitialized(ProtectionDomain.class); return javaSecurityProtectionDomainAccess; } + + public static void setJavaSecurityCodeSignerAccess + (JavaSecurityCodeSignerAccess jscsa) { + javaSecurityCodeSignerAccess = jscsa; + } + + public static JavaSecurityCodeSignerAccess + getJavaSecurityCodeSignerAccess() { + if (javaSecurityCodeSignerAccess == null) + unsafe.ensureClassInitialized(CodeSigner.class); + return javaSecurityCodeSignerAccess; + } } diff --git a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java index 1a1bcf41cf2..d3342fdb2b5 100644 --- a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java +++ b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2010 Sun Microsystems, Inc. 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 @@ -28,7 +28,6 @@ package sun.security.pkcs; import java.io.*; import java.math.BigInteger; import java.util.*; -import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.security.cert.X509CRL; @@ -173,20 +172,30 @@ public class PKCS7 { * @param digestAlgorithmIds the message digest algorithm identifiers. * @param contentInfo the content information. * @param certificates an array of X.509 certificates. + * @param crls an array of CRLs * @param signerInfos an array of signer information. */ public PKCS7(AlgorithmId[] digestAlgorithmIds, ContentInfo contentInfo, X509Certificate[] certificates, + X509CRL[] crls, SignerInfo[] signerInfos) { version = BigInteger.ONE; this.digestAlgorithmIds = digestAlgorithmIds; this.contentInfo = contentInfo; this.certificates = certificates; + this.crls = crls; this.signerInfos = signerInfos; } + public PKCS7(AlgorithmId[] digestAlgorithmIds, + ContentInfo contentInfo, + X509Certificate[] certificates, + SignerInfo[] signerInfos) { + this(digestAlgorithmIds, contentInfo, certificates, null, signerInfos); + } + private void parseNetscapeCertChain(DerValue val) throws ParsingException, IOException { DerInputStream dis = new DerInputStream(val.toByteArray()); @@ -312,7 +321,7 @@ public class PKCS7 { ByteArrayInputStream bais = null; try { if (certfac == null) - crls[i] = (X509CRL) new X509CRLImpl(crlVals[i]); + crls[i] = new X509CRLImpl(crlVals[i]); else { byte[] encoded = crlVals[i].toByteArray(); bais = new ByteArrayInputStream(encoded); @@ -480,7 +489,30 @@ public class PKCS7 { signedData.putOrderedSetOf((byte)0xA0, implCerts); } - // no crls (OPTIONAL field) + // CRLs (optional) + if (crls != null && crls.length != 0) { + // cast to X509CRLImpl[] since X509CRLImpl implements DerEncoder + Set implCRLs = new HashSet(crls.length); + for (X509CRL crl: crls) { + if (crl instanceof X509CRLImpl) + implCRLs.add((X509CRLImpl) crl); + else { + try { + byte[] encoded = crl.getEncoded(); + implCRLs.add(new X509CRLImpl(encoded)); + } catch (CRLException ce) { + IOException ie = new IOException(ce.getMessage()); + ie.initCause(ce); + throw ie; + } + } + } + + // Add the CRL set (tagged with [1] IMPLICIT) + // to the signed data + signedData.putOrderedSetOf((byte)0xA1, + implCRLs.toArray(new X509CRLImpl[implCRLs.size()])); + } // signerInfos signedData.putOrderedSetOf(DerValue.tag_Set, signerInfos); diff --git a/jdk/src/share/classes/sun/security/tools/JarSigner.java b/jdk/src/share/classes/sun/security/tools/JarSigner.java index 0f7324d7c19..f45a2c93157 100644 --- a/jdk/src/share/classes/sun/security/tools/JarSigner.java +++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java @@ -26,6 +26,7 @@ package sun.security.tools; import java.io.*; +import java.security.cert.X509CRL; import java.util.*; import java.util.zip.*; import java.util.jar.*; @@ -35,6 +36,7 @@ import java.net.URISyntaxException; import java.text.Collator; import java.text.MessageFormat; import java.security.cert.Certificate; +import java.security.cert.CRL; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.security.*; @@ -56,6 +58,7 @@ import java.util.Map.Entry; import sun.security.x509.*; import sun.security.util.*; import sun.misc.BASE64Encoder; +import sun.misc.SharedSecrets; /** @@ -114,14 +117,16 @@ public class JarSigner { static final int SIGNED_BY_ALIAS = 0x08; // signer is in alias list X509Certificate[] certChain; // signer's cert chain (when composing) + Set crls; // signer provided CRLs PrivateKey privateKey; // private key KeyStore store; // the keystore specified by -keystore // or the default keystore, never null String keystore; // key store file + List crlfiles = new ArrayList(); // CRL files to add boolean nullStream = false; // null keystore input stream (NONE) boolean token = false; // token-based keystore - String jarfile; // jar file to sign or verify + String jarfile; // jar files to sign or verify String alias; // alias to sign jar with List ckaliases = new ArrayList(); // aliases in -verify char[] storepass; // keystore password @@ -146,6 +151,7 @@ public class JarSigner { boolean signManifest = true; // "sign" the whole manifest boolean externalSF = true; // leave the .SF out of the PKCS7 block boolean strict = false; // treat warnings as error + boolean autoCRL = false; // Automatcially add CRL defined in cert // read zip entry raw bytes private ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); @@ -226,6 +232,29 @@ public class JarSigner { } else { loadKeyStore(keystore, true); getAliasInfo(alias); + crls = new HashSet(); + if (crlfiles.size() > 0 || autoCRL) { + CertificateFactory fac = + CertificateFactory.getInstance("X509"); + List list = new ArrayList(); + for (String file: crlfiles) { + Collection tmp = KeyTool.loadCRLs(file); + for (CRL crl: tmp) { + if (crl instanceof X509CRL) { + crls.add((X509CRL)crl); + } + } + } + if (autoCRL) { + List crlsFromCert = + KeyTool.readCRLsFromCert(certChain[0]); + for (CRL crl: crlsFromCert) { + if (crl instanceof X509CRL) { + crls.add((X509CRL)crl); + } + } + } + } // load the alternative signing mechanism if (altSignerClass != null) { @@ -367,6 +396,13 @@ public class JarSigner { } else if (collator.compare(flags, "-digestalg") ==0) { if (++n == args.length) usageNoArg(); digestalg = args[n]; + } else if (collator.compare(flags, "-crl") ==0) { + if ("auto".equals(modifier)) { + autoCRL = true; + } else { + if (++n == args.length) usageNoArg(); + crlfiles.add(args[n]); + } } else if (collator.compare(flags, "-certs") ==0) { showcerts = true; } else if (collator.compare(flags, "-strict") ==0) { @@ -515,6 +551,9 @@ public class JarSigner { System.out.println(rb.getString ("[-sigalg ] name of signature algorithm")); System.out.println(); + System.out.println(rb.getString + ("[-crl[:auto| ] include CRL in signed jar")); + System.out.println(); System.out.println(rb.getString ("[-verify] verify a signed JAR file")); System.out.println(); @@ -654,6 +693,20 @@ public class JarSigner { if (showcerts) { sb.append(si); sb.append('\n'); + CRL[] crls = SharedSecrets + .getJavaSecurityCodeSignerAccess() + .getCRLs(signer); + if (crls != null) { + for (CRL crl: crls) { + if (crl instanceof X509CRLImpl) { + sb.append(tab).append("["); + sb.append(String.format( + rb.getString("with a CRL including %d entries"), + ((X509CRLImpl)crl).getRevokedCertificates().size())) + .append("]\n"); + } + } + } } } } else if (showcerts && !verbose.equals("all")) { @@ -1233,7 +1286,7 @@ public class JarSigner { try { block = - sf.generateBlock(privateKey, sigalg, certChain, + sf.generateBlock(privateKey, sigalg, certChain, crls, externalSF, tsaUrl, tsaCert, signingMechanism, args, zipFile); } catch (SocketTimeoutException e) { @@ -2197,6 +2250,7 @@ class SignatureFile { public Block generateBlock(PrivateKey privateKey, String sigalg, X509Certificate[] certChain, + Set crls, boolean externalSF, String tsaUrl, X509Certificate tsaCert, ContentSigner signingMechanism, @@ -2204,7 +2258,7 @@ class SignatureFile { throws NoSuchAlgorithmException, InvalidKeyException, IOException, SignatureException, CertificateException { - return new Block(this, privateKey, sigalg, certChain, externalSF, + return new Block(this, privateKey, sigalg, certChain, crls, externalSF, tsaUrl, tsaCert, signingMechanism, args, zipFile); } @@ -2218,7 +2272,8 @@ class SignatureFile { * Construct a new signature block. */ Block(SignatureFile sfg, PrivateKey privateKey, String sigalg, - X509Certificate[] certChain, boolean externalSF, String tsaUrl, + X509Certificate[] certChain, Set crls, + boolean externalSF, String tsaUrl, X509Certificate tsaCert, ContentSigner signingMechanism, String[] args, ZipFile zipFile) throws NoSuchAlgorithmException, InvalidKeyException, IOException, @@ -2305,7 +2360,7 @@ class SignatureFile { // Assemble parameters for the signing mechanism ContentSignerParameters params = new JarSignerParameters(args, tsaUri, tsaCert, signature, - signatureAlgorithm, certChain, content, zipFile); + signatureAlgorithm, certChain, crls, content, zipFile); // Generate the signature block block = signingMechanism.generateSignedData( @@ -2346,6 +2401,7 @@ class JarSignerParameters implements ContentSignerParameters { private byte[] signature; private String signatureAlgorithm; private X509Certificate[] signerCertificateChain; + private Set crls; private byte[] content; private ZipFile source; @@ -2354,7 +2410,8 @@ class JarSignerParameters implements ContentSignerParameters { */ JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate, byte[] signature, String signatureAlgorithm, - X509Certificate[] signerCertificateChain, byte[] content, + X509Certificate[] signerCertificateChain, Set crls, + byte[] content, ZipFile source) { if (signature == null || signatureAlgorithm == null || @@ -2367,6 +2424,7 @@ class JarSignerParameters implements ContentSignerParameters { this.signature = signature; this.signatureAlgorithm = signatureAlgorithm; this.signerCertificateChain = signerCertificateChain; + this.crls = crls; this.content = content; this.source = source; } @@ -2442,4 +2500,13 @@ class JarSignerParameters implements ContentSignerParameters { public ZipFile getSource() { return source; } + + @Override + public Set getCRLs() { + if (crls == null) { + return Collections.emptySet(); + } else { + return Collections.unmodifiableSet(crls); + } + } } diff --git a/jdk/src/share/classes/sun/security/tools/JarSignerResources.java b/jdk/src/share/classes/sun/security/tools/JarSignerResources.java index 7e259e8e8fe..16cc6863b43 100644 --- a/jdk/src/share/classes/sun/security/tools/JarSignerResources.java +++ b/jdk/src/share/classes/sun/security/tools/JarSignerResources.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2010 Sun Microsystems, Inc. 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 @@ -74,6 +74,8 @@ public class JarSignerResources extends java.util.ListResourceBundle { "[-digestalg ] name of digest algorithm"}, {"[-sigalg ] name of signature algorithm", "[-sigalg ] name of signature algorithm"}, + {"[-crl[:auto| ] include CRL in signed jar", + "[-crl[:auto| ] include CRL in signed jar"}, {"[-verify] verify a signed JAR file", "[-verify] verify a signed JAR file"}, {"[-verbose[:suboptions]] verbose output when signing/verifying.", @@ -191,6 +193,7 @@ public class JarSignerResources extends java.util.ListResourceBundle { {"using an alternative signing mechanism", "using an alternative signing mechanism"}, {"entry was signed on", "entry was signed on {0}"}, + {"with a CRL including %d entries", "with a CRL including %d entries"}, {"Warning: ", "Warning: "}, {"This jar contains unsigned entries which have not been integrity-checked. ", "This jar contains unsigned entries which have not been integrity-checked. "}, diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index 2539d43e14b..b799bfaa7fc 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -25,6 +25,7 @@ package sun.security.tools; +import sun.misc.SharedSecrets; import java.io.*; import java.security.CodeSigner; import java.security.KeyStore; @@ -42,6 +43,7 @@ import java.security.Principal; import java.security.Provider; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; +import java.security.cert.CRL; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.text.Collator; @@ -50,14 +52,20 @@ import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.lang.reflect.Constructor; +import java.math.BigInteger; +import java.net.URI; import java.net.URL; import java.net.URLClassLoader; +import java.security.cert.CertStore; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.security.cert.X509CRLSelector; +import javax.security.auth.x500.X500Principal; import sun.misc.BASE64Encoder; import sun.security.util.ObjectIdentifier; import sun.security.pkcs.PKCS10; import sun.security.provider.X509Factory; -import sun.security.util.DerOutputStream; import sun.security.util.Password; import sun.security.util.PathList; import javax.crypto.KeyGenerator; @@ -72,6 +80,7 @@ import javax.net.ssl.X509TrustManager; import sun.misc.BASE64Decoder; import sun.security.pkcs.PKCS10Attribute; import sun.security.pkcs.PKCS9Attribute; +import sun.security.provider.certpath.ldap.LDAPCertStoreHelper; import sun.security.util.DerValue; import sun.security.x509.*; @@ -147,6 +156,7 @@ public final class KeyTool { private Set passwords = new HashSet (); private String startDate = null; + private List ids = new ArrayList (); // used in GENCRL private List v3ext = new ArrayList (); enum Command { @@ -180,9 +190,6 @@ public final class KeyTool { STARTDATE, EXT, VALIDITY, KEYPASS, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V, PROTECTED), - IDENTITYDB("Imports entries from a JDK 1.1.x-style identity database", - FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, - PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), IMPORTCERT("Imports a certificate or a certificate chain", NOPROMPT, TRUSTCACERTS, PROTECTED, ALIAS, FILEIN, KEYPASS, KEYSTORE, STOREPASS, STORETYPE, @@ -195,10 +202,6 @@ public final class KeyTool { SRCALIAS, DESTALIAS, SRCKEYPASS, DESTKEYPASS, NOPROMPT, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), - KEYCLONE("Clones a key entry", - ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE, - KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, - PROVIDERARG, PROVIDERPATH, V), KEYPASSWD("Changes the key password of an entry", ALIAS, KEYPASS, NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, @@ -211,12 +214,29 @@ public final class KeyTool { RFC, FILEIN, SSLSERVER, JARFILE, V), PRINTCERTREQ("Prints the content of a certificate request", FILEIN, V), + PRINTCRL("Prints the content of a CRL file", + FILEIN, V), + STOREPASSWD("Changes the store password of a keystore", + NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, + PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), + + // Undocumented start here, KEYCLONE is used a marker in -help; + + KEYCLONE("Clones a key entry", + ALIAS, DESTALIAS, KEYPASS, NEW, STORETYPE, + KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, + PROVIDERARG, PROVIDERPATH, V), SELFCERT("Generates a self-signed certificate", ALIAS, SIGALG, DNAME, STARTDATE, VALIDITY, KEYPASS, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V), - STOREPASSWD("Changes the store password of a keystore", - NEW, KEYSTORE, STOREPASS, STORETYPE, PROVIDERNAME, + GENCRL("Generates CRL", + RFC, FILEOUT, ID, + ALIAS, SIGALG, EXT, KEYPASS, KEYSTORE, + STOREPASS, STORETYPE, PROVIDERNAME, PROVIDERCLASS, + PROVIDERARG, PROVIDERPATH, V, PROTECTED), + IDENTITYDB("Imports entries from a JDK 1.1.x-style identity database", + FILEIN, STORETYPE, KEYSTORE, STOREPASS, PROVIDERNAME, PROVIDERCLASS, PROVIDERARG, PROVIDERPATH, V); final String description; @@ -244,6 +264,7 @@ public final class KeyTool { EXT("ext", "", "X.509 extension"), FILEOUT("file", "", "output file name"), FILEIN("file", "", "input file name"), + ID("id", "", "Serial ID of cert to revoke"), INFILE("infile", "", "input file name"), KEYALG("keyalg", "", "key algorithm name"), KEYPASS("keypass", "", "key password"), @@ -458,6 +479,8 @@ public final class KeyTool { validity = Long.parseLong(args[++i]); } else if (collator.compare(flags, "-ext") == 0) { v3ext.add(args[++i]); + } else if (collator.compare(flags, "-id") == 0) { + ids.add(args[++i]); } else if (collator.compare(flags, "-file") == 0) { filename = args[++i]; } else if (collator.compare(flags, "-infile") == 0) { @@ -720,7 +743,8 @@ public final class KeyTool { command != GENSECKEY && command != IDENTITYDB && command != IMPORTCERT && - command != IMPORTKEYSTORE) { + command != IMPORTKEYSTORE && + command != PRINTCRL) { throw new Exception(rb.getString ("Keystore file does not exist: ") + ksfname); } @@ -855,10 +879,12 @@ public final class KeyTool { && !KeyStoreUtil.isWindowsKeyStore(storetype) && isKeyStoreRelated(command)) { // here we have EXPORTCERT and LIST (info valid until STOREPASSWD) - System.err.print(rb.getString("Enter keystore password: ")); - System.err.flush(); - storePass = Password.readPassword(System.in); - passwords.add(storePass); + if (command != PRINTCRL) { + System.err.print(rb.getString("Enter keystore password: ")); + System.err.flush(); + storePass = Password.readPassword(System.in); + passwords.add(storePass); + } } // Now load a nullStream-based keystore, @@ -895,7 +921,7 @@ public final class KeyTool { // Create a certificate factory if (command == PRINTCERT || command == IMPORTCERT - || command == IDENTITYDB) { + || command == IDENTITYDB || command == PRINTCRL) { cf = CertificateFactory.getInstance("X509"); } @@ -1086,6 +1112,22 @@ public final class KeyTool { ps.close(); } } + } else if (command == GENCRL) { + if (alias == null) { + alias = keyAlias; + } + PrintStream ps = null; + if (filename != null) { + ps = new PrintStream(new FileOutputStream(filename)); + out = ps; + } + try { + doGenCRL(out); + } finally { + if (ps != null) { + ps.close(); + } + } } else if (command == PRINTCERTREQ) { InputStream inStream = System.in; if (filename != null) { @@ -1098,6 +1140,8 @@ public final class KeyTool { inStream.close(); } } + } else if (command == PRINTCRL) { + doPrintCRL(filename, out); } // If we need to save the keystore, do so. @@ -1152,7 +1196,8 @@ public final class KeyTool { CertificateValidity interval = new CertificateValidity(firstDate, lastDate); - PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; + PrivateKey privateKey = + (PrivateKey)recoverKey(alias, storePass, keyPass).fst; if (sigAlgName == null) { sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); } @@ -1221,6 +1266,56 @@ public final class KeyTool { } } + private void doGenCRL(PrintStream out) + throws Exception { + if (ids == null) { + throw new Exception("Must provide -id when -gencrl"); + } + Certificate signerCert = keyStore.getCertificate(alias); + byte[] encoded = signerCert.getEncoded(); + X509CertImpl signerCertImpl = new X509CertImpl(encoded); + X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." + + CertificateSubjectName.DN_NAME); + + Date firstDate = getStartDate(startDate); + Date lastDate = (Date) firstDate.clone(); + lastDate.setTime(lastDate.getTime() + (long)validity*1000*24*60*60); + CertificateValidity interval = new CertificateValidity(firstDate, + lastDate); + + + PrivateKey privateKey = + (PrivateKey)recoverKey(alias, storePass, keyPass).fst; + if (sigAlgName == null) { + sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); + } + + X509CRLEntry[] badCerts = new X509CRLEntry[ids.size()]; + for (int i=0; i= 0) { + CRLExtensions ext = new CRLExtensions(); + ext.set("Reason", new CRLReasonCodeExtension(Integer.parseInt(id.substring(d+1)))); + badCerts[i] = new X509CRLEntryImpl(new BigInteger(id.substring(0, d)), + firstDate, ext); + } else { + badCerts[i] = new X509CRLEntryImpl(new BigInteger(ids.get(i)), firstDate); + } + } + X509CRLImpl crl = new X509CRLImpl(owner, firstDate, lastDate, badCerts); + crl.sign(privateKey, sigAlgName); + if (rfc) { + out.println("-----BEGIN X509 CRL-----"); + new BASE64Encoder().encodeBuffer(crl.getEncodedInternal(), out); + out.println("-----END X509 CRL-----"); + } else { + out.write(crl.getEncodedInternal()); + } + } + /** * Creates a PKCS#10 cert signing request, corresponding to the * keys (and name) associated with a given alias. @@ -1925,6 +2020,177 @@ public final class KeyTool { } } + private static Iterable e2i(final Enumeration e) { + return new Iterable() { + @Override + public Iterator iterator() { + return new Iterator() { + @Override + public boolean hasNext() { + return e.hasMoreElements(); + } + @Override + public T next() { + return e.nextElement(); + } + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } + }; + } + }; + } + + /** + * Loads CRLs from a source. This method is also called in JarSigner. + * @param src the source, which means System.in if null, or a URI, + * or a bare file path name + */ + public static Collection loadCRLs(String src) throws Exception { + InputStream in = null; + URI uri = null; + if (src == null) { + in = System.in; + } else { + try { + uri = new URI(src); + if (uri.getScheme().equals("ldap")) { + // No input stream for LDAP + } else { + in = uri.toURL().openStream(); + } + } catch (Exception e) { + try { + in = new FileInputStream(src); + } catch (Exception e2) { + if (uri == null || uri.getScheme() == null) { + throw e2; // More likely a bare file path + } else { + throw e; // More likely a protocol or network problem + } + } + } + } + if (in != null) { + try { + // Read the full stream before feeding to X509Factory, + // otherwise, keytool -gencrl | keytool -printcrl + // might not work properly, since -gencrl is slow + // and there's no data in the pipe at the beginning. + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[4096]; + while (true) { + int len = in.read(b); + if (len < 0) break; + bout.write(b, 0, len); + } + return CertificateFactory.getInstance("X509").generateCRLs( + new ByteArrayInputStream(bout.toByteArray())); + } finally { + if (in != System.in) { + in.close(); + } + } + } else { // must be LDAP, and uri is not null + String path = uri.getPath(); + if (path.charAt(0) == '/') path = path.substring(1); + LDAPCertStoreHelper h = new LDAPCertStoreHelper(); + CertStore s = h.getCertStore(uri); + X509CRLSelector sel = + h.wrap(new X509CRLSelector(), null, path); + return s.getCRLs(sel); + } + } + + /** + * Returns CRLs described in a X509Certificate's CRLDistributionPoints + * Extension. Only those containing a general name of type URI are read. + */ + public static List readCRLsFromCert(X509Certificate cert) + throws Exception { + List crls = new ArrayList(); + CRLDistributionPointsExtension ext = + X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension(); + if (ext == null) return crls; + for (DistributionPoint o: (List) + ext.get(CRLDistributionPointsExtension.POINTS)) { + GeneralNames names = o.getFullName(); + if (names != null) { + for (GeneralName name: names.names()) { + if (name.getType() == GeneralNameInterface.NAME_URI) { + URIName uriName = (URIName)name.getName(); + for (CRL crl: KeyTool.loadCRLs(uriName.getName())) { + if (crl instanceof X509CRL) { + crls.add((X509CRL)crl); + } + } + break; // Different name should point to same CRL + } + } + } + } + return crls; + } + + private static String verifyCRL(KeyStore ks, CRL crl) + throws Exception { + X509CRLImpl xcrl = (X509CRLImpl)crl; + X500Principal issuer = xcrl.getIssuerX500Principal(); + for (String s: e2i(ks.aliases())) { + Certificate cert = ks.getCertificate(s); + if (cert instanceof X509Certificate) { + X509Certificate xcert = (X509Certificate)cert; + if (xcert.getSubjectX500Principal().equals(issuer)) { + try { + ((X509CRLImpl)crl).verify(cert.getPublicKey()); + return s; + } catch (Exception e) { + } + } + } + } + return null; + } + + private void doPrintCRL(String src, PrintStream out) + throws Exception { + for (CRL crl: loadCRLs(src)) { + printCRL(crl, out); + String issuer = null; + if (caks != null) { + issuer = verifyCRL(caks, crl); + if (issuer != null) { + System.out.println("Verified by " + issuer + " in cacerts"); + } + } + if (issuer == null && keyStore != null) { + issuer = verifyCRL(keyStore, crl); + if (issuer != null) { + System.out.println("Verified by " + issuer + " in keystore"); + } + } + if (issuer == null) { + out.println(rb.getString + ("*******************************************")); + out.println("WARNING: not verified. Make sure -keystore and -alias are correct."); + out.println(rb.getString + ("*******************************************\n\n")); + } + } + } + + private void printCRL(CRL crl, PrintStream out) + throws Exception { + if (rfc) { + X509CRL xcrl = (X509CRL)crl; + out.println("-----BEGIN X509 CRL-----"); + new BASE64Encoder().encodeBuffer(xcrl.getEncoded(), out); + out.println("-----END X509 CRL-----"); + } else { + out.println(crl.toString()); + } + } + private void doPrintCertReq(InputStream in, PrintStream out) throws Exception { @@ -2063,6 +2329,16 @@ public final class KeyTool { out.println(); } } + CRL[] crls = SharedSecrets + .getJavaSecurityCodeSignerAccess() + .getCRLs(signer); + if (crls != null) { + out.println(rb.getString("CRLs:")); + out.println(); + for (CRL crl: crls) { + printCRL(crl, out); + } + } } } } @@ -3330,15 +3606,22 @@ public final class KeyTool { /** * Match a command (may be abbreviated) with a command set. * @param s the command provided - * @param list the legal command set + * @param list the legal command set. If there is a null, commands after it + * are regarded experimental, which means they are supported but their + * existence should not be revealed to user. * @return the position of a single match, or -1 if none matched * @throws Exception if s is ambiguous */ private static int oneOf(String s, String... list) throws Exception { int[] match = new int[list.length]; int nmatch = 0; + int experiment = Integer.MAX_VALUE; for (int i = 0; i experiment) { + return match[0]; + } + StringBuffer sb = new StringBuffer(); + MessageFormat form = new MessageFormat(rb.getString + ("command {0} is ambiguous:")); + Object[] source = {s}; + sb.append(form.format(source)); + sb.append("\n "); + for (int i=0; i(); } // Append the new code signer - signers.add(new CodeSigner(certChain, getTimestamp(info))); + CodeSigner signer = new CodeSigner(certChain, getTimestamp(info)); + if (block.getCRLs() != null) { + SharedSecrets.getJavaSecurityCodeSignerAccess().setCRLs( + signer, block.getCRLs()); + } + signers.add(signer); if (debug != null) { debug.println("Signature Block Certificate: " + diff --git a/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java b/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java index b1157799663..f5d159891d9 100644 --- a/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java +++ b/jdk/src/share/classes/sun/security/x509/X509CRLImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2010 Sun Microsystems, Inc. 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 @@ -89,7 +89,7 @@ import sun.misc.HexDumpEncoder; * @author Hemma Prafullchandra * @see X509CRL */ -public class X509CRLImpl extends X509CRL { +public class X509CRLImpl extends X509CRL implements DerEncoder { // CRL data, and its envelope private byte[] signedCRL = null; // DER encoded crl @@ -1189,6 +1189,13 @@ public class X509CRLImpl extends X509CRL { } } + @Override + public void derEncode(OutputStream out) throws IOException { + if (signedCRL == null) + throw new IOException("Null CRL to encode"); + out.write(signedCRL.clone()); + } + /** * Immutable X.509 Certificate Issuer DN and serial number pair */ diff --git a/jdk/test/sun/security/tools/jarsigner/crl.sh b/jdk/test/sun/security/tools/jarsigner/crl.sh new file mode 100644 index 00000000000..73d0c4eae57 --- /dev/null +++ b/jdk/test/sun/security/tools/jarsigner/crl.sh @@ -0,0 +1,91 @@ +# +# Copyright 2010 Sun Microsystems, Inc. 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. +# +# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6890876 +# @summary jarsigner can add CRL info into signed jar +# + +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +# PF: platform name, say, solaris-sparc + +PF="" + +OS=`uname -s` +case "$OS" in + Windows* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +KS=crl.jks +JFILE=crl.jar + +KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS" +JAR=$TESTJAVA${FS}bin${FS}jar +JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner + +rm $KS $JFILE + +# Generates some crl files, each containing two entries + +$KT -alias a -dname CN=a -keyalg rsa -genkey -validity 300 +$KT -alias a -gencrl -id 1:1 -id 2:2 -file crl1 +$KT -alias a -gencrl -id 3:3 -id 4:4 -file crl2 +$KT -alias b -dname CN=b -keyalg rsa -genkey -validity 300 +$KT -alias b -gencrl -id 5:1 -id 6:2 -file crl3 + +$KT -alias c -dname CN=c -keyalg rsa -genkey -validity 300 \ + -ext crl=uri:file://`pwd`/crl1 + +echo A > A + +# Test -crl:auto, cRLDistributionPoints is a local file + +$JAR cvf $JFILE A +$JARSIGNER -keystore $KS -storepass changeit $JFILE c \ + -crl:auto || exit 1 +$JARSIGNER -keystore $KS -verify -debug -strict $JFILE || exit 6 +$KT -printcert -jarfile $JFILE | grep CRLs || exit 7 + +# Test -crl + +$JAR cvf $JFILE A +$JARSIGNER -keystore $KS -storepass changeit $JFILE a \ + -crl crl1 -crl crl2 || exit 1 +$JARSIGNER -keystore $KS -storepass changeit $JFILE b \ + -crl crl3 -crl crl2 || exit 1 +$JARSIGNER -keystore $KS -verify -debug -strict $JFILE || exit 3 +$KT -printcert -jarfile $JFILE | grep CRLs || exit 4 +CRLCOUNT=`$KT -printcert -jarfile $JFILE | grep SerialNumber | wc -l` +if [ $CRLCOUNT != 8 ]; then exit 5; fi + +exit 0 From 5a66416a07a4ba361c31018571a51e9b0dbd7a07 Mon Sep 17 00:00:00 2001 From: Peter Zhelezniakov Date: Thu, 6 May 2010 12:57:30 +0400 Subject: [PATCH 15/23] 6919629: Nimbus L&F Nimbus.Overrides option leaks significant amounts of memory Reviewed-by: rupashka --- .../javax/swing/plaf/nimbus/NimbusStyle.java | 13 ++- .../javax/swing/plaf/nimbus/Test6919629.java | 82 +++++++++++++++++++ 2 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 jdk/test/javax/swing/plaf/nimbus/Test6919629.java diff --git a/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java index a8f8b3fc5b6..c8672e3c8c9 100644 --- a/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java +++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/NimbusStyle.java @@ -38,6 +38,7 @@ import javax.swing.plaf.synth.SynthStyle; import java.awt.Color; import java.awt.Font; import java.awt.Insets; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -193,7 +194,7 @@ public final class NimbusStyle extends SynthStyle { * UIDefaults which overrides (or supplements) those defaults found in * UIManager. */ - private JComponent component; + private WeakReference component; /** * Create a new NimbusStyle. Only the prefix must be supplied. At the @@ -209,7 +210,9 @@ public final class NimbusStyle extends SynthStyle { * should be null otherwise. */ NimbusStyle(String prefix, JComponent c) { - this.component = c; + if (c != null) { + this.component = new WeakReference(c); + } this.prefix = prefix; this.painter = new SynthPainterImpl(this); } @@ -251,9 +254,11 @@ public final class NimbusStyle extends SynthStyle { // value is an instance of UIDefaults, then these defaults are used // in place of, or in addition to, the defaults in UIManager. if (component != null) { - Object o = component.getClientProperty("Nimbus.Overrides"); + // We know component.get() is non-null here, as if the component + // were GC'ed, we wouldn't be processing its style. + Object o = component.get().getClientProperty("Nimbus.Overrides"); if (o instanceof UIDefaults) { - Object i = component.getClientProperty( + Object i = component.get().getClientProperty( "Nimbus.Overrides.InheritDefaults"); boolean inherit = i instanceof Boolean ? (Boolean)i : true; UIDefaults d = (UIDefaults)o; diff --git a/jdk/test/javax/swing/plaf/nimbus/Test6919629.java b/jdk/test/javax/swing/plaf/nimbus/Test6919629.java new file mode 100644 index 00000000000..38d66a0cf42 --- /dev/null +++ b/jdk/test/javax/swing/plaf/nimbus/Test6919629.java @@ -0,0 +1,82 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* @test + @bug 6919629 + @summary Tests that components with Nimbus.Overrides are GC'ed properly + @author Peter Zhelezniakov + @run main Test6919629 +*/ + +import java.awt.Color; +import java.lang.ref.WeakReference; +import javax.swing.*; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; + +public class Test6919629 +{ + JFrame f; + WeakReference ref; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel(new NimbusLookAndFeel()); + Test6919629 t = new Test6919629(); + t.test(); + System.gc(); + t.check(); + } + + void test() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + UIDefaults d = new UIDefaults(); + d.put("Label.textForeground", Color.MAGENTA); + + JLabel l = new JLabel(); + ref = new WeakReference(l); + l.putClientProperty("Nimbus.Overrides", d); + + f = new JFrame(); + f.getContentPane().add(l); + f.pack(); + f.setVisible(true); + } + }); + Thread.sleep(2000); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + f.getContentPane().removeAll(); + f.setVisible(false); + f.dispose(); + } + }); + Thread.sleep(2000); + } + + void check() { + if (ref.get() != null) { + throw new RuntimeException("Failed: an unused component wasn't collected"); + } + } +} From 1a12511929ef912eec9a5a470d07ac49955d28af Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Thu, 6 May 2010 17:17:09 +0100 Subject: [PATCH 16/23] 6946825: com.sun.net.httpserver.HttpServer; Memory Leak on Non HTTP conform open socket Reviewed-by: michaelm --- jdk/src/share/classes/sun/net/httpserver/ServerImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java index 8f5c8bee038..575661e776a 100644 --- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java +++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java @@ -451,6 +451,7 @@ class ServerImpl implements TimeSource { if (requestLine == null) { /* connection closed */ connection.close(); + allConnections.remove(connection); return; } int space = requestLine.indexOf (' '); @@ -592,6 +593,8 @@ class ServerImpl implements TimeSource { sendReply ( code, true, "

"+code+Code.msg(code)+"

"+message ); + /* connection is already closed by sendReply, now remove it */ + allConnections.remove(connection); } void sendReply ( From 473182bb12e887e84a433df6273842ec21cacf3c Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Fri, 7 May 2010 10:11:37 +0100 Subject: [PATCH 17/23] 6947917: Error in basic authentication when user name and password are long Reviewed-by: weijun --- .../protocol/http/BasicAuthentication.java | 15 ++- .../protocol/http/BasicLongCredentials.java | 111 ++++++++++++++++++ 2 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 jdk/test/sun/net/www/protocol/http/BasicLongCredentials.java diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java index 8e9c8a7281d..6755b59b061 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java @@ -29,8 +29,10 @@ import java.net.URL; import java.net.URI; import java.net.URISyntaxException; import java.net.PasswordAuthentication; +import java.io.IOException; +import java.io.OutputStream; import sun.net.www.HeaderParser; - +import sun.misc.BASE64Encoder; /** * BasicAuthentication: Encapsulate an http server authentication using @@ -74,7 +76,7 @@ class BasicAuthentication extends AuthenticationInfo { System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length); System.arraycopy(passwdBytes, 0, concat, nameBytes.length, passwdBytes.length); - this.auth = "Basic " + (new sun.misc.BASE64Encoder()).encode(concat); + this.auth = "Basic " + (new BasicBASE64Encoder()).encode(concat); this.pw = pw; } @@ -114,7 +116,7 @@ class BasicAuthentication extends AuthenticationInfo { System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length); System.arraycopy(passwdBytes, 0, concat, nameBytes.length, passwdBytes.length); - this.auth = "Basic " + (new sun.misc.BASE64Encoder()).encode(concat); + this.auth = "Basic " + (new BasicBASE64Encoder()).encode(concat); this.pw = pw; } @@ -200,4 +202,11 @@ class BasicAuthentication extends AuthenticationInfo { return npath; } + /* It is never expected that the header value will exceed the bytesPerLine */ + private class BasicBASE64Encoder extends BASE64Encoder { + @Override + protected int bytesPerLine() { + return (10000); + } + } } diff --git a/jdk/test/sun/net/www/protocol/http/BasicLongCredentials.java b/jdk/test/sun/net/www/protocol/http/BasicLongCredentials.java new file mode 100644 index 00000000000..5ce3c500097 --- /dev/null +++ b/jdk/test/sun/net/www/protocol/http/BasicLongCredentials.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010 Sun Microsystems, Inc. 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6947917 + * @summary Error in basic authentication when user name and password are long + */ + +import com.sun.net.httpserver.BasicAuthenticator; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpPrincipal; +import com.sun.net.httpserver.HttpServer; +import java.io.InputStream; +import java.io.IOException; +import java.net.Authenticator; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.HttpURLConnection; +import java.net.URL; + +public class BasicLongCredentials { + + static final String USERNAME = "ThisIsMyReallyReallyReallyReallyReallyReally" + + "LongFirstNameDotLastNameAtCompanyEmailAddress"; + static final String PASSWORD = "AndThisIsALongLongLongLongLongLongLongLongLong" + + "LongLongLongLongLongLongLongLongLongPassword"; + static final String REALM = "foobar@test.realm"; + + public static void main (String[] args) throws Exception { + HttpServer server = HttpServer.create(new InetSocketAddress(0), 0); + try { + Handler handler = new Handler(); + HttpContext ctx = server.createContext("/test", handler); + + BasicAuthenticator a = new BasicAuthenticator(REALM) { + public boolean checkCredentials (String username, String pw) { + return USERNAME.equals(username) && PASSWORD.equals(pw); + } + }; + ctx.setAuthenticator(a); + server.start(); + + Authenticator.setDefault(new MyAuthenticator()); + + URL url = new URL("http://localhost:"+server.getAddress().getPort()+"/test/"); + HttpURLConnection urlc = (HttpURLConnection)url.openConnection(); + InputStream is = urlc.getInputStream(); + int c = 0; + while (is.read()!= -1) { c ++; } + + if (c != 0) { throw new RuntimeException("Test failed c = " + c); } + if (error) { throw new RuntimeException("Test failed: error"); } + + System.out.println ("OK"); + } finally { + server.stop(0); + } + } + + public static boolean error = false; + + static class MyAuthenticator extends java.net.Authenticator { + @Override + public PasswordAuthentication getPasswordAuthentication () { + if (!getRequestingPrompt().equals(REALM)) { + BasicLongCredentials.error = true; + } + return new PasswordAuthentication (USERNAME, PASSWORD.toCharArray()); + } + } + + static class Handler implements HttpHandler { + public void handle (HttpExchange t) throws IOException { + InputStream is = t.getRequestBody(); + while (is.read () != -1) ; + is.close(); + t.sendResponseHeaders(200, -1); + HttpPrincipal p = t.getPrincipal(); + if (!p.getUsername().equals(USERNAME)) { + error = true; + } + if (!p.getRealm().equals(REALM)) { + error = true; + } + t.close(); + } + } +} From 521354406a4e9226aa2fbfe10238d3c9dac3c7a5 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Fri, 7 May 2010 16:11:13 +0100 Subject: [PATCH 18/23] 6946673: DatagramSocket.connect() documentation contradicts the implementation Reviewed-by: alanb --- .../classes/java/net/DatagramSocket.java | 63 +++++++++++++------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/jdk/src/share/classes/java/net/DatagramSocket.java b/jdk/src/share/classes/java/net/DatagramSocket.java index 3e3464c677d..b177423979a 100644 --- a/jdk/src/share/classes/java/net/DatagramSocket.java +++ b/jdk/src/share/classes/java/net/DatagramSocket.java @@ -401,29 +401,40 @@ class DatagramSocket implements java.io.Closeable { * send or receive may throw a PortUnreachableException. Note, there is no * guarantee that the exception will be thrown. * - *

A caller's permission to send and receive datagrams to a - * given host and port are checked at connect time. When a socket - * is connected, receive and send will not - * perform any security checks on incoming and outgoing - * packets, other than matching the packet's and the socket's - * address and port. On a send operation, if the packet's address - * is set and the packet's address and the socket's address do not - * match, an IllegalArgumentException will be thrown. A socket - * connected to a multicast address may only be used to send packets. + *

If a security manager has been installed then it is invoked to check + * access to the remote address. Specifically, if the given {@code address} + * is a {@link InetAddress#isMulticastAddress multicast address}, + * the security manager's {@link + * java.lang.SecurityManager#checkMulticast(InetAddress) + * checkMulticast} method is invoked with the given {@code address}. + * Otherwise, the security manager's {@link + * java.lang.SecurityManager#checkConnect(String,int) checkConnect} + * and {@link java.lang.SecurityManager#checkAccept checkAccept} methods + * are invoked, with the given {@code address} and {@code port}, to + * verify that datagrams are permitted to be sent and received + * respectively. + * + *

When a socket is connected, {@link #receive receive} and + * {@link #send send} will not perform any security checks + * on incoming and outgoing packets, other than matching the packet's + * and the socket's address and port. On a send operation, if the + * packet's address is set and the packet's address and the socket's + * address do not match, an {@code IllegalArgumentException} will be + * thrown. A socket connected to a multicast address may only be used + * to send packets. * * @param address the remote address for the socket * * @param port the remote port for the socket. * - * @exception IllegalArgumentException if the address is null, - * or the port is out of range. + * @throws IllegalArgumentException + * if the address is null, or the port is out of range. * - * @exception SecurityException if the caller is not allowed to - * send datagrams to and receive datagrams from the address and port. + * @throws SecurityException + * if a security manager has been installed and it does + * not permit access to the given remote address * * @see #disconnect - * @see #send - * @see #receive */ public void connect(InetAddress address, int port) { try { @@ -435,13 +446,25 @@ class DatagramSocket implements java.io.Closeable { /** * Connects this socket to a remote socket address (IP address + port number). - *

+ * + *

If given an {@link InetSocketAddress InetSocketAddress}, this method + * behaves as if invoking {@link #connect(InetAddress,int) connect(InetAddress,int)} + * with the the given socket addresses IP address and port number. + * * @param addr The remote address. - * @throws SocketException if the connect fails - * @throws IllegalArgumentException if addr is null or addr is a SocketAddress - * subclass not supported by this socket + * + * @throws SocketException + * if the connect fails + * + * @throws IllegalArgumentException + * if {@code addr} is {@code null}, or {@code addr} is a SocketAddress + * subclass not supported by this socket + * + * @throws SecurityException + * if a security manager has been installed and it does + * not permit access to the given remote address + * * @since 1.4 - * @see #connect */ public void connect(SocketAddress addr) throws SocketException { if (addr == null) From 4a29f05c6ad61db2932750d9799a050e6954bf04 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Sun, 9 May 2010 00:59:30 -0700 Subject: [PATCH 19/23] 6933217: Huge arrays handled poorly in core libraries Write overflow-conscious array resizing code Reviewed-by: chegar --- .../java/io/ByteArrayOutputStream.java | 56 ++++++-- .../java/lang/AbstractStringBuilder.java | 124 +++++++----------- .../classes/java/util/AbstractCollection.java | 28 +++- .../share/classes/java/util/ArrayList.java | 47 +++++-- .../share/classes/java/util/Hashtable.java | 17 ++- .../classes/java/util/PriorityQueue.java | 31 +++-- jdk/src/share/classes/java/util/Vector.java | 39 ++++-- 7 files changed, 218 insertions(+), 124 deletions(-) diff --git a/jdk/src/share/classes/java/io/ByteArrayOutputStream.java b/jdk/src/share/classes/java/io/ByteArrayOutputStream.java index 6a9b190f20c..a3b0e06bbb4 100644 --- a/jdk/src/share/classes/java/io/ByteArrayOutputStream.java +++ b/jdk/src/share/classes/java/io/ByteArrayOutputStream.java @@ -77,18 +77,51 @@ public class ByteArrayOutputStream extends OutputStream { buf = new byte[size]; } + /** + * Increases the capacity if necessary to ensure that it can hold + * at least the number of elements specified by the minimum + * capacity argument. + * + * @param minCapacity the desired minimum capacity + * @throws OutOfMemoryError if {@code minCapacity < 0}. This is + * interpreted as a request for the unsatisfiably large capacity + * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}. + */ + private void ensureCapacity(int minCapacity) { + // overflow-conscious code + if (minCapacity - buf.length > 0) + grow(minCapacity); + } + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + // overflow-conscious code + int oldCapacity = buf.length; + int newCapacity = oldCapacity << 1; + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + if (newCapacity < 0) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + newCapacity = Integer.MAX_VALUE; + } + buf = Arrays.copyOf(buf, newCapacity); + } + /** * Writes the specified byte to this byte array output stream. * * @param b the byte to be written. */ public synchronized void write(int b) { - int newcount = count + 1; - if (newcount > buf.length) { - buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); - } - buf[count] = (byte)b; - count = newcount; + ensureCapacity(count + 1); + buf[count] = (byte) b; + count += 1; } /** @@ -101,17 +134,12 @@ public class ByteArrayOutputStream extends OutputStream { */ public synchronized void write(byte b[], int off, int len) { if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { + ((off + len) - b.length > 0)) { throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - int newcount = count + len; - if (newcount > buf.length) { - buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); } + ensureCapacity(count + len); System.arraycopy(b, off, buf, count, len); - count = newcount; + count += len; } /** diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java index 973e0854d61..fd98eb0403c 100644 --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java @@ -36,6 +36,8 @@ import java.util.Arrays; * sequence can be changed through certain method calls. * * @author Michael McCloskey + * @author Martin Buchholz + * @author Ulf Zibis * @since 1.5 */ abstract class AbstractStringBuilder implements Appendable, CharSequence { @@ -98,9 +100,16 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @param minimumCapacity the minimum desired capacity. */ public void ensureCapacity(int minimumCapacity) { - if (minimumCapacity > value.length) { + ensureCapacityInternal(minimumCapacity); + } + + /** + * This method has the same contract as ensureCapacity, but is + * never synchronized. + */ + private void ensureCapacityInternal(int minimumCapacity) { + if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity); - } } /** @@ -108,11 +117,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * size check or synchronization. */ void expandCapacity(int minimumCapacity) { - int newCapacity = (value.length + 1) * 2; - if (newCapacity < 0) { - newCapacity = Integer.MAX_VALUE; - } else if (minimumCapacity > newCapacity) { + int newCapacity = value.length * 2; + if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; + if (newCapacity < 0) { + if (minimumCapacity < 0) // overflow + throw new OutOfMemoryError(); + newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); } @@ -158,8 +169,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { public void setLength(int newLength) { if (newLength < 0) throw new StringIndexOutOfBoundsException(newLength); - if (newLength > value.length) - expandCapacity(newLength); + ensureCapacityInternal(newLength); if (count < newLength) { for (; count < newLength; count++) @@ -400,12 +410,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { public AbstractStringBuilder append(String str) { if (str == null) str = "null"; int len = str.length(); - if (len == 0) return this; - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); str.getChars(0, len, value, count); - count = newCount; + count += len; return this; } @@ -414,11 +421,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { if (sb == null) return append("null"); int len = sb.length(); - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); sb.getChars(0, len, value, count); - count = newCount; + count += len; return this; } @@ -470,14 +475,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { "start " + start + ", end " + end + ", s.length() " + s.length()); int len = end - start; - if (len == 0) - return this; - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); - for (int i=start; i value.length) - expandCapacity(newCount); - System.arraycopy(str, 0, value, count, str.length); - count = newCount; + int len = str.length; + ensureCapacityInternal(count + len); + System.arraycopy(str, 0, value, count, len); + count += len; return this; } @@ -529,11 +529,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * or {@code offset+len > str.length} */ public AbstractStringBuilder append(char str[], int offset, int len) { - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); System.arraycopy(str, offset, value, count, len); - count = newCount; + count += len; return this; } @@ -551,17 +549,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { */ public AbstractStringBuilder append(boolean b) { if (b) { - int newCount = count + 4; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + 4); value[count++] = 't'; value[count++] = 'r'; value[count++] = 'u'; value[count++] = 'e'; } else { - int newCount = count + 5; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + 5); value[count++] = 'f'; value[count++] = 'a'; value[count++] = 'l'; @@ -587,9 +581,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @return a reference to this object. */ public AbstractStringBuilder append(char c) { - int newCount = count + 1; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + 1); value[count++] = c; return this; } @@ -614,8 +606,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1 : Integer.stringSize(i); int spaceNeeded = count + appendedLength; - if (spaceNeeded > value.length) - expandCapacity(spaceNeeded); + ensureCapacityInternal(spaceNeeded); Integer.getChars(i, spaceNeeded, value); count = spaceNeeded; return this; @@ -641,8 +632,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { int appendedLength = (l < 0) ? Long.stringSize(-l) + 1 : Long.stringSize(l); int spaceNeeded = count + appendedLength; - if (spaceNeeded > value.length) - expandCapacity(spaceNeeded); + ensureCapacityInternal(spaceNeeded); Long.getChars(l, spaceNeeded, value); count = spaceNeeded; return this; @@ -738,10 +728,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) { n++; } - int newCount = count + n; - if (newCount > value.length) { - expandCapacity(newCount); - } + ensureCapacityInternal(count + n); if (n == 1) { value[count++] = (char) codePoint; } else { @@ -807,8 +794,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { end = count; int len = str.length(); int newCount = count + len - (end - start); - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(newCount); System.arraycopy(value, end, value, start + len, count - end); str.getChars(value, start); @@ -915,12 +901,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { throw new StringIndexOutOfBoundsException( "offset " + offset + ", len " + len + ", str.length " + str.length); - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); System.arraycopy(value, index, value, index + len, count - index); System.arraycopy(str, offset, value, index, len); - count = newCount; + count += len; return this; } @@ -984,12 +968,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { if (str == null) str = "null"; int len = str.length(); - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); System.arraycopy(value, offset, value, offset + len, count - offset); str.getChars(value, offset); - count = newCount; + count += len; return this; } @@ -1021,12 +1003,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { if ((offset < 0) || (offset > length())) throw new StringIndexOutOfBoundsException(offset); int len = str.length; - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); System.arraycopy(value, offset, value, offset + len, count - offset); System.arraycopy(str, 0, value, offset, len); - count = newCount; + count += len; return this; } @@ -1114,16 +1094,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { "start " + start + ", end " + end + ", s.length() " + s.length()); int len = end - start; - if (len == 0) - return this; - int newCount = count + len; - if (newCount > value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + len); System.arraycopy(value, dstOffset, value, dstOffset + len, count - dstOffset); for (int i=start; i value.length) - expandCapacity(newCount); + ensureCapacityInternal(count + 1); System.arraycopy(value, offset, value, offset + 1, count - offset); value[offset] = c; - count = newCount; + count += 1; return this; } diff --git a/jdk/src/share/classes/java/util/AbstractCollection.java b/jdk/src/share/classes/java/util/AbstractCollection.java index 5b13c9b00fd..f40d050589f 100644 --- a/jdk/src/share/classes/java/util/AbstractCollection.java +++ b/jdk/src/share/classes/java/util/AbstractCollection.java @@ -190,6 +190,14 @@ public abstract class AbstractCollection implements Collection { return it.hasNext() ? finishToArray(r, it) : r; } + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + /** * Reallocates the array being used within toArray when the iterator * returned more elements than expected, and finishes filling it from @@ -205,13 +213,10 @@ public abstract class AbstractCollection implements Collection { while (it.hasNext()) { int cap = r.length; if (i == cap) { - int newCap = ((cap / 2) + 1) * 3; - if (newCap <= cap) { // integer overflow - if (cap == Integer.MAX_VALUE) - throw new OutOfMemoryError - ("Required array size too large"); - newCap = Integer.MAX_VALUE; - } + int newCap = cap + (cap >> 1) + 1; + // overflow-conscious code + if (newCap - MAX_ARRAY_SIZE > 0) + newCap = hugeCapacity(cap + 1); r = Arrays.copyOf(r, newCap); } r[i++] = (T)it.next(); @@ -220,6 +225,15 @@ public abstract class AbstractCollection implements Collection { return (i == r.length) ? r : Arrays.copyOf(r, i); } + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError + ("Required array size too large"); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; + } + // Modification Operations /** diff --git a/jdk/src/share/classes/java/util/ArrayList.java b/jdk/src/share/classes/java/util/ArrayList.java index dbd46096bf3..92dbfd9c84b 100644 --- a/jdk/src/share/classes/java/util/ArrayList.java +++ b/jdk/src/share/classes/java/util/ArrayList.java @@ -173,18 +173,47 @@ public class ArrayList extends AbstractList * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * - * @param minCapacity the desired minimum capacity + * @param minCapacity the desired minimum capacity */ public void ensureCapacity(int minCapacity) { modCount++; + // overflow-conscious code + if (minCapacity - elementData.length > 0) + grow(minCapacity); + } + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + // overflow-conscious code int oldCapacity = elementData.length; - if (minCapacity > oldCapacity) { - int newCapacity = (oldCapacity * 3)/2 + 1; - if (newCapacity < minCapacity) - newCapacity = minCapacity; - // minCapacity is usually close to size, so this is a win: - elementData = Arrays.copyOf(elementData, newCapacity); - } + int newCapacity = oldCapacity + (oldCapacity >> 1); + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + // minCapacity is usually close to size, so this is a win: + elementData = Arrays.copyOf(elementData, newCapacity); + } + + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; } /** @@ -391,7 +420,7 @@ public class ArrayList extends AbstractList public void add(int index, E element) { rangeCheckForAdd(index); - ensureCapacity(size+1); // Increments modCount!! + ensureCapacity(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index 4fbd336ca6c..17267985d2a 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -364,6 +364,14 @@ public class Hashtable return null; } + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + /** * Increases the capacity of and internally reorganizes this * hashtable, in order to accommodate and access its entries more @@ -375,7 +383,14 @@ public class Hashtable int oldCapacity = table.length; Entry[] oldMap = table; - int newCapacity = oldCapacity * 2 + 1; + // overflow-conscious code + int newCapacity = (oldCapacity << 1) + 1; + if (newCapacity - MAX_ARRAY_SIZE > 0) { + if (oldCapacity == MAX_ARRAY_SIZE) + // Keep running with MAX_ARRAY_SIZE buckets + return; + newCapacity = MAX_ARRAY_SIZE; + } Entry[] newMap = new Entry[newCapacity]; modCount++; diff --git a/jdk/src/share/classes/java/util/PriorityQueue.java b/jdk/src/share/classes/java/util/PriorityQueue.java index 428792fe1c6..ac87d9fb569 100644 --- a/jdk/src/share/classes/java/util/PriorityQueue.java +++ b/jdk/src/share/classes/java/util/PriorityQueue.java @@ -235,26 +235,39 @@ public class PriorityQueue extends AbstractQueue size = a.length; } + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + /** * Increases the capacity of the array. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { - if (minCapacity < 0) // overflow - throw new OutOfMemoryError(); int oldCapacity = queue.length; // Double size if small; else grow by 50% - int newCapacity = ((oldCapacity < 64)? - ((oldCapacity + 1) * 2): - ((oldCapacity / 2) * 3)); - if (newCapacity < 0) // overflow - newCapacity = Integer.MAX_VALUE; - if (newCapacity < minCapacity) - newCapacity = minCapacity; + int newCapacity = oldCapacity + ((oldCapacity < 64) ? + (oldCapacity + 2) : + (oldCapacity >> 1)); + // overflow-conscious code + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); queue = Arrays.copyOf(queue, newCapacity); } + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; + } + /** * Inserts the specified element into this priority queue. * diff --git a/jdk/src/share/classes/java/util/Vector.java b/jdk/src/share/classes/java/util/Vector.java index f70d36ee069..6fa6c84f8da 100644 --- a/jdk/src/share/classes/java/util/Vector.java +++ b/jdk/src/share/classes/java/util/Vector.java @@ -235,16 +235,37 @@ public class Vector * @see #ensureCapacity(int) */ private void ensureCapacityHelper(int minCapacity) { + // overflow-conscious code + if (minCapacity - elementData.length > 0) + grow(minCapacity); + } + + /** + * The maximum size of array to allocate. + * Some VMs reserve some header words in an array. + * Attempts to allocate larger arrays may result in + * OutOfMemoryError: Requested array size exceeds VM limit + */ + private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + private void grow(int minCapacity) { + // overflow-conscious code int oldCapacity = elementData.length; - if (minCapacity > oldCapacity) { - Object[] oldData = elementData; - int newCapacity = (capacityIncrement > 0) ? - (oldCapacity + capacityIncrement) : (oldCapacity * 2); - if (newCapacity < minCapacity) { - newCapacity = minCapacity; - } - elementData = Arrays.copyOf(elementData, newCapacity); - } + int newCapacity = oldCapacity + ((capacityIncrement > 0) ? + capacityIncrement : oldCapacity); + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + if (newCapacity - MAX_ARRAY_SIZE > 0) + newCapacity = hugeCapacity(minCapacity); + elementData = Arrays.copyOf(elementData, newCapacity); + } + + private static int hugeCapacity(int minCapacity) { + if (minCapacity < 0) // overflow + throw new OutOfMemoryError(); + return (minCapacity > MAX_ARRAY_SIZE) ? + Integer.MAX_VALUE : + MAX_ARRAY_SIZE; } /** From b455514c890ea10fbb2104051d2b3b4e347239eb Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Sun, 9 May 2010 00:59:49 -0700 Subject: [PATCH 20/23] 6950540: PriorityQueue(collection) should throw NPE if collection contains a null Rewrite PriorityQueue constructors for best performance and error handling Reviewed-by: dholmes, chegar --- .../classes/java/util/PriorityQueue.java | 63 ++++-- jdk/test/java/util/PriorityQueue/NoNulls.java | 204 ++++++++++++++++++ 2 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 jdk/test/java/util/PriorityQueue/NoNulls.java diff --git a/jdk/src/share/classes/java/util/PriorityQueue.java b/jdk/src/share/classes/java/util/PriorityQueue.java index ac87d9fb569..931c287c0c2 100644 --- a/jdk/src/share/classes/java/util/PriorityQueue.java +++ b/jdk/src/share/classes/java/util/PriorityQueue.java @@ -170,17 +170,21 @@ public class PriorityQueue extends AbstractQueue * @throws NullPointerException if the specified collection or any * of its elements are null */ + @SuppressWarnings("unchecked") public PriorityQueue(Collection c) { - initFromCollection(c); - if (c instanceof SortedSet) - comparator = (Comparator) - ((SortedSet)c).comparator(); - else if (c instanceof PriorityQueue) - comparator = (Comparator) - ((PriorityQueue)c).comparator(); + if (c instanceof SortedSet) { + SortedSet ss = (SortedSet) c; + this.comparator = (Comparator) ss.comparator(); + initElementsFromCollection(ss); + } + else if (c instanceof PriorityQueue) { + PriorityQueue pq = (PriorityQueue) c; + this.comparator = (Comparator) pq.comparator(); + initFromPriorityQueue(pq); + } else { - comparator = null; - heapify(); + this.comparator = null; + initFromCollection(c); } } @@ -198,9 +202,10 @@ public class PriorityQueue extends AbstractQueue * @throws NullPointerException if the specified priority queue or any * of its elements are null */ + @SuppressWarnings("unchecked") public PriorityQueue(PriorityQueue c) { - comparator = (Comparator)c.comparator(); - initFromCollection(c); + this.comparator = (Comparator) c.comparator(); + initFromPriorityQueue(c); } /** @@ -216,9 +221,33 @@ public class PriorityQueue extends AbstractQueue * @throws NullPointerException if the specified sorted set or any * of its elements are null */ + @SuppressWarnings("unchecked") public PriorityQueue(SortedSet c) { - comparator = (Comparator)c.comparator(); - initFromCollection(c); + this.comparator = (Comparator) c.comparator(); + initElementsFromCollection(c); + } + + private void initFromPriorityQueue(PriorityQueue c) { + if (c.getClass() == PriorityQueue.class) { + this.queue = c.toArray(); + this.size = c.size(); + } else { + initFromCollection(c); + } + } + + private void initElementsFromCollection(Collection c) { + Object[] a = c.toArray(); + // If c.toArray incorrectly doesn't return Object[], copy it. + if (a.getClass() != Object[].class) + a = Arrays.copyOf(a, a.length, Object[].class); + int len = a.length; + if (len == 1 || this.comparator != null) + for (int i = 0; i < len; i++) + if (a[i] == null) + throw new NullPointerException(); + this.queue = a; + this.size = a.length; } /** @@ -227,12 +256,8 @@ public class PriorityQueue extends AbstractQueue * @param c the collection */ private void initFromCollection(Collection c) { - Object[] a = c.toArray(); - // If c.toArray incorrectly doesn't return Object[], copy it. - if (a.getClass() != Object[].class) - a = Arrays.copyOf(a, a.length, Object[].class); - queue = a; - size = a.length; + initElementsFromCollection(c); + heapify(); } /** diff --git a/jdk/test/java/util/PriorityQueue/NoNulls.java b/jdk/test/java/util/PriorityQueue/NoNulls.java new file mode 100644 index 00000000000..c40c93be893 --- /dev/null +++ b/jdk/test/java/util/PriorityQueue/NoNulls.java @@ -0,0 +1,204 @@ +/* + * 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. + * + * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Martin Buchholz with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/licenses/publicdomain + */ + +/* + * @test + * @bug 6950540 + * @summary Attempt to add a null throws NullPointerException + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Collection; +import java.util.Collections; +import java.util.PriorityQueue; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; + +public class NoNulls { + void test(String[] args) throws Throwable { + final Comparator nullTolerantComparator + = new Comparator<>() { + public int compare(String x, String y) { + return (x == null ? -1 : + y == null ? 1 : + x.compareTo(y)); + }}; + + final SortedSet nullSortedSet + = new TreeSet<>(nullTolerantComparator); + nullSortedSet.add(null); + + final PriorityQueue nullPriorityQueue + = new PriorityQueue<>() { + public Object[] toArray() { return new Object[] { null };}}; + + final Collection nullCollection = new ArrayList<>(); + nullCollection.add(null); + + THROWS(NullPointerException.class, + new F() { void f() { + new PriorityQueue(nullCollection); + }}, + new F() { void f() { + new PriorityBlockingQueue(nullCollection); + }}, + new F() { void f() { + new ArrayBlockingQueue(10, false, nullCollection); + }}, + new F() { void f() { + new ArrayBlockingQueue(10, true, nullCollection); + }}, + new F() { void f() { + new LinkedBlockingQueue(nullCollection); + }}, + new F() { void f() { + new LinkedBlockingDeque(nullCollection); + }}, + + new F() { void f() { + new PriorityQueue((Collection) nullPriorityQueue); + }}, + new F() { void f() { + new PriorityBlockingQueue((Collection) nullPriorityQueue); + }}, + + new F() { void f() { + new PriorityQueue(nullSortedSet); + }}, + new F() { void f() { + new PriorityBlockingQueue(nullSortedSet); + }}, + + new F() { void f() { + new PriorityQueue((Collection) nullSortedSet); + }}, + new F() { void f() { + new PriorityBlockingQueue((Collection) nullSortedSet); + }}, + + new F() { void f() { + new PriorityQueue(nullPriorityQueue); + }}, + new F() { void f() { + new PriorityBlockingQueue(nullPriorityQueue); + }}, + + new F() { void f() { + new PriorityQueue().add(null); + }}, + new F() { void f() { + new PriorityBlockingQueue().add(null); + }}, + new F() { void f() { + new ArrayBlockingQueue(10, false).add(null); + }}, + new F() { void f() { + new ArrayBlockingQueue(10, true).add(null); + }}, + new F() { void f() { + new LinkedBlockingQueue().add(null); + }}, + new F() { void f() { + new LinkedBlockingDeque().add(null); + }}, + + new F() { void f() { + new PriorityQueue().offer(null); + }}, + new F() { void f() { + new PriorityBlockingQueue().offer(null); + }}); + + nullSortedSet.add("foo"); + nullCollection.add("foo"); + THROWS(NullPointerException.class, + new F() { void f() { + new PriorityQueue(nullCollection); + }}, + new F() { void f() { + new PriorityBlockingQueue(nullCollection); + }}, + + new F() { void f() { + new PriorityQueue((Collection) nullPriorityQueue); + }}, + new F() { void f() { + new PriorityBlockingQueue((Collection) nullPriorityQueue); + }}, + + new F() { void f() { + new PriorityQueue(nullSortedSet); + }}, + new F() { void f() { + new PriorityBlockingQueue(nullSortedSet); + }}, + + new F() { void f() { + new PriorityQueue((Collection) nullSortedSet); + }}, + new F() { void f() { + new PriorityBlockingQueue((Collection) nullSortedSet); + }}); + + } + + //--------------------- Infrastructure --------------------------- + volatile int passed = 0, failed = 0; + void pass() {passed++;} + void fail() {failed++; Thread.dumpStack();} + void fail(String msg) {System.err.println(msg); fail();} + void unexpected(Throwable t) {failed++; t.printStackTrace();} + void check(boolean cond) {if (cond) pass(); else fail();} + void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + new NoNulls().instanceMain(args);} + public void instanceMain(String[] args) throws Throwable { + try {test(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} + abstract class F {abstract void f() throws Throwable;} + void THROWS(Class k, F... fs) { + for (F f : fs) + try {f.f(); fail("Expected " + k.getName() + " not thrown");} + catch (Throwable t) { + if (k.isAssignableFrom(t.getClass())) pass(); + else unexpected(t);}} +} From 75e3cde928811b1931a255bbe70e86ba4369d6dc Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Sun, 9 May 2010 16:03:13 -0700 Subject: [PATCH 21/23] 6937857: Concurrent calls to new Random() not random enough Seed uniquifier should use an independent PRNG Reviewed-by: dl --- jdk/src/share/classes/java/util/Random.java | 29 +++++++++++--- jdk/test/java/util/Random/DistinctSeeds.java | 40 +++++++++++++++++++- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/java/util/Random.java b/jdk/src/share/classes/java/util/Random.java index efe3f68a01a..b3381252bef 100644 --- a/jdk/src/share/classes/java/util/Random.java +++ b/jdk/src/share/classes/java/util/Random.java @@ -86,8 +86,23 @@ class Random implements java.io.Serializable { * the seed of the random number generator to a value very likely * to be distinct from any other invocation of this constructor. */ - public Random() { this(++seedUniquifier + System.nanoTime()); } - private static volatile long seedUniquifier = 8682522807148012L; + public Random() { + this(seedUniquifier() ^ System.nanoTime()); + } + + private static long seedUniquifier() { + // L'Ecuyer, "Tables of Linear Congruential Generators of + // Different Sizes and Good Lattice Structure", 1999 + for (;;) { + long current = seedUniquifier.get(); + long next = current * 181783497276652981L; + if (seedUniquifier.compareAndSet(current, next)) + return next; + } + } + + private static final AtomicLong seedUniquifier + = new AtomicLong(8682522807148012L); /** * Creates a new random number generator using a single {@code long} seed. @@ -103,8 +118,11 @@ class Random implements java.io.Serializable { * @see #setSeed(long) */ public Random(long seed) { - this.seed = new AtomicLong(0L); - setSeed(seed); + this.seed = new AtomicLong(initialScramble(seed)); + } + + private static long initialScramble(long seed) { + return (seed ^ multiplier) & mask; } /** @@ -127,8 +145,7 @@ class Random implements java.io.Serializable { * @param seed the initial seed */ synchronized public void setSeed(long seed) { - seed = (seed ^ multiplier) & mask; - this.seed.set(seed); + this.seed.set(initialScramble(seed)); haveNextNextGaussian = false; } diff --git a/jdk/test/java/util/Random/DistinctSeeds.java b/jdk/test/java/util/Random/DistinctSeeds.java index 795051b0298..736761ebb77 100644 --- a/jdk/test/java/util/Random/DistinctSeeds.java +++ b/jdk/test/java/util/Random/DistinctSeeds.java @@ -33,18 +33,54 @@ /* * @test - * @bug 4949279 + * @bug 4949279 6937857 * @summary Independent instantiations of Random() have distinct seeds. */ +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Random; public class DistinctSeeds { public static void main(String[] args) throws Exception { // Strictly speaking, it is possible for these to randomly fail, - // but the probability should be *extremely* small (< 2**-63). + // but the probability should be small (approximately 2**-48). if (new Random().nextLong() == new Random().nextLong() || new Random().nextLong() == new Random().nextLong()) throw new RuntimeException("Random() seeds not unique."); + + // Now try generating seeds concurrently + class RandomCollector implements Runnable { + long[] randoms = new long[1<<17]; + public void run() { + for (int i = 0; i < randoms.length; i++) + randoms[i] = new Random().nextLong(); + } + } + final int threadCount = 2; + List collectors = new ArrayList(); + List threads = new ArrayList(); + for (int i = 0; i < threadCount; i++) { + RandomCollector r = new RandomCollector(); + collectors.add(r); + threads.add(new Thread(r)); + } + for (Thread thread : threads) + thread.start(); + for (Thread thread : threads) + thread.join(); + int collisions = 0; + HashSet s = new HashSet(); + for (RandomCollector r : collectors) { + for (long x : r.randoms) { + if (s.contains(x)) + collisions++; + s.add(x); + } + } + System.out.printf("collisions=%d%n", collisions); + if (collisions > 10) + throw new Error("too many collisions"); } } From 3adf1d8538179a0a788bdaa34621e39c1eb7e8a2 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Sun, 9 May 2010 16:37:06 -0700 Subject: [PATCH 22/23] 6937842: Unreadable \uXXXX in javadoc Replace \uXXXX by \u005CXXXX, or simply delete Reviewed-by: sherman --- jdk/src/share/classes/java/lang/String.java | 8 ++++---- jdk/src/share/classes/java/util/zip/Deflater.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java index 2aead0f545d..918b4dee02e 100644 --- a/jdk/src/share/classes/java/lang/String.java +++ b/jdk/src/share/classes/java/lang/String.java @@ -2551,8 +2551,8 @@ public final class String * Examples are programming language identifiers, protocol keys, and HTML * tags. * For instance, "TITLE".toLowerCase() in a Turkish locale - * returns "t\u0131tle", where '\u0131' is the LATIN SMALL - * LETTER DOTLESS I character. + * returns "t\u005Cu0131tle", where '\u005Cu0131' is the + * LATIN SMALL LETTER DOTLESS I character. * To obtain correct results for locale insensitive strings, use * toLowerCase(Locale.ENGLISH). *

@@ -2714,8 +2714,8 @@ public final class String * Examples are programming language identifiers, protocol keys, and HTML * tags. * For instance, "title".toUpperCase() in a Turkish locale - * returns "T\u0130TLE", where '\u0130' is the LATIN CAPITAL - * LETTER I WITH DOT ABOVE character. + * returns "T\u005Cu0130TLE", where '\u005Cu0130' is the + * LATIN CAPITAL LETTER I WITH DOT ABOVE character. * To obtain correct results for locale insensitive strings, use * toUpperCase(Locale.ENGLISH). *

diff --git a/jdk/src/share/classes/java/util/zip/Deflater.java b/jdk/src/share/classes/java/util/zip/Deflater.java index 9c4c0ce6c8c..abc1b6541ed 100644 --- a/jdk/src/share/classes/java/util/zip/Deflater.java +++ b/jdk/src/share/classes/java/util/zip/Deflater.java @@ -40,7 +40,7 @@ package java.util.zip; *

  * try {
  *     // Encode a String into bytes
- *     String inputString = "blahblahblah\u20AC\u20AC";
+ *     String inputString = "blahblahblah";
  *     byte[] input = inputString.getBytes("UTF-8");
  *
  *     // Compress the bytes

From 5545514e602ec90fcc1632095b1f270e56f260fb Mon Sep 17 00:00:00 2001
From: Anthony Petrov 
Date: Tue, 18 May 2010 19:35:41 +0400
Subject: [PATCH 23/23] 6953275: Many Swing tests are failing because of a GTK
 lib

Reviewed-by: art, dcherepanov
---
 jdk/src/solaris/native/sun/awt/gtk2_interface.c | 13 ++++++++-----
 jdk/src/solaris/native/sun/awt/gtk2_interface.h |  1 -
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c
index dfa7ef1dfb4..ee1c3cc7856 100644
--- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c
+++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c
@@ -77,6 +77,7 @@ const gint DEFAULT    = 1 << 10;
 
 static void *gtk2_libhandle = NULL;
 static void *gthread_libhandle = NULL;
+static gboolean flag_g_thread_get_initialized = FALSE;
 static jmp_buf j;
 
 /* Widgets */
@@ -436,8 +437,10 @@ void gtk2_file_chooser_load()
     fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");
     fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");
     fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");
-    fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(
-            "gtk_file_chooser_set_do_overwrite_confirmation");
+    if (fp_gtk_check_version(2, 8, 0) == NULL) {
+        fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(
+                "gtk_file_chooser_set_do_overwrite_confirmation");
+    }
     fp_gtk_file_chooser_set_select_multiple = dl_symbol(
             "gtk_file_chooser_set_select_multiple");
     fp_gtk_file_chooser_get_current_folder = dl_symbol(
@@ -641,8 +644,6 @@ gboolean gtk2_load()
         /**
          * GLib thread system
          */
-        fp_g_thread_get_initialized = dl_symbol_gthread(
-                "g_thread_get_initialized");
         fp_g_thread_init = dl_symbol_gthread("g_thread_init");
         fp_gdk_threads_init = dl_symbol("gdk_threads_init");
         fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");
@@ -744,7 +745,9 @@ gboolean gtk2_load()
 
     if (fp_gtk_check_version(2, 2, 0) == NULL) {
         // Init the thread system to use GLib in a thread-safe mode
-        if (!fp_g_thread_get_initialized()) {
+        if (!flag_g_thread_get_initialized) {
+            flag_g_thread_get_initialized = TRUE;
+
             fp_g_thread_init(NULL);
 
             //According the GTK documentation, gdk_threads_init() should be
diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.h b/jdk/src/solaris/native/sun/awt/gtk2_interface.h
index 95ca3cecaad..fc401c1bc12 100644
--- a/jdk/src/solaris/native/sun/awt/gtk2_interface.h
+++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.h
@@ -786,7 +786,6 @@ void (*fp_gtk_main)(void);
 guint (*fp_gtk_main_level)(void);
 
 
-gboolean (*fp_g_thread_get_initialized)(void);
 void (*fp_g_thread_init)(GThreadFunctions *vtable);
 void (*fp_gdk_threads_init)(void);
 void (*fp_gdk_threads_enter)(void);