--- a/jdk/make/com/Makefile Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/com/Makefile Thu Sep 16 11:19:43 2010 -0700
@@ -31,7 +31,7 @@
PRODUCT = com
include $(BUILDDIR)/common/Defs.gmk
-SUBDIRS = sun
+SUBDIRS = sun oracle
include $(BUILDDIR)/common/Subdirs.gmk
all build clean clobber::
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/oracle/Makefile Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+BUILDDIR = ../..
+PRODUCT = oracle
+include $(BUILDDIR)/common/Defs.gmk
+
+SUBDIRS = net
+include $(BUILDDIR)/common/Subdirs.gmk
+
+all build clean clobber::
+ $(SUBDIRS-loop)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/oracle/net/Makefile Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+BUILDDIR = ../../..
+PRODUCT = oracle
+include $(BUILDDIR)/common/Defs.gmk
+
+#
+# Files to compile
+#
+AUTO_FILES_JAVA_DIRS = com/oracle/net
+
+#
+# Rules
+#
+include $(BUILDDIR)/common/Classes.gmk
+
--- a/jdk/make/common/Release.gmk Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/common/Release.gmk Thu Sep 16 11:19:43 2010 -0700
@@ -573,13 +573,13 @@
$(ECHO) "sun/jvmstat/" >> $@
$(ECHO) "sun/nio/cs/ext/" >> $@
$(ECHO) "sun/awt/HKSCS.class" >> $@
- $(ECHO) "sun/awt/motif/X11GB2312$Decoder.class" >> $@
- $(ECHO) "sun/awt/motif/X11GB2312$Encoder.class" >> $@
+ $(ECHO) "sun/awt/motif/X11GB2312\$$Decoder.class" >> $@
+ $(ECHO) "sun/awt/motif/X11GB2312\$$Encoder.class" >> $@
$(ECHO) "sun/awt/motif/X11GB2312.class" >> $@
- $(ECHO) "sun/awt/motif/X11GBK$Encoder.class" >> $@
+ $(ECHO) "sun/awt/motif/X11GBK\$$Encoder.class" >> $@
$(ECHO) "sun/awt/motif/X11GBK.class" >> $@
- $(ECHO) "sun/awt/motif/X11KSC5601$Decoder.class" >> $@
- $(ECHO) "sun/awt/motif/X11KSC5601$Encoder.class" >> $@
+ $(ECHO) "sun/awt/motif/X11KSC5601\$$Decoder.class" >> $@
+ $(ECHO) "sun/awt/motif/X11KSC5601\$$Encoder.class" >> $@
$(ECHO) "sun/awt/motif/X11KSC5601.class" >> $@
$(ECHO) "sun/rmi/rmic/" >> $@
$(ECHO) "sun/tools/asm/" >> $@
--- a/jdk/make/docs/NON_CORE_PKGS.gmk Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk Thu Sep 16 11:19:43 2010 -0700
@@ -91,6 +91,8 @@
TRACING_PKGS = com.sun.tracing \
com.sun.tracing.dtrace
+ORACLENET_PKGS = com.oracle.net
+
# non-core packages in rt.jar
NON_CORE_PKGS = $(DOMAPI_PKGS) \
$(MGMT_PKGS) \
@@ -101,5 +103,6 @@
$(HTTPSERVER_PKGS) \
$(SMARTCARDIO_PKGS) \
$(TRACING_PKGS) \
- $(SCTPAPI_PKGS)
+ $(SCTPAPI_PKGS) \
+ $(ORACLENET_PKGS)
--- a/jdk/make/java/net/FILES_c.gmk Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/net/FILES_c.gmk Thu Sep 16 11:19:43 2010 -0700
@@ -39,10 +39,6 @@
ResolverConfigurationImpl.c \
DefaultProxySelector.c
-ifeq ($(PLATFORM), solaris)
- FILES_c += SdpProvider.c
-endif
-
ifeq ($(PLATFORM), linux)
FILES_c += linux_close.c
endif
--- a/jdk/make/java/net/Makefile Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/net/Makefile Thu Sep 16 11:19:43 2010 -0700
@@ -44,6 +44,8 @@
endif
FILES_c += NTLMAuthSequence.c
FILES_c += NetworkInterface_winXP.c
+else
+ FILES_c += SdpSupport.c
endif
FILES_export = \
@@ -84,7 +86,8 @@
#
# Find platform specific native code
#
-vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi
+vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm \
+ $(PLATFORM_SRC)/native/sun/net/sdp $(PLATFORM_SRC)/native/sun/net/spi
#
# Include rules
--- a/jdk/make/java/net/mapfile-vers Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/net/mapfile-vers Thu Sep 16 11:19:43 2010 -0700
@@ -88,9 +88,10 @@
Java_java_net_PlainDatagramSocketImpl_setTimeToLive;
Java_sun_net_dns_ResolverConfigurationImpl_localDomain0;
Java_sun_net_dns_ResolverConfigurationImpl_fallbackDomain0;
+ Java_sun_net_sdp_SdpSupport_convert0;
+ Java_sun_net_sdp_SdpSupport_create0;
Java_sun_net_spi_DefaultProxySelector_init;
Java_sun_net_spi_DefaultProxySelector_getSystemProxy;
- Java_sun_net_spi_SdpProvider_convert;
NET_AllocSockaddr;
NET_SockaddrToInetAddress;
NET_SockaddrEqualsInetAddress;
--- a/jdk/make/java/nio/FILES_java.gmk Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/nio/FILES_java.gmk Thu Sep 16 11:19:43 2010 -0700
@@ -83,6 +83,7 @@
java/nio/file/ClosedFileSystemException.java \
java/nio/file/ClosedWatchServiceException.java \
java/nio/file/CopyOption.java \
+ java/nio/file/DirectoryIteratorException.java \
java/nio/file/DirectoryNotEmptyException.java \
java/nio/file/DirectoryStream.java \
java/nio/file/FileAlreadyExistsException.java \
@@ -199,6 +200,7 @@
sun/nio/ch/PipeImpl.java \
sun/nio/ch/PollArrayWrapper.java \
sun/nio/ch/Reflect.java \
+ sun/nio/ch/Secrets.java \
sun/nio/ch/SelectionKeyImpl.java \
sun/nio/ch/SelectorImpl.java \
sun/nio/ch/SelectorProviderImpl.java \
--- a/jdk/make/java/nio/mapfile-linux Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/nio/mapfile-linux Thu Sep 16 11:19:43 2010 -0700
@@ -89,7 +89,7 @@
Java_sun_nio_ch_IOUtil_drain;
Java_sun_nio_ch_IOUtil_fdVal;
Java_sun_nio_ch_IOUtil_initIDs;
- Java_sun_nio_ch_IOUtil_initPipe;
+ Java_sun_nio_ch_IOUtil_makePipe;
Java_sun_nio_ch_IOUtil_randomBytes;
Java_sun_nio_ch_IOUtil_setfdVal;
Java_sun_nio_ch_NativeThread_current;
--- a/jdk/make/java/nio/mapfile-solaris Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/java/nio/mapfile-solaris Thu Sep 16 11:19:43 2010 -0700
@@ -76,7 +76,7 @@
Java_sun_nio_ch_IOUtil_drain;
Java_sun_nio_ch_IOUtil_fdVal;
Java_sun_nio_ch_IOUtil_initIDs;
- Java_sun_nio_ch_IOUtil_initPipe;
+ Java_sun_nio_ch_IOUtil_makePipe;
Java_sun_nio_ch_IOUtil_randomBytes;
Java_sun_nio_ch_IOUtil_setfdVal;
Java_sun_nio_ch_NativeThread_current;
--- a/jdk/make/sun/net/FILES_java.gmk Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/make/sun/net/FILES_java.gmk Thu Sep 16 11:19:43 2010 -0700
@@ -53,6 +53,7 @@
sun/net/ftp/FtpProtocolException.java \
sun/net/ftp/impl/FtpClient.java \
sun/net/ftp/impl/DefaultFtpClientProvider.java \
+ sun/net/sdp/SdpSupport.java \
sun/net/spi/DefaultProxySelector.java \
sun/net/spi/nameservice/NameServiceDescriptor.java \
sun/net/spi/nameservice/NameService.java \
@@ -136,8 +137,6 @@
ifeq ($(PLATFORM), windows)
FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java
+else
+ FILES_java += sun/net/sdp/SdpProvider.java
endif
-
-ifeq ($(PLATFORM), solaris)
- FILES_java += sun/net/spi/SdpProvider.java
-endif
--- a/jdk/src/share/bin/java.c Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/bin/java.c Thu Sep 16 11:19:43 2010 -0700
@@ -712,19 +712,19 @@
struct stat statbuf;
/* return if jre/lib/rt.jar exists */
- sprintf(pathname, "%s%slib%srt.jar", jrepath, separator, separator);
+ JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%srt.jar", jrepath, separator, separator);
if (stat(pathname, &statbuf) == 0) {
return;
}
/* return if jre/classes exists */
- sprintf(pathname, "%s%sclasses", jrepath, separator);
+ JLI_Snprintf(pathname, sizeof(pathname), "%s%sclasses", jrepath, separator);
if (stat(pathname, &statbuf) == 0) {
return;
}
/* modularized jre */
- sprintf(pathname, "%s%slib%s*", jrepath, separator, separator);
+ JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%s*", jrepath, separator, separator);
s = (char *) JLI_WildcardExpandClasspath(pathname);
def = JLI_MemAlloc(sizeof(format)
- 2 /* strlen("%s") */
@@ -1624,11 +1624,8 @@
if (JLI_IsTraceLauncher()) {
start = CounterGet();
}
-
- JLI_StrCpy(jvmCfgName, jrepath);
- JLI_StrCat(jvmCfgName, FILESEP "lib" FILESEP);
- JLI_StrCat(jvmCfgName, arch);
- JLI_StrCat(jvmCfgName, FILESEP "jvm.cfg");
+ JLI_Snprintf(jvmCfgName, sizeof(jvmCfgName), "%s%slib%s%s%sjvm.cfg",
+ jrepath, FILESEP, FILESEP, arch, FILESEP);
jvmCfg = fopen(jvmCfgName, "r");
if (jvmCfg == NULL) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/oracle/net/Sdp.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.net;
+
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.net.SocketImpl;
+import java.net.SocketImplFactory;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.InvocationTargetException;
+
+import sun.net.sdp.SdpSupport;
+
+/**
+ * This class consists exclusively of static methods that Sockets or Channels to
+ * sockets that support the InfiniBand Sockets Direct Protocol (SDP).
+ */
+
+public final class Sdp {
+ private Sdp() { }
+
+ /**
+ * The package-privage ServerSocket(SocketImpl) constructor
+ */
+ private static final Constructor<ServerSocket> serverSocketCtor;
+ static {
+ try {
+ serverSocketCtor = (Constructor<ServerSocket>)
+ ServerSocket.class.getDeclaredConstructor(SocketImpl.class);
+ setAccessible(serverSocketCtor);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /**
+ * The package-private SdpSocketImpl() constructor
+ */
+ private static final Constructor<SocketImpl> socketImplCtor;
+ static {
+ try {
+ Class<?> cl = Class.forName("java.net.SdpSocketImpl", true, null);
+ socketImplCtor = (Constructor<SocketImpl>)cl.getDeclaredConstructor();
+ setAccessible(socketImplCtor);
+ } catch (ClassNotFoundException e) {
+ throw new AssertionError(e);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private static void setAccessible(final AccessibleObject o) {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ o.setAccessible(true);
+ return null;
+ }
+ });
+ }
+
+ /**
+ * SDP enabled Socket.
+ */
+ private static class SdpSocket extends Socket {
+ SdpSocket(SocketImpl impl) throws SocketException {
+ super(impl);
+ }
+ }
+
+ /**
+ * Creates a SDP enabled SocketImpl
+ */
+ private static SocketImpl createSocketImpl() {
+ try {
+ return socketImplCtor.newInstance();
+ } catch (InstantiationException x) {
+ throw new AssertionError(x);
+ } catch (IllegalAccessException x) {
+ throw new AssertionError(x);
+ } catch (InvocationTargetException x) {
+ throw new AssertionError(x);
+ }
+ }
+
+ /**
+ * Creates an unconnected and unbound SDP socket. The {@code Socket} is
+ * associated with a {@link java.net.SocketImpl} of the system-default type.
+ *
+ * @return a new Socket
+ *
+ * @throws UnsupportedOperationException
+ * If SDP is not supported
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static Socket openSocket() throws IOException {
+ SocketImpl impl = createSocketImpl();
+ return new SdpSocket(impl);
+ }
+
+ /**
+ * Creates an unbound SDP server socket. The {@code ServerSocket} is
+ * associated with a {@link java.net.SocketImpl} of the system-default type.
+ *
+ * @return a new ServerSocket
+ *
+ * @throws UnsupportedOperationException
+ * If SDP is not supported
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static ServerSocket openServerSocket() throws IOException {
+ // create ServerSocket via package-private constructor
+ SocketImpl impl = createSocketImpl();
+ try {
+ return serverSocketCtor.newInstance(impl);
+ } catch (IllegalAccessException x) {
+ throw new AssertionError(x);
+ } catch (InstantiationException x) {
+ throw new AssertionError(x);
+ } catch (InvocationTargetException x) {
+ Throwable cause = x.getCause();
+ if (cause instanceof IOException)
+ throw (IOException)cause;
+ if (cause instanceof RuntimeException)
+ throw (RuntimeException)cause;
+ throw new RuntimeException(x);
+ }
+ }
+
+ /**
+ * Opens a socket channel to a SDP socket.
+ *
+ * <p> The channel will be associated with the system-wide default
+ * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}.
+ *
+ * @return a new SocketChannel
+ *
+ * @throws UnsupportedOperationException
+ * If SDP is not supported or not supported by the default selector
+ * provider
+ * @throws IOException
+ * If an I/O error occurs.
+ */
+ public static SocketChannel openSocketChannel() throws IOException {
+ FileDescriptor fd = SdpSupport.createSocket();
+ return sun.nio.ch.Secrets.newSocketChannel(fd);
+ }
+
+ /**
+ * Opens a socket channel to a SDP socket.
+ *
+ * <p> The channel will be associated with the system-wide default
+ * {@link java.nio.channels.spi.SelectorProvider SelectorProvider}.
+ *
+ * @return a new ServerSocketChannel
+ *
+ * @throws UnsupportedOperationException
+ * If SDP is not supported or not supported by the default selector
+ * provider
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static ServerSocketChannel openServerSocketChannel()
+ throws IOException
+ {
+ FileDescriptor fd = SdpSupport.createSocket();
+ return sun.nio.ch.Secrets.newServerSocketChannel(fd);
+ }
+}
--- a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -518,7 +518,7 @@
setReadOnly(true);
setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
setEscapeProcessing(true);
- setTypeMap(null);
+ //setTypeMap(null);
checkTransactionalWriter();
//Instantiating the vector for MatchColumns
@@ -679,7 +679,10 @@
} else if (obj instanceof Clob) {
obj = new SerialClob((Clob)obj);
} else if (obj instanceof java.sql.Array) {
- obj = new SerialArray((java.sql.Array)obj, map);
+ if(map != null)
+ obj = new SerialArray((java.sql.Array)obj, map);
+ else
+ obj = new SerialArray((java.sql.Array)obj);
}
((Row)currentRow).initColumnObject(i, obj);
@@ -762,7 +765,7 @@
if( conn != null){
// JDBC 4.0 mandates as does the Java EE spec that all DataBaseMetaData methods
// must be implemented, therefore, the previous fix for 5055528 is being backed out
- dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy();
+ dbmslocatorsUpdateCopy = conn.getMetaData().locatorsUpdateCopy();
}
}
@@ -6322,6 +6325,7 @@
crs.RowSetMD = RowSetMD;
crs.numRows = 1;
crs.cursorPos = 0;
+ crs.setTypeMap(this.getTypeMap());
// make sure we don't get someone playing with these
// %%% is this now necessary ???
@@ -10114,7 +10118,7 @@
* during the deserialization process
*
*/
- protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Default state initialization happens here
ois.defaultReadObject();
// Initialization of transient Res Bundle happens here .
@@ -10125,5 +10129,15 @@
}
}
- static final long serialVersionUID =1884577171200622428L;
+
+ //------------------------- JDBC 4.1 -----------------------------------
+ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Not supported yet.");
+ }
+
+ public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Not supported yet.");
+ }
+
+ static final long serialVersionUID =1884577171200622428L;
}
--- a/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/FilteredRowSetImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1746,5 +1746,23 @@
onInsertRow = false;
super.insertRow();
}
- static final long serialVersionUID = 6178454588413509360L;
+
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = 6178454588413509360L;
} // end FilteredRowSetImpl class
--- a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -101,7 +101,7 @@
private Vector strMatchColumns;
- protected transient JdbcRowSetResourceBundle jdbcResBundle;
+ protected transient JdbcRowSetResourceBundle resBundle;
/**
* Constructs a default <code>JdbcRowSet</code> object.
@@ -140,7 +140,7 @@
rs = null;
try {
- jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
@@ -154,42 +154,42 @@
try {
setShowDeleted(false);
} catch(SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setshowdeleted").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setshowdeleted").toString() +
sqle.getLocalizedMessage());
}
try {
setQueryTimeout(0);
} catch(SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() +
sqle.getLocalizedMessage());
}
try {
setMaxRows(0);
} catch(SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() +
sqle.getLocalizedMessage());
}
try {
setMaxFieldSize(0);
} catch(SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() +
sqle.getLocalizedMessage());
}
try {
setEscapeProcessing(true);
} catch(SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() +
sqle.getLocalizedMessage());
}
try {
setConcurrency(ResultSet.CONCUR_UPDATABLE);
} catch (SQLException sqle) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setconcurrency").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setconcurrency").toString() +
sqle.getLocalizedMessage());
}
@@ -198,7 +198,7 @@
try {
setType(ResultSet.TYPE_SCROLL_INSENSITIVE);
} catch(SQLException sqle){
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.settype").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.settype").toString() +
sqle.getLocalizedMessage());
}
@@ -207,7 +207,7 @@
try {
setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} catch(SQLException sqle){
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.settransactionisolation").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.settransactionisolation").toString() +
sqle.getLocalizedMessage());
}
@@ -263,7 +263,7 @@
rs = null;
try {
- jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
@@ -338,7 +338,7 @@
rs = null;
try {
- jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
@@ -430,7 +430,7 @@
rs = res;
try {
- jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
} catch(IOException ioe) {
throw new RuntimeException(ioe);
}
@@ -517,7 +517,7 @@
// to the db, implies undesirable state so throw exception
if (conn == null && ps == null && rs == null ) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.invalstate").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.invalstate").toString());
}
}
@@ -593,28 +593,28 @@
try {
ps.setEscapeProcessing(getEscapeProcessing());
} catch (SQLException ex) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setescapeprocessing").toString() +
ex.getLocalizedMessage());
}
try {
ps.setMaxFieldSize(getMaxFieldSize());
} catch (SQLException ex) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxfieldsize").toString() +
ex.getLocalizedMessage());
}
try {
ps.setMaxRows(getMaxRows());
} catch (SQLException ex) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setmaxrows").toString() +
ex.getLocalizedMessage());
}
try {
ps.setQueryTimeout(getQueryTimeout());
} catch (SQLException ex) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.setquerytimeout").toString() +
ex.getLocalizedMessage());
}
@@ -651,7 +651,7 @@
}
}
catch (javax.naming.NamingException ex) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
}
} else if (getUrl() != null) {
@@ -681,7 +681,7 @@
}
ps = conn.prepareStatement(getCommand(),ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
} catch (SQLException ex) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.prepare").toString() +
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.prepare").toString() +
ex.getLocalizedMessage());
if (ps != null)
@@ -721,15 +721,15 @@
if (param[0] instanceof java.sql.Date ||
param[0] instanceof java.sql.Time ||
param[0] instanceof java.sql.Timestamp) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.detecteddate"));
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.detecteddate"));
if (param[1] instanceof java.util.Calendar) {
- System.err.println(jdbcResBundle.handleGetObject("jdbcrowsetimpl.detectedcalendar"));
+ System.err.println(resBundle.handleGetObject("jdbcrowsetimpl.detectedcalendar"));
ps.setDate(i + 1, (java.sql.Date)param[0],
(java.util.Calendar)param[1]);
continue;
}
else {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
}
}
@@ -770,7 +770,7 @@
(java.io.InputStream)param[0],
((Integer)param[1]).intValue());
default:
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
}
}
@@ -784,7 +784,7 @@
continue;
}
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.paramtype").toString());
} else {
// common case - this catches all SQL92 types
@@ -3749,7 +3749,7 @@
for( int j= 0 ;j < columnIdxes.length; j++) {
i_val = (Integer.parseInt(iMatchColumns.get(j).toString()));
if(columnIdxes[j] != i_val) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString());
}
}
@@ -3776,7 +3776,7 @@
for(int j = 0 ;j < columnIdxes.length; j++) {
if( !columnIdxes[j].equals(strMatchColumns.get(j)) ){
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols").toString());
}
}
@@ -3800,7 +3800,7 @@
String []str_temp = new String[strMatchColumns.size()];
if( strMatchColumns.get(0) == null) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString());
}
strMatchColumns.copyInto(str_temp);
@@ -3825,7 +3825,7 @@
i_val = ((Integer)iMatchColumns.get(0)).intValue();
if( i_val == -1 ) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.setmatchcols").toString());
}
@@ -3859,7 +3859,7 @@
for(int j = 0 ; j < columnIdxes.length; j++) {
if( columnIdxes[j] < 0 ) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString());
}
}
for(int i = 0 ;i < columnIdxes.length; i++) {
@@ -3886,7 +3886,7 @@
for(int j = 0; j < columnNames.length; j++) {
if( columnNames[j] == null || columnNames[j].equals("")) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString());
}
}
for( int i = 0; i < columnNames.length; i++) {
@@ -3915,7 +3915,7 @@
public void setMatchColumn(int columnIdx) throws SQLException {
// validate, if col is ok to be set
if(columnIdx < 0) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols1").toString());
} else {
// set iMatchColumn
iMatchColumns.set(0, new Integer(columnIdx));
@@ -3941,7 +3941,7 @@
public void setMatchColumn(String columnName) throws SQLException {
// validate, if col is ok to be set
if(columnName.equals(null) || ((columnName = columnName.trim()) == "" )) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.matchcols2").toString());
} else {
// set strMatchColumn
strMatchColumns.set(0, columnName);
@@ -3966,9 +3966,9 @@
public void unsetMatchColumn(int columnIdx) throws SQLException {
// check if we are unsetting the SAME column
if(! iMatchColumns.get(0).equals(new Integer(columnIdx) ) ) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString());
} else if(strMatchColumns.get(0) != null) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.usecolname").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.usecolname").toString());
} else {
// that is, we are unsetting it.
iMatchColumns.set(0, new Integer(-1));
@@ -3995,9 +3995,9 @@
columnName = columnName.trim();
if(!((strMatchColumns.get(0)).equals(columnName))) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.unsetmatch").toString());
} else if( ((Integer)(iMatchColumns.get(0))).intValue() > 0) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.usecolid").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.usecolid").toString());
} else {
strMatchColumns.set(0, null); // that is, we are unsetting it.
}
@@ -4152,7 +4152,7 @@
private void checkTypeConcurrency() throws SQLException {
if(rs.getType() == TYPE_FORWARD_ONLY ||
rs.getConcurrency() == CONCUR_READ_ONLY) {
- throw new SQLException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.resnotupd").toString());
+ throw new SQLException(resBundle.handleGetObject("jdbcrowsetimpl.resnotupd").toString());
}
}
@@ -4642,7 +4642,7 @@
* @since 6.0
*/
public SQLXML getSQLXML(int columnIndex) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4653,7 +4653,7 @@
* @throws SQLException if a database access error occurs
*/
public SQLXML getSQLXML(String colName) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4668,7 +4668,7 @@
* @since 6.0
*/
public RowId getRowId(int columnIndex) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4683,7 +4683,7 @@
* @since 6.0
*/
public RowId getRowId(String columnName) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4699,7 +4699,7 @@
* @since 6.0
*/
public void updateRowId(int columnIndex, RowId x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4715,7 +4715,7 @@
* @since 6.0
*/
public void updateRowId(String columnName, RowId x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4725,7 +4725,7 @@
* @since 6.0
*/
public int getHoldability() throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4736,7 +4736,7 @@
* @since 6.0
*/
public boolean isClosed() throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4748,7 +4748,7 @@
* @since 6.0
*/
public void updateNString(int columnIndex, String nString) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4760,7 +4760,7 @@
* @since 6.0
*/
public void updateNString(String columnName, String nString) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4773,7 +4773,7 @@
* @since 6.0
*/
public void updateNClob(int columnIndex, NClob nClob) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4785,7 +4785,7 @@
* @since 6.0
*/
public void updateNClob(String columnName, NClob nClob) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4800,7 +4800,7 @@
* @since 6.0
*/
public NClob getNClob(int i) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4816,7 +4816,7 @@
* @since 6.0
*/
public NClob getNClob(String colName) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
public <T> T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException{
@@ -4836,7 +4836,7 @@
* @since 1.6
*/
public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4848,7 +4848,7 @@
* @since 1.6
*/
public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4863,7 +4863,7 @@
* @since 1.6
*/
public void setRowId(int parameterIndex, RowId x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4877,7 +4877,7 @@
* @since 1.6
*/
public void setRowId(String parameterName, RowId x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4897,7 +4897,7 @@
* @since 1.6
*/
public void setNString(int parameterIndex, String value) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4925,7 +4925,7 @@
* @since 1.6
*/
public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4940,7 +4940,7 @@
* @since 1.6
*/
public void setNClob(String parameterName, NClob value) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4960,7 +4960,7 @@
* @since 1.6
*/
public java.io.Reader getNCharacterStream(int columnIndex) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -4980,7 +4980,7 @@
* @since 1.6
*/
public java.io.Reader getNCharacterStream(String columnName) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -4996,7 +4996,7 @@
* @since 1.6
*/
public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5013,7 +5013,7 @@
* @since 1.6
*/
public void updateSQLXML(String columnName, SQLXML xmlObject) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5031,7 +5031,7 @@
* @since 1.6
*/
public String getNString(int columnIndex) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5049,7 +5049,7 @@
* @since 1.6
*/
public String getNString(String columnName) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5071,7 +5071,7 @@
java.io.Reader x,
long length)
throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5093,7 +5093,7 @@
java.io.Reader x,
long length)
throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5123,7 +5123,7 @@
*/
public void updateNCharacterStream(int columnIndex,
java.io.Reader x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5155,7 +5155,7 @@
*/
public void updateNCharacterStream(String columnLabel,
java.io.Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5188,7 +5188,7 @@
* @since 1.6
*/
public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5221,7 +5221,7 @@
* @since 1.6
*/
public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5256,7 +5256,7 @@
* @since 1.6
*/
public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5291,7 +5291,7 @@
* @since 1.6
*/
public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5323,7 +5323,7 @@
* @since 1.6
*/
public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5355,7 +5355,7 @@
* @since 1.6
*/
public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5389,7 +5389,7 @@
* @since 1.6
*/
public void updateClob(int columnIndex, Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5424,7 +5424,7 @@
* @since 1.6
*/
public void updateClob(String columnLabel, Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5458,7 +5458,7 @@
* @since 1.6
*/
public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5492,7 +5492,7 @@
* @since 1.6
*/
public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5528,7 +5528,7 @@
* @since 1.6
*/
public void updateNClob(int columnIndex, Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5565,7 +5565,7 @@
* @since 1.6
*/
public void updateNClob(String columnLabel, Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5590,7 +5590,7 @@
public void updateAsciiStream(int columnIndex,
java.io.InputStream x,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5614,7 +5614,7 @@
public void updateBinaryStream(int columnIndex,
java.io.InputStream x,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5638,7 +5638,7 @@
public void updateCharacterStream(int columnIndex,
java.io.Reader x,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5662,7 +5662,7 @@
public void updateAsciiStream(String columnLabel,
java.io.InputStream x,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5687,7 +5687,7 @@
*/
public void updateAsciiStream(int columnIndex,
java.io.InputStream x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5713,7 +5713,7 @@
*/
public void updateAsciiStream(String columnLabel,
java.io.InputStream x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5738,7 +5738,7 @@
public void updateBinaryStream(String columnLabel,
java.io.InputStream x,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5763,7 +5763,7 @@
*/
public void updateBinaryStream(int columnIndex,
java.io.InputStream x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5790,7 +5790,7 @@
*/
public void updateBinaryStream(String columnLabel,
java.io.InputStream x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5816,7 +5816,7 @@
public void updateCharacterStream(String columnLabel,
java.io.Reader reader,
long length) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5841,7 +5841,7 @@
*/
public void updateCharacterStream(int columnIndex,
java.io.Reader x) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5868,7 +5868,7 @@
*/
public void updateCharacterStream(String columnLabel,
java.io.Reader reader) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5885,7 +5885,7 @@
* @since 1.4
*/
public void setURL(int parameterIndex, java.net.URL x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5914,7 +5914,7 @@
*/
public void setNClob(int parameterIndex, Reader reader)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -5942,7 +5942,7 @@
*/
public void setNClob(String parameterName, Reader reader, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5969,7 +5969,7 @@
*/
public void setNClob(String parameterName, Reader reader)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -5996,7 +5996,7 @@
*/
public void setNClob(int parameterIndex, Reader reader, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6012,7 +6012,7 @@
* @since 1.6
*/
public void setNClob(int parameterIndex, NClob value) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6029,7 +6029,7 @@
*/
public void setNString(String parameterName, String value)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6046,7 +6046,7 @@
* @since 1.6
*/
public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6066,7 +6066,7 @@
*/
public void setNCharacterStream(String parameterName, Reader value, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6092,7 +6092,7 @@
* @since 1.6
*/
public void setNCharacterStream(String parameterName, Reader value) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6118,7 +6118,7 @@
*/
public void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6144,7 +6144,7 @@
*/
public void setClob(String parameterName, Reader reader, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6163,7 +6163,7 @@
* @since 1.6
*/
public void setClob (String parameterName, Clob x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6188,7 +6188,7 @@
*/
public void setClob(String parameterName, Reader reader)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6210,7 +6210,7 @@
*/
public void setDate(String parameterName, java.sql.Date x)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6236,7 +6236,7 @@
*/
public void setDate(String parameterName, java.sql.Date x, Calendar cal)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6256,7 +6256,7 @@
*/
public void setTime(String parameterName, java.sql.Time x)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6282,7 +6282,7 @@
*/
public void setTime(String parameterName, java.sql.Time x, Calendar cal)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6308,7 +6308,7 @@
*/
public void setClob(int parameterIndex, Reader reader)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6333,7 +6333,7 @@
*/
public void setClob(int parameterIndex, Reader reader, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6363,7 +6363,7 @@
*/
public void setBlob(int parameterIndex, InputStream inputStream, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6395,7 +6395,7 @@
*/
public void setBlob(int parameterIndex, InputStream inputStream)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6426,7 +6426,7 @@
*/
public void setBlob(String parameterName, InputStream inputStream, long length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6444,7 +6444,7 @@
* @since 1.6
*/
public void setBlob (String parameterName, Blob x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6470,7 +6470,7 @@
*/
public void setBlob(String parameterName, InputStream inputStream)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6516,7 +6516,7 @@
*/
public void setObject(String parameterName, Object x, int targetSqlType, int scale)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6542,7 +6542,7 @@
*/
public void setObject(String parameterName, Object x, int targetSqlType)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6582,7 +6582,7 @@
* @since 1.4
*/
public void setObject(String parameterName, Object x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6609,7 +6609,7 @@
*/
public void setAsciiStream(String parameterName, java.io.InputStream x, int length)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6636,7 +6636,7 @@
*/
public void setBinaryStream(String parameterName, java.io.InputStream x,
int length) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6665,7 +6665,7 @@
public void setCharacterStream(String parameterName,
java.io.Reader reader,
int length) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6692,7 +6692,7 @@
*/
public void setAsciiStream(String parameterName, java.io.InputStream x)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6719,7 +6719,7 @@
*/
public void setBinaryStream(String parameterName, java.io.InputStream x)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6748,7 +6748,7 @@
*/
public void setCharacterStream(String parameterName,
java.io.Reader reader) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6767,7 +6767,7 @@
* @since 1.4
*/
public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6788,7 +6788,7 @@
* @since 1.4
*/
public void setString(String parameterName, String x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6810,7 +6810,7 @@
* @since 1.4
*/
public void setBytes(String parameterName, byte x[]) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6830,7 +6830,7 @@
*/
public void setTimestamp(String parameterName, java.sql.Timestamp x)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6847,7 +6847,7 @@
* @since 1.4
*/
public void setNull(String parameterName, int sqlType) throws SQLException {
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6884,7 +6884,7 @@
*/
public void setNull (String parameterName, int sqlType, String typeName)
throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6902,7 +6902,7 @@
* @since 1.4
*/
public void setBoolean(String parameterName, boolean x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6922,7 +6922,7 @@
* @since 1.4
*/
public void setByte(String parameterName, byte x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6941,7 +6941,7 @@
* @since 1.4
*/
public void setShort(String parameterName, short x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6960,7 +6960,7 @@
* @since 1.4
*/
public void setInt(String parameterName, int x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -6978,7 +6978,7 @@
* @since 1.4
*/
public void setLong(String parameterName, long x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
@@ -6997,7 +6997,7 @@
* @since 1.4
*/
public void setFloat(String parameterName, float x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -7015,7 +7015,7 @@
* @since 1.4
*/
public void setDouble(String parameterName, double x) throws SQLException{
- throw new SQLFeatureNotSupportedException(jdbcResBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
+ throw new SQLFeatureNotSupportedException(resBundle.handleGetObject("jdbcrowsetimpl.featnotsupp").toString());
}
/**
@@ -7023,15 +7023,25 @@
* during the deserialization process
*
*/
- protected void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Default state initialization happens here
ois.defaultReadObject();
// Initialization of transient Res Bundle happens here .
try {
- jdbcResBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
} catch(IOException ioe) {}
}
static final long serialVersionUID = -3591946023893483003L;
+
+ //------------------------- JDBC 4.1 -----------------------------------
+
+ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Not supported yet.");
+ }
+
+ public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
+ throw new SQLFeatureNotSupportedException("Not supported yet.");
+ }
}
--- a/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/JdbcRowSetResourceBundle.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -153,4 +153,5 @@
return propResBundle.handleGetObject(key);
}
+ static final long serialVersionUID = 436199386225359954L;
}
--- a/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/JoinRowSetImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -127,6 +127,11 @@
strMatchKey = null;
supportedJOINs =
new boolean[] {false, true, false, false, false};
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
}
@@ -4306,5 +4311,22 @@
return crsInternal.createCopySchema();
}
- static final long serialVersionUID = -5590501621560008453L;
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = -5590501621560008453L;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/rowset/RowSetFactoryImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.rowset;
+
+import java.sql.SQLException;
+import javax.sql.rowset.CachedRowSet;
+import javax.sql.rowset.FilteredRowSet;
+import javax.sql.rowset.JdbcRowSet;
+import javax.sql.rowset.JoinRowSet;
+import javax.sql.rowset.WebRowSet;
+import javax.sql.rowset.RowSetFactory;
+
+/**
+ * This is the implementation specific class for the
+ * <code>javax.sql.rowset.spi.RowSetFactory</code>. This is the platform
+ * default implementation for the Java SE platform.
+ *
+ * @author Lance Andersen
+ *
+ *
+ * @version 1.7
+ */
+public final class RowSetFactoryImpl implements RowSetFactory {
+
+ public CachedRowSet createCachedRowSet() throws SQLException {
+ return new com.sun.rowset.CachedRowSetImpl();
+ }
+
+ public FilteredRowSet createFilteredRowSet() throws SQLException {
+ return new com.sun.rowset.FilteredRowSetImpl();
+ }
+
+
+ public JdbcRowSet createJdbcRowSet() throws SQLException {
+ return new com.sun.rowset.JdbcRowSetImpl();
+ }
+
+ public JoinRowSet createJoinRowSet() throws SQLException {
+ return new com.sun.rowset.JoinRowSetImpl();
+ }
+
+ public WebRowSet createWebRowSet() throws SQLException {
+ return new com.sun.rowset.WebRowSetImpl();
+ }
+
+}
--- a/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/WebRowSetImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -103,6 +103,12 @@
*/
public WebRowSetImpl(Hashtable env) throws SQLException {
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
if ( env == null) {
throw new SQLException(resBundle.handleGetObject("webrowsetimpl.nullhash").toString());
}
@@ -263,5 +269,23 @@
this.writeXml(oStream);
}
-static final long serialVersionUID = -8771775154092422943L;
+
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = -8771775154092422943L;
}
--- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetReader.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -490,4 +490,17 @@
startPosition = pos;
}
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID =5049738185801363801L;
}
--- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,13 @@
import java.io.*;
import com.sun.rowset.*;
+import java.text.MessageFormat;
import javax.sql.rowset.*;
+import javax.sql.rowset.serial.SQLInputImpl;
+import javax.sql.rowset.serial.SerialArray;
+import javax.sql.rowset.serial.SerialBlob;
+import javax.sql.rowset.serial.SerialClob;
+import javax.sql.rowset.serial.SerialStruct;
import javax.sql.rowset.spi.*;
@@ -53,6 +59,7 @@
* Standard JDBC RowSet implementations provide an object instance of this
* writer by invoking the <code>SyncProvider.getRowSetWriter()</code> method.
*
+ * @version 0.2
* @author Jonathan Bruce
* @see javax.sql.rowset.spi.SyncProvider
* @see javax.sql.rowset.spi.SyncFactory
@@ -508,10 +515,11 @@
ResultSet rs = null;
rs = pstmt.executeQuery();
- if (rs.next() == true) {
+ ResultSetMetaData rsmd = rs.getMetaData();
+ if (rs.next()) {
if (rs.next()) {
- /** More than one row conflict.
+ /** More than one row conflict.
* If rs has only one row we are able to
* uniquely identify the row where update
* have to happen else if more than one
@@ -528,7 +536,7 @@
// we require the record in rs to be used.
// rs.close();
// pstmt.close();
- rs.first();
+ rs.first();
// how many fields need to be updated
int colsNotChanged = 0;
@@ -552,6 +560,49 @@
orig = origVals.getObject(i);
curr = crs.getObject(i);
rsval = rs.getObject(i);
+ /*
+ * the following block creates equivalent objects
+ * that would have been created if this rs is populated
+ * into a CachedRowSet so that comparison of the column values
+ * from the ResultSet and CachedRowSet are possible
+ */
+ Map map = (crs.getTypeMap() == null)?con.getTypeMap():crs.getTypeMap();
+ if (rsval instanceof Struct) {
+
+ Struct s = (Struct)rsval;
+
+ // look up the class in the map
+ Class c = null;
+ c = (Class)map.get(s.getSQLTypeName());
+ if (c != null) {
+ // create new instance of the class
+ SQLData obj = null;
+ try {
+ obj = (SQLData)c.newInstance();
+ } catch (java.lang.InstantiationException ex) {
+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(),
+ ex.getMessage()));
+ } catch (java.lang.IllegalAccessException ex) {
+ throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(),
+ ex.getMessage()));
+ }
+ // get the attributes from the struct
+ Object attribs[] = s.getAttributes(map);
+ // create the SQLInput "stream"
+ SQLInputImpl sqlInput = new SQLInputImpl(attribs, map);
+ // read the values...
+ obj.readSQL(sqlInput, s.getSQLTypeName());
+ rsval = obj;
+ }
+ } else if (rsval instanceof SQLData) {
+ rsval = new SerialStruct((SQLData)rsval, map);
+ } else if (rsval instanceof Blob) {
+ rsval = new SerialBlob((Blob)rsval);
+ } else if (rsval instanceof Clob) {
+ rsval = new SerialClob((Clob)rsval);
+ } else if (rsval instanceof java.sql.Array) {
+ rsval = new SerialArray((java.sql.Array)rsval, map);
+ }
// reset boolNull if it had been set
boolNull = true;
@@ -669,6 +720,9 @@
}
} //end for
+ rs.close();
+ pstmt.close();
+
this.crsResolve.insertRow();
this.crsResolve.moveToCurrentRow();
@@ -1179,11 +1233,22 @@
private void buildKeyDesc(CachedRowSet crs) throws SQLException {
keyCols = crs.getKeyColumns();
+ ResultSetMetaData resultsetmd = crs.getMetaData();
if (keyCols == null || keyCols.length == 0) {
- keyCols = new int[callerColumnCount];
- for (int i = 0; i < keyCols.length; ) {
- keyCols[i] = ++i;
+ ArrayList<Integer> listKeys = new ArrayList<Integer>();
+
+ for (int i = 0; i < callerColumnCount; i++ ) {
+ if(resultsetmd.getColumnType(i+1) != java.sql.Types.CLOB &&
+ resultsetmd.getColumnType(i+1) != java.sql.Types.STRUCT &&
+ resultsetmd.getColumnType(i+1) != java.sql.Types.SQLXML &&
+ resultsetmd.getColumnType(i+1) != java.sql.Types.BLOB &&
+ resultsetmd.getColumnType(i+1) != java.sql.Types.ARRAY &&
+ resultsetmd.getColumnType(i+1) != java.sql.Types.OTHER )
+ listKeys.add(i+1);
}
+ keyCols = new int[listKeys.size()];
+ for (int i = 0; i < listKeys.size(); i++ )
+ keyCols[i] = listKeys.get(i);
}
params = new Object[keyCols.length];
}
@@ -1359,4 +1424,17 @@
}
}
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID =-8506030970299413976L;
}
--- a/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/InsertRow.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -157,4 +157,23 @@
origVals[idx - 1] = val;
markColInserted(idx - 1);
}
+
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = 1066099658102869344L;
}
--- a/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/SyncResolverImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
import com.sun.rowset.*;
import java.io.IOException;
+import java.io.ObjectInputStream;
/**
* There will be two sets of data which will be maintained by the rowset at the
@@ -4837,4 +4838,23 @@
throws SQLException {
throw new UnsupportedOperationException("Operation not yet supported");
}
+
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = -3345004441725080251L;
} //end class
--- a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlReader.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -216,4 +216,22 @@
public void readData(RowSetInternal caller) {
}
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = -9127058392819008014L;
}
--- a/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/internal/WebRowSetXmlWriter.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -663,4 +663,23 @@
return s;
}
+
+ /**
+ * This method re populates the resBundle
+ * during the deserialization process
+ *
+ */
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+
+ static final long serialVersionUID = 7163134986189677641L;
}
--- a/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/rowset/providers/RIOptimisticProvider.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -245,4 +245,18 @@
public String getVendor() {
return this.vendorName;
}
+
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ // Default state initialization happens here
+ ois.defaultReadObject();
+ // Initialization of transient Res Bundle happens here .
+ try {
+ resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();
+ } catch(IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ }
+ static final long serialVersionUID =-3143367176751761936L;
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.ntlm;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * The NTLM client. Not multi-thread enabled.<p>
+ * Example:
+ * <pre>
+ * Client client = new Client(null, "host", "dummy",
+ * "REALM", "t0pSeCr3t".toCharArray());
+ * byte[] type1 = client.type1();
+ * // Send type1 to server and receive response as type2
+ * byte[] type3 = client.type3(type2, nonce);
+ * // Send type3 to server
+ * </pre>
+ */
+public final class Client extends NTLM {
+ final private String hostname;
+ final private String username;
+
+ private String domain; // might be updated by Type 2 msg
+ private byte[] pw1, pw2;
+
+ /**
+ * Creates an NTLM Client instance.
+ * @param version the NTLM version to use, which can be:
+ * <ul>
+ * <li>LM/NTLM: Original NTLM v1
+ * <li>LM: Original NTLM v1, LM only
+ * <li>NTLM: Original NTLM v1, NTLM only
+ * <li>NTLM2: NTLM v1 with Client Challenge
+ * <li>LMv2/NTLMv2: NTLM v2
+ * <li>LMv2: NTLM v2, LM only
+ * <li>NTLMv2: NTLM v2, NTLM only
+ * </ul>
+ * If null, "LMv2/NTLMv2" will be used.
+ * @param hostname hostname of the client, can be null
+ * @param username username to be authenticated, must not be null
+ * @param domain domain of {@code username}, can be null
+ * @param password password for {@code username}, must not be not null.
+ * This method does not make any modification to this parameter, it neither
+ * needs to access the content of this parameter after this method call,
+ * so you are free to modify or nullify this parameter after this call.
+ * @throws NullPointerException if {@code username} or {@code password} is null.
+ * @throws NTLMException if {@code version} is illegal
+ */
+ public Client(String version, String hostname, String username,
+ String domain, char[] password) throws NTLMException {
+ super(version);
+ if ((username == null || password == null)) {
+ throw new NullPointerException("username/password cannot be null");
+ }
+ this.hostname = hostname;
+ this.username = username;
+ this.domain = domain;
+ this.pw1 = getP1(password);
+ this.pw2 = getP2(password);
+ debug("NTLM Client: (h,u,t,version(v)) = (%s,%s,%s,%s(%s))\n",
+ hostname, username, domain, version, v.toString());
+ }
+
+ /**
+ * Generates the Type 1 message
+ * @return the message generated
+ */
+ public byte[] type1() {
+ Writer p = new Writer(1, 32);
+ int flags = 0x8203;
+ if (hostname != null) {
+ flags |= 0x2000;
+ }
+ if (domain != null) {
+ flags |= 0x1000;
+ }
+ if (v != Version.NTLM) {
+ flags |= 0x80000;
+ }
+ p.writeInt(12, flags);
+ p.writeSecurityBuffer(24, hostname, false);
+ p.writeSecurityBuffer(16, domain, false);
+ debug("NTLM Client: Type 1 created\n");
+ debug(p.getBytes());
+ return p.getBytes();
+ }
+
+ /**
+ * Generates the Type 3 message
+ * @param type2 the responding Type 2 message from server, must not be null
+ * @param nonce random 8-byte array to be used in message generation,
+ * must not be null except for original NTLM v1
+ * @return the message generated
+ * @throws NullPointerException if {@code type2} or {@code nonce} is null
+ * for NTLM v1.
+ * @throws NTLMException if the incoming message is invalid
+ */
+ public byte[] type3(byte[] type2, byte[] nonce) throws NTLMException {
+ if (type2 == null || (v != Version.NTLM && nonce == null)) {
+ throw new NullPointerException("type2 and nonce cannot be null");
+ }
+ debug("NTLM Client: Type 2 received\n");
+ debug(type2);
+ Reader r = new Reader(type2);
+ byte[] challenge = r.readBytes(24, 8);
+ int inputFlags = r.readInt(20);
+ boolean unicode = (inputFlags & 1) == 1;
+ String domainFromServer = r.readSecurityBuffer(12, unicode);
+ if (domainFromServer != null) {
+ domain = domainFromServer;
+ }
+ if (domain == null) {
+ throw new NTLMException(NTLMException.NO_DOMAIN_INFO,
+ "No domain info");
+ }
+
+ int flags = 0x88200 | (inputFlags & 3);
+ Writer p = new Writer(3, 64);
+ byte[] lm = null, ntlm = null;
+
+ p.writeSecurityBuffer(28, domain, unicode);
+ p.writeSecurityBuffer(36, username, unicode);
+ p.writeSecurityBuffer(44, hostname, unicode);
+
+ if (v == Version.NTLM) {
+ byte[] lmhash = calcLMHash(pw1);
+ byte[] nthash = calcNTHash(pw2);
+ if (writeLM) lm = calcResponse (lmhash, challenge);
+ if (writeNTLM) ntlm = calcResponse (nthash, challenge);
+ } else if (v == Version.NTLM2) {
+ byte[] nthash = calcNTHash(pw2);
+ lm = ntlm2LM(nonce);
+ ntlm = ntlm2NTLM(nthash, nonce, challenge);
+ } else {
+ byte[] nthash = calcNTHash(pw2);
+ if (writeLM) lm = calcV2(nthash,
+ username.toUpperCase(Locale.US)+domain, nonce, challenge);
+ if (writeNTLM) {
+ byte[] alist = type2.length > 48 ?
+ r.readSecurityBuffer(40) : new byte[0];
+ byte[] blob = new byte[32+alist.length];
+ System.arraycopy(new byte[]{1,1,0,0,0,0,0,0}, 0, blob, 0, 8);
+ // TS
+ byte[] time = BigInteger.valueOf(new Date().getTime())
+ .add(new BigInteger("11644473600000"))
+ .multiply(BigInteger.valueOf(10000))
+ .toByteArray();
+ for (int i=0; i<time.length; i++) {
+ blob[8+time.length-i-1] = time[i];
+ }
+ System.arraycopy(nonce, 0, blob, 16, 8);
+ System.arraycopy(new byte[]{0,0,0,0}, 0, blob, 24, 4);
+ System.arraycopy(alist, 0, blob, 28, alist.length);
+ System.arraycopy(new byte[]{0,0,0,0}, 0,
+ blob, 28+alist.length, 4);
+ ntlm = calcV2(nthash, username.toUpperCase(Locale.US)+domain,
+ blob, challenge);
+ }
+ }
+ p.writeSecurityBuffer(12, lm);
+ p.writeSecurityBuffer(20, ntlm);
+ p.writeSecurityBuffer(52, new byte[0]);
+
+ p.writeInt(60, flags);
+ debug("NTLM Client: Type 3 created\n");
+ debug(p.getBytes());
+ return p.getBytes();
+ }
+
+ /**
+ * Returns the domain value provided by server after the authentication
+ * is complete, or the domain value provided by the client before it.
+ * @return the domain
+ */
+ public String getDomain() {
+ return domain;
+ }
+
+ /**
+ * Disposes any password-derived information.
+ */
+ public void dispose() {
+ Arrays.fill(pw1, (byte)0);
+ Arrays.fill(pw2, (byte)0);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.ntlm;
+
+import static com.sun.security.ntlm.Version.*;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * NTLM authentication implemented according to MS-NLMP, version 12.1
+ * @since 1.7
+ */
+class NTLM {
+
+ private final SecretKeyFactory fac;
+ private final Cipher cipher;
+ private final MessageDigest md4;
+ private final Mac hmac;
+ private final MessageDigest md5;
+ private static final boolean DEBUG =
+ System.getProperty("ntlm.debug") != null;
+
+ final Version v;
+
+ final boolean writeLM;
+ final boolean writeNTLM;
+
+ protected NTLM(String version) throws NTLMException {
+ if (version == null) version = "LMv2/NTLMv2";
+ switch (version) {
+ case "LM": v = NTLM; writeLM = true; writeNTLM = false; break;
+ case "NTLM": v = NTLM; writeLM = false; writeNTLM = true; break;
+ case "LM/NTLM": v = NTLM; writeLM = writeNTLM = true; break;
+ case "NTLM2": v = NTLM2; writeLM = writeNTLM = true; break;
+ case "LMv2": v = NTLMv2; writeLM = true; writeNTLM = false; break;
+ case "NTLMv2": v = NTLMv2; writeLM = false; writeNTLM = true; break;
+ case "LMv2/NTLMv2": v = NTLMv2; writeLM = writeNTLM = true; break;
+ default: throw new NTLMException(NTLMException.BAD_VERSION,
+ "Unknown version " + version);
+ }
+ try {
+ fac = SecretKeyFactory.getInstance ("DES");
+ cipher = Cipher.getInstance ("DES/ECB/NoPadding");
+ md4 = sun.security.provider.MD4.getInstance();
+ hmac = Mac.getInstance("HmacMD5");
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchPaddingException e) {
+ throw new AssertionError();
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Prints out a formatted string, called in various places inside then NTLM
+ * implementation for debugging/logging purposes. When the system property
+ * "ntlm.debug" is set, <code>System.out.printf(format, args)</code> is
+ * called. This method is designed to be overridden by child classes to
+ * match their own debugging/logging mechanisms.
+ * @param format a format string
+ * @param args the arguments referenced by <code>format</code>
+ * @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[])
+ */
+ public void debug(String format, Object... args) {
+ if (DEBUG) {
+ System.out.printf(format, args);
+ }
+ }
+
+ /**
+ * Prints out the content of a byte array, called in various places inside
+ * the NTLM implementation for debugging/logging purposes. When the system
+ * property "ntlm.debug" is set, the hexdump of the array is printed into
+ * System.out. This method is designed to be overridden by child classes to
+ * match their own debugging/logging mechanisms.
+ * @param bytes the byte array to print out
+ */
+ public void debug(byte[] bytes) {
+ if (DEBUG) {
+ try {
+ new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out);
+ } catch (IOException ioe) {
+ // Impossible
+ }
+ }
+ }
+
+ /**
+ * Reading an NTLM packet
+ */
+ static class Reader {
+
+ private final byte[] internal;
+
+ Reader(byte[] data) {
+ internal = data;
+ }
+
+ int readInt(int offset) throws NTLMException {
+ try {
+ return internal[offset] & 0xff +
+ (internal[offset+1] & 0xff << 8) +
+ (internal[offset+2] & 0xff << 16) +
+ (internal[offset+3] & 0xff << 24);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new NTLMException(NTLMException.PACKET_READ_ERROR,
+ "Input message incorrect size");
+ }
+ }
+
+ int readShort(int offset) throws NTLMException {
+ try {
+ return internal[offset] & 0xff +
+ (internal[offset+1] & 0xff << 8);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new NTLMException(NTLMException.PACKET_READ_ERROR,
+ "Input message incorrect size");
+ }
+ }
+
+ byte[] readBytes(int offset, int len) throws NTLMException {
+ try {
+ return Arrays.copyOfRange(internal, offset, offset + len);
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new NTLMException(NTLMException.PACKET_READ_ERROR,
+ "Input message incorrect size");
+ }
+ }
+
+ byte[] readSecurityBuffer(int offset) throws NTLMException {
+ int pos = readInt(offset+4);
+ if (pos == 0) return null;
+ try {
+ return Arrays.copyOfRange(
+ internal, pos, pos + readShort(offset));
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ throw new NTLMException(NTLMException.PACKET_READ_ERROR,
+ "Input message incorrect size");
+ }
+ }
+
+ String readSecurityBuffer(int offset, boolean unicode)
+ throws NTLMException {
+ byte[] raw = readSecurityBuffer(offset);
+ try {
+ return raw == null ? null : new String(
+ raw, unicode ? "UnicodeLittleUnmarked" : "ISO8859_1");
+ } catch (UnsupportedEncodingException ex) {
+ throw new NTLMException(NTLMException.PACKET_READ_ERROR,
+ "Invalid input encoding");
+ }
+ }
+ }
+
+ /**
+ * Writing an NTLM packet
+ */
+ static class Writer {
+
+ private byte[] internal; // buffer
+ private int current; // current written content interface buffer
+
+ /**
+ * Starts writing a NTLM packet
+ * @param type NEGOTIATE || CHALLENGE || AUTHENTICATE
+ * @param len the base length, without security buffers
+ */
+ Writer(int type, int len) {
+ assert len < 256;
+ internal = new byte[256];
+ current = len;
+ System.arraycopy (
+ new byte[] {'N','T','L','M','S','S','P',0,(byte)type},
+ 0, internal, 0, 9);
+ }
+
+ void writeShort(int offset, int number) {
+ internal[offset] = (byte)(number);
+ internal[offset+1] = (byte)(number >> 8);
+ }
+
+ void writeInt(int offset, int number) {
+ internal[offset] = (byte)(number);
+ internal[offset+1] = (byte)(number >> 8);
+ internal[offset+2] = (byte)(number >> 16);
+ internal[offset+3] = (byte)(number >> 24);
+ }
+
+ void writeBytes(int offset, byte[] data) {
+ System.arraycopy(data, 0, internal, offset, data.length);
+ }
+
+ void writeSecurityBuffer(int offset, byte[] data) {
+ if (data == null) {
+ writeShort(offset+4, current);
+ } else {
+ int len = data.length;
+ if (current + len > internal.length) {
+ internal = Arrays.copyOf(internal, current + len + 256);
+ }
+ writeShort(offset, len);
+ writeShort(offset+2, len);
+ writeShort(offset+4, current);
+ System.arraycopy(data, 0, internal, current, len);
+ current += len;
+ }
+ }
+
+ void writeSecurityBuffer(int offset, String str, boolean unicode) {
+ try {
+ writeSecurityBuffer(offset, str == null ? null : str.getBytes(
+ unicode ? "UnicodeLittleUnmarked" : "ISO8859_1"));
+ } catch (UnsupportedEncodingException ex) {
+ assert false;
+ }
+ }
+
+ byte[] getBytes() {
+ return Arrays.copyOf(internal, current);
+ }
+ }
+
+ // LM/NTLM
+
+ /* Convert a 7 byte array to an 8 byte array (for a des key with parity)
+ * input starts at offset off
+ */
+ byte[] makeDesKey (byte[] input, int off) {
+ int[] in = new int [input.length];
+ for (int i=0; i<in.length; i++ ) {
+ in[i] = input[i]<0 ? input[i]+256: input[i];
+ }
+ byte[] out = new byte[8];
+ out[0] = (byte)in[off+0];
+ out[1] = (byte)(((in[off+0] << 7) & 0xFF) | (in[off+1] >> 1));
+ out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2));
+ out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3));
+ out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4));
+ out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5));
+ out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6));
+ out[7] = (byte)((in[off+6] << 1) & 0xFF);
+ return out;
+ }
+
+ byte[] calcLMHash (byte[] pwb) {
+ byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+ byte[] pwb1 = new byte [14];
+ int len = pwb.length;
+ if (len > 14)
+ len = 14;
+ System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */
+
+ try {
+ DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0));
+ DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7));
+
+ SecretKey key1 = fac.generateSecret (dks1);
+ SecretKey key2 = fac.generateSecret (dks2);
+ cipher.init (Cipher.ENCRYPT_MODE, key1);
+ byte[] out1 = cipher.doFinal (magic, 0, 8);
+ cipher.init (Cipher.ENCRYPT_MODE, key2);
+ byte[] out2 = cipher.doFinal (magic, 0, 8);
+ byte[] result = new byte [21];
+ System.arraycopy (out1, 0, result, 0, 8);
+ System.arraycopy (out2, 0, result, 8, 8);
+ return result;
+ } catch (InvalidKeyException ive) {
+ // Will not happen, all key material are 8 bytes
+ assert false;
+ } catch (InvalidKeySpecException ikse) {
+ // Will not happen, we only feed DESKeySpec to DES factory
+ assert false;
+ } catch (IllegalBlockSizeException ibse) {
+ // Will not happen, we encrypt 8 bytes
+ assert false;
+ } catch (BadPaddingException bpe) {
+ // Will not happen, this is encryption
+ assert false;
+ }
+ return null; // will not happen, we returned already
+ }
+
+ byte[] calcNTHash (byte[] pw) {
+ byte[] out = md4.digest (pw);
+ byte[] result = new byte [21];
+ System.arraycopy (out, 0, result, 0, 16);
+ return result;
+ }
+
+ /* key is a 21 byte array. Split it into 3 7 byte chunks,
+ * Convert each to 8 byte DES keys, encrypt the text arg with
+ * each key and return the three results in a sequential []
+ */
+ byte[] calcResponse (byte[] key, byte[] text) {
+ try {
+ assert key.length == 21;
+ DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
+ DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
+ DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
+ SecretKey key1 = fac.generateSecret(dks1);
+ SecretKey key2 = fac.generateSecret(dks2);
+ SecretKey key3 = fac.generateSecret(dks3);
+ cipher.init(Cipher.ENCRYPT_MODE, key1);
+ byte[] out1 = cipher.doFinal(text, 0, 8);
+ cipher.init(Cipher.ENCRYPT_MODE, key2);
+ byte[] out2 = cipher.doFinal(text, 0, 8);
+ cipher.init(Cipher.ENCRYPT_MODE, key3);
+ byte[] out3 = cipher.doFinal(text, 0, 8);
+ byte[] result = new byte[24];
+ System.arraycopy(out1, 0, result, 0, 8);
+ System.arraycopy(out2, 0, result, 8, 8);
+ System.arraycopy(out3, 0, result, 16, 8);
+ return result;
+ } catch (IllegalBlockSizeException ex) { // None will happen
+ assert false;
+ } catch (BadPaddingException ex) {
+ assert false;
+ } catch (InvalidKeySpecException ex) {
+ assert false;
+ } catch (InvalidKeyException ex) {
+ assert false;
+ }
+ return null;
+ }
+
+ // LMv2/NTLMv2
+
+ byte[] hmacMD5(byte[] key, byte[] text) {
+ try {
+ SecretKeySpec skey =
+ new SecretKeySpec(Arrays.copyOf(key, 16), "HmacMD5");
+ hmac.init(skey);
+ return hmac.doFinal(text);
+ } catch (InvalidKeyException ex) {
+ assert false;
+ } catch (RuntimeException e) {
+ assert false;
+ }
+ return null;
+ }
+
+ byte[] calcV2(byte[] nthash, String text, byte[] blob, byte[] challenge) {
+ try {
+ byte[] ntlmv2hash = hmacMD5(nthash,
+ text.getBytes("UnicodeLittleUnmarked"));
+ byte[] cn = new byte[blob.length+8];
+ System.arraycopy(challenge, 0, cn, 0, 8);
+ System.arraycopy(blob, 0, cn, 8, blob.length);
+ byte[] result = new byte[16+blob.length];
+ System.arraycopy(hmacMD5(ntlmv2hash, cn), 0, result, 0, 16);
+ System.arraycopy(blob, 0, result, 16, blob.length);
+ return result;
+ } catch (UnsupportedEncodingException ex) {
+ assert false;
+ }
+ return null;
+ }
+
+ // NTLM2 LM/NTLM
+
+ static byte[] ntlm2LM(byte[] nonce) {
+ return Arrays.copyOf(nonce, 24);
+ }
+
+ byte[] ntlm2NTLM(byte[] ntlmHash, byte[] nonce, byte[] challenge) {
+ byte[] b = Arrays.copyOf(challenge, 16);
+ System.arraycopy(nonce, 0, b, 8, 8);
+ byte[] sesshash = Arrays.copyOf(md5.digest(b), 8);
+ return calcResponse(ntlmHash, sesshash);
+ }
+
+ // Password in ASCII and UNICODE
+
+ static byte[] getP1(char[] password) {
+ try {
+ return new String(password).toUpperCase().getBytes("ISO8859_1");
+ } catch (UnsupportedEncodingException ex) {
+ return null;
+ }
+ }
+
+ static byte[] getP2(char[] password) {
+ try {
+ return new String(password).getBytes("UnicodeLittleUnmarked");
+ } catch (UnsupportedEncodingException ex) {
+ return null;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLMException.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.ntlm;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * An NTLM-related Exception
+ */
+public final class NTLMException extends GeneralSecurityException {
+
+ /**
+ * If the incoming packet is invalid.
+ */
+ public final static int PACKET_READ_ERROR = 1;
+
+ /**
+ * If the client cannot get a domain value from the server and the
+ * caller has not provided one.
+ */
+ public final static int NO_DOMAIN_INFO = 2;
+
+ /**
+ * If the domain provided by the client does not match the one received
+ * from server.
+ */
+ //public final static int DOMAIN_UNMATCH = 3;
+
+ /**
+ * If the client name is not found on server's user database.
+ */
+ public final static int USER_UNKNOWN = 3;
+
+ /**
+ * If authentication fails.
+ */
+ public final static int AUTH_FAILED = 4;
+
+ /**
+ * If an illegal version string is provided.
+ */
+ public final static int BAD_VERSION = 5;
+
+ private int errorCode;
+
+ /**
+ * Constructs an NTLMException object.
+ * @param errorCode the error code, which can be retrieved by
+ * the {@link #errorCode() } method.
+ * @param msg the string message, which can be retrived by
+ * the {@link Exception#getMessage() } method.
+ */
+ public NTLMException(int errorCode, String msg) {
+ super(msg);
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * Returns the error code associated with this NTLMException.
+ * @return the error code
+ */
+ public int errorCode() {
+ return errorCode;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/ntlm/Server.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.ntlm;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * The NTLM server, not multi-thread enabled.<p>
+ * Example:
+ * <pre>
+ * Server server = new Server(null, "REALM") {
+ * public char[] getPassword(String ntdomain, String username) {
+ * switch (username) {
+ * case "dummy": return "t0pSeCr3t".toCharArray();
+ * case "guest": return "".toCharArray();
+ * default: return null;
+ * }
+ * }
+ * };
+ * // Receive client request as type1
+ * byte[] type2 = server.type2(type1, nonce);
+ * // Send type2 to client and receive type3
+ * verify(type3, nonce);
+ * </pre>
+ */
+public abstract class Server extends NTLM {
+ final private String domain;
+ final private boolean allVersion;
+ /**
+ * Creates a Server instance.
+ * @param version the NTLM version to use, which can be:
+ * <ul>
+ * <li>NTLM: Original NTLM v1
+ * <li>NTLM2: NTLM v1 with Client Challenge
+ * <li>NTLMv2: NTLM v2
+ * </ul>
+ * If null, all versions will be supported. Please note that unless NTLM2
+ * is selected, authentication succeeds if one of LM (or LMv2) or
+ * NTLM (or NTLMv2) is verified.
+ * @param domain the domain, must not be null
+ * @throws NullPointerException if {@code domain} is null.
+ */
+ public Server(String version, String domain) throws NTLMException {
+ super(version);
+ if (domain == null) {
+ throw new NullPointerException("domain cannot be null");
+ }
+ this.allVersion = (version == null);
+ this.domain = domain;
+ debug("NTLM Server: (t,version) = (%s,%s)\n", domain, version);
+ }
+
+ /**
+ * Generates the Type 2 message
+ * @param type1 the Type1 message received, must not be null
+ * @param nonce the random 8-byte array to be used in message generation,
+ * must not be null
+ * @return the message generated
+ * @throws NullPointerException if type1 or nonce is null
+ * @throws NTLMException if the incoming message is invalid
+ */
+ public byte[] type2(byte[] type1, byte[] nonce) {
+ if (nonce == null) {
+ throw new NullPointerException("nonce cannot be null");
+ }
+ debug("NTLM Server: Type 1 received\n");
+ if (type1 != null) debug(type1);
+ Writer p = new Writer(2, 32);
+ int flags = 0x80205;
+ p.writeSecurityBuffer(12, domain, true);
+ p.writeInt(20, flags);
+ p.writeBytes(24, nonce);
+ debug("NTLM Server: Type 2 created\n");
+ debug(p.getBytes());
+ return p.getBytes();
+ }
+
+ /**
+ * Verifies the Type3 message received from client and returns
+ * various negotiated information.
+ * @param type3 the incoming Type3 message from client, must not be null
+ * @param nonce the same nonce provided in {@link #type2}, must not be null
+ * @return username and hostname of the client in a byte array
+ * @throws NullPointerException if {@code type3} or {@code nonce} is null
+ * @throws NTLMException if the incoming message is invalid
+ */
+ public String[] verify(byte[] type3, byte[] nonce)
+ throws NTLMException {
+ if (type3 == null || nonce == null) {
+ throw new NullPointerException("type1 or nonce cannot be null");
+ }
+ debug("NTLM Server: Type 3 received\n");
+ if (type3 != null) debug(type3);
+ Reader r = new Reader(type3);
+ String username = r.readSecurityBuffer(36, true);
+ String hostname = r.readSecurityBuffer(44, true);
+ String incomingDomain = r.readSecurityBuffer(28, true);
+ /*if (incomingDomain != null && !incomingDomain.equals(domain)) {
+ throw new NTLMException(NTLMException.DOMAIN_UNMATCH,
+ "Wrong domain: " + incomingDomain +
+ " vs " + domain); // Needed?
+ }*/
+ boolean verified = false;
+ char[] password = getPassword(domain, username);
+ if (password == null) {
+ throw new NTLMException(NTLMException.USER_UNKNOWN,
+ "Unknown user");
+ }
+ byte[] incomingLM = r.readSecurityBuffer(12);
+ byte[] incomingNTLM = r.readSecurityBuffer(20);
+
+ if (!verified && (allVersion || v == Version.NTLM)) {
+ if (incomingLM.length > 0) {
+ byte[] pw1 = getP1(password);
+ byte[] lmhash = calcLMHash(pw1);
+ byte[] lmresponse = calcResponse (lmhash, nonce);
+ if (Arrays.equals(lmresponse, incomingLM)) {
+ verified = true;
+ }
+ }
+ if (incomingNTLM.length > 0) {
+ byte[] pw2 = getP2(password);
+ byte[] nthash = calcNTHash(pw2);
+ byte[] ntresponse = calcResponse (nthash, nonce);
+ if (Arrays.equals(ntresponse, incomingNTLM)) {
+ verified = true;
+ }
+ }
+ debug("NTLM Server: verify using NTLM: " + verified + "\n");
+ }
+ if (!verified && (allVersion || v == Version.NTLM2)) {
+ byte[] pw2 = getP2(password);
+ byte[] nthash = calcNTHash(pw2);
+ byte[] clientNonce = Arrays.copyOf(incomingLM, 8);
+ byte[] ntlmresponse = ntlm2NTLM(nthash, clientNonce, nonce);
+ if (Arrays.equals(incomingNTLM, ntlmresponse)) {
+ verified = true;
+ }
+ debug("NTLM Server: verify using NTLM2: " + verified + "\n");
+ }
+ if (!verified && (allVersion || v == Version.NTLMv2)) {
+ byte[] pw2 = getP2(password);
+ byte[] nthash = calcNTHash(pw2);
+ if (incomingLM.length > 0) {
+ byte[] clientNonce = Arrays.copyOfRange(
+ incomingLM, 16, incomingLM.length);
+ byte[] lmresponse = calcV2(nthash,
+ username.toUpperCase(Locale.US)+incomingDomain,
+ clientNonce, nonce);
+ if (Arrays.equals(lmresponse, incomingLM)) {
+ verified = true;
+ }
+ }
+ if (incomingNTLM.length > 0) {
+ byte[] clientBlob = Arrays.copyOfRange(
+ incomingNTLM, 16, incomingNTLM.length);
+ byte[] ntlmresponse = calcV2(nthash,
+ username.toUpperCase(Locale.US)+incomingDomain,
+ clientBlob, nonce);
+ if (Arrays.equals(ntlmresponse, incomingNTLM)) {
+ verified = true;
+ }
+ }
+ debug("NTLM Server: verify using NTLMv2: " + verified + "\n");
+ }
+ if (!verified) {
+ throw new NTLMException(NTLMException.AUTH_FAILED,
+ "None of LM and NTLM verified");
+ }
+ return new String[] {username, hostname};
+ }
+
+ /**
+ * Retrieves the password for a given user. This method should be
+ * overridden in a concrete class.
+ * @param domain can be null
+ * @param username must not be null
+ * @return the password for the user, or null if unknown
+ */
+ public abstract char[] getPassword(String domain, String username);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/ntlm/Version.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.ntlm;
+
+enum Version {
+ NTLM, NTLM2, NTLMv2
+}
--- a/jdk/src/share/classes/com/sun/security/sasl/Provider.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/com/sun/security/sasl/Provider.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,10 +35,12 @@
* - CRAM-MD5
* - DIGEST-MD5
* - GSSAPI/Kerberos v5
+ * - NTLM
* And server support for
* - CRAM-MD5
* - DIGEST-MD5
* - GSSAPI/Kerberos v5
+ * - NTLM
*/
public final class Provider extends java.security.Provider {
@@ -47,8 +49,8 @@
private static final String info = "Sun SASL provider" +
"(implements client mechanisms for: " +
- "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5;" +
- " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5)";
+ "DIGEST-MD5, GSSAPI, EXTERNAL, PLAIN, CRAM-MD5, NTLM;" +
+ " server mechanisms for: DIGEST-MD5, GSSAPI, CRAM-MD5, NTLM)";
public Provider() {
super("SunSASL", 1.7d, info);
@@ -58,6 +60,8 @@
// Client mechanisms
put("SaslClientFactory.DIGEST-MD5",
"com.sun.security.sasl.digest.FactoryImpl");
+ put("SaslClientFactory.NTLM",
+ "com.sun.security.sasl.ntlm.FactoryImpl");
put("SaslClientFactory.GSSAPI",
"com.sun.security.sasl.gsskerb.FactoryImpl");
@@ -75,6 +79,8 @@
"com.sun.security.sasl.gsskerb.FactoryImpl");
put("SaslServerFactory.DIGEST-MD5",
"com.sun.security.sasl.digest.FactoryImpl");
+ put("SaslServerFactory.NTLM",
+ "com.sun.security.sasl.ntlm.FactoryImpl");
return null;
}
});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/FactoryImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.sasl.ntlm;
+
+import java.util.Map;
+
+import javax.security.sasl.*;
+import javax.security.auth.callback.CallbackHandler;
+
+import com.sun.security.sasl.util.PolicyUtils;
+
+
+/**
+ * Client and server factory for NTLM SASL client/server mechanisms.
+ * See NTLMClient and NTLMServer for input requirements.
+ *
+ * @since 1.7
+ */
+
+public final class FactoryImpl implements SaslClientFactory,
+SaslServerFactory{
+
+ private static final String myMechs[] = { "NTLM" };
+ private static final int mechPolicies[] = {
+ PolicyUtils.NOPLAINTEXT|PolicyUtils.NOANONYMOUS
+ };
+
+ /**
+ * Empty constructor.
+ */
+ public FactoryImpl() {
+ }
+
+ /**
+ * Returns a new instance of the NTLM SASL client mechanism.
+ * Argument checks are performed in SaslClient's constructor.
+ * @returns a new SaslClient ; otherwise null if unsuccessful.
+ * @throws SaslException If there is an error creating the NTLM
+ * SASL client.
+ */
+ public SaslClient createSaslClient(String[] mechs,
+ String authorizationId, String protocol, String serverName,
+ Map<String,?> props, CallbackHandler cbh)
+ throws SaslException {
+
+ for (int i=0; i<mechs.length; i++) {
+ if (mechs[i].equals("NTLM") &&
+ PolicyUtils.checkPolicy(mechPolicies[0], props)) {
+
+ return new NTLMClient(mechs[i], authorizationId,
+ protocol, serverName, props, cbh);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a new instance of the NTLM SASL server mechanism.
+ * Argument checks are performed in SaslServer's constructor.
+ * @returns a new SaslServer ; otherwise null if unsuccessful.
+ * @throws SaslException If there is an error creating the NTLM
+ * SASL server.
+ */
+ public SaslServer createSaslServer(String mech,
+ String protocol, String serverName, Map<String,?> props, CallbackHandler cbh)
+ throws SaslException {
+
+ if (mech.equals("NTLM") &&
+ PolicyUtils.checkPolicy(mechPolicies[0], props)) {
+ if (props != null) {
+ String qop = (String)props.get(Sasl.QOP);
+ if (qop != null && !qop.equals("auth")) {
+ throw new SaslException("NTLM only support auth");
+ }
+ }
+ if (cbh == null) {
+ throw new SaslException(
+ "Callback handler with support for AuthorizeCallback, "+
+ "RealmCallback, NameCallback, and PasswordCallback " +
+ "required");
+ }
+ return new NTLMServer(mech, protocol, serverName, props, cbh);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the authentication mechanisms that this factory can produce.
+ *
+ * @returns String[] {"NTLM"} if policies in env match those of this
+ * factory.
+ */
+ public String[] getMechanismNames(Map<String,?> env) {
+ return PolicyUtils.filterMechs(myMechs, mechPolicies, env);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMClient.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.sasl.ntlm;
+
+import com.sun.security.ntlm.Client;
+import com.sun.security.ntlm.NTLMException;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.Random;
+import javax.security.auth.callback.Callback;
+
+
+import javax.security.sasl.*;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * Required callbacks:
+ * - RealmCallback
+ * handle can provide domain info for authentication, optional
+ * - NameCallback
+ * handler must enter username to use for authentication
+ * - PasswordCallback
+ * handler must enter password for username to use for authentication
+ *
+ * Environment properties that affect behavior of implementation:
+ *
+ * javax.security.sasl.qop
+ * String, quality of protection; only "auth" is accepted, default "auth"
+ *
+ * com.sun.security.sasl.ntlm.version
+ * String, name a specific version to use; can be:
+ * LM/NTLM: Original NTLM v1
+ * LM: Original NTLM v1, LM only
+ * NTLM: Original NTLM v1, NTLM only
+ * NTLM2: NTLM v1 with Client Challenge
+ * LMv2/NTLMv2: NTLM v2
+ * LMv2: NTLM v2, LM only
+ * NTLMv2: NTLM v2, NTLM only
+ * If not specified, use system property "ntlm.version". If
+ * still not specified, use default value "LMv2/NTLMv2".
+ *
+ * com.sun.security.sasl.ntlm.random
+ * java.util.Random, the nonce source to be used in NTLM v2 or NTLM v1 with
+ * Client Challenge. Default null, an internal java.util.Random object
+ * will be used
+ *
+ * Negotiated Properties:
+ *
+ * javax.security.sasl.qop
+ * Always "auth"
+ *
+ * com.sun.security.sasl.html.domain
+ * The domain for the user, provided by the server
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2222.txt">RFC 2222</a>
+ * - Simple Authentication and Security Layer (SASL)
+ *
+ */
+final class NTLMClient implements SaslClient {
+
+ private static final String NTLM_VERSION =
+ "com.sun.security.sasl.ntlm.version";
+ private static final String NTLM_RANDOM =
+ "com.sun.security.sasl.ntlm.random";
+ private final static String NTLM_DOMAIN =
+ "com.sun.security.sasl.ntlm.domain";
+ private final static String NTLM_HOSTNAME =
+ "com.sun.security.sasl.ntlm.hostname";
+
+ private final Client client;
+ private final String mech;
+ private final Random random;
+
+ private int step = 0; // 0-start,1-nego,2-auth,3-done
+
+ /**
+ * @param mech non-null
+ * @param authorizationId can be null or empty and ignored
+ * @param protocol non-null for Sasl, useless for NTLM
+ * @param serverName non-null for Sasl, but can be null for NTLM
+ * @param props can be null
+ * @param cbh can be null for Sasl, but will throw NPE for NTLM
+ * @throws SaslException
+ */
+ NTLMClient(String mech, String authzid, String protocol, String serverName,
+ Map props, CallbackHandler cbh) throws SaslException {
+
+ this.mech = mech;
+ String version = null;
+ Random rtmp = null;
+ String hostname = null;
+
+ if (props != null) {
+ String qop = (String)props.get(Sasl.QOP);
+ if (qop != null && !qop.equals("auth")) {
+ throw new SaslException("NTLM only support auth");
+ }
+ version = (String)props.get(NTLM_VERSION);
+ rtmp = (Random)props.get(NTLM_RANDOM);
+ hostname = (String)props.get(NTLM_HOSTNAME);
+ }
+ this.random = rtmp != null ? rtmp : new Random();
+
+ if (version == null) {
+ version = System.getProperty("ntlm.version");
+ }
+
+ RealmCallback dcb = (serverName != null && !serverName.isEmpty())?
+ new RealmCallback("Realm: ", serverName) :
+ new RealmCallback("Realm: ");
+ NameCallback ncb = (authzid != null && !authzid.isEmpty()) ?
+ new NameCallback("User name: ", authzid) :
+ new NameCallback("User name: ");
+ PasswordCallback pcb =
+ new PasswordCallback("Password: ", false);
+
+ try {
+ cbh.handle(new Callback[] {dcb, ncb, pcb});
+ } catch (UnsupportedCallbackException e) {
+ throw new SaslException("NTLM: Cannot perform callback to " +
+ "acquire realm, username or password", e);
+ } catch (IOException e) {
+ throw new SaslException(
+ "NTLM: Error acquiring realm, username or password", e);
+ }
+
+ if (hostname == null) {
+ try {
+ hostname = InetAddress.getLocalHost().getCanonicalHostName();
+ } catch (UnknownHostException e) {
+ hostname = "localhost";
+ }
+ }
+ try {
+ client = new Client(version, hostname,
+ ncb.getName(),
+ dcb.getText(),
+ pcb.getPassword());
+ } catch (NTLMException ne) {
+ throw new SaslException(
+ "NTLM: Invalid version string: " + version, ne);
+ }
+ }
+
+ @Override
+ public String getMechanismName() {
+ return mech;
+ }
+
+ @Override
+ public boolean isComplete() {
+ return step >= 2;
+ }
+
+ @Override
+ public byte[] unwrap(byte[] incoming, int offset, int len)
+ throws SaslException {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public byte[] wrap(byte[] outgoing, int offset, int len)
+ throws SaslException {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public Object getNegotiatedProperty(String propName) {
+ if (propName.equals(Sasl.QOP)) {
+ return "auth";
+ } else if (propName.equals(NTLM_DOMAIN)) {
+ return client.getDomain();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void dispose() throws SaslException {
+ client.dispose();
+ }
+
+ @Override
+ public boolean hasInitialResponse() {
+ return true;
+ }
+
+ @Override
+ public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
+ step++;
+ if (step == 1) {
+ return client.type1();
+ } else {
+ try {
+ byte[] nonce = new byte[8];
+ random.nextBytes(nonce);
+ return client.type3(challenge, nonce);
+ } catch (NTLMException ex) {
+ throw new SaslException("Type3 creation failed", ex);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/sasl/ntlm/NTLMServer.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.security.sasl.ntlm;
+
+import com.sun.security.ntlm.NTLMException;
+import com.sun.security.ntlm.Server;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.Map;
+import java.util.Random;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.*;
+
+/**
+ * Required callbacks:
+ * - RealmCallback
+ * used as key by handler to fetch password, optional
+ * - NameCallback
+ * used as key by handler to fetch password
+ * - PasswordCallback
+ * handler must enter password for username/realm supplied
+ *
+ * Environment properties that affect the implementation:
+ *
+ * javax.security.sasl.qop
+ * String, quality of protection; only "auth" is accepted, default "auth"
+ *
+ * com.sun.security.sasl.ntlm.version
+ * String, name a specific version to accept:
+ * LM/NTLM: Original NTLM v1
+ * LM: Original NTLM v1, LM only
+ * NTLM: Original NTLM v1, NTLM only
+ * NTLM2: NTLM v1 with Client Challenge
+ * LMv2/NTLMv2: NTLM v2
+ * LMv2: NTLM v2, LM only
+ * NTLMv2: NTLM v2, NTLM only
+ * If not specified, use system property "ntlm.version". If also
+ * not specfied, all versions are accepted.
+ *
+ * com.sun.security.sasl.ntlm.domain
+ * String, the domain of the server, default is server name (fqdn parameter)
+ *
+ * com.sun.security.sasl.ntlm.random
+ * java.util.Random, the nonce source. Default null, an internal
+ * java.util.Random object will be used
+ *
+ * Negotiated Properties:
+ *
+ * javax.security.sasl.qop
+ * Always "auth"
+ *
+ * com.sun.security.sasl.ntlm.hostname
+ * The hostname for the user, provided by the client
+ *
+ */
+
+final class NTLMServer implements SaslServer {
+
+ private final static String NTLM_VERSION =
+ "com.sun.security.sasl.ntlm.version";
+ private final static String NTLM_DOMAIN =
+ "com.sun.security.sasl.ntlm.domain";
+ private final static String NTLM_HOSTNAME =
+ "com.sun.security.sasl.ntlm.hostname";
+ private static final String NTLM_RANDOM =
+ "com.sun.security.sasl.ntlm.random";
+
+ private final Random random;
+ private final Server server;
+ private byte[] nonce;
+ private int step = 0;
+ private String authzId;
+ private final String mech;
+ private String hostname;
+
+ /**
+ * @param mech not null
+ * @param protocol not null for Sasl, ignored in NTLM
+ * @param serverName not null for Sasl, can be null in NTLM. If non-null,
+ * might be used as domain if not provided in props
+ * @param props can be null
+ * @param cbh can be null for Sasl, but will throw NPE in auth for NTLM
+ * @throws SaslException
+ */
+ NTLMServer(String mech, String protocol, String serverName,
+ Map props, final CallbackHandler cbh) throws SaslException {
+
+ this.mech = mech;
+ String version = null;
+ String domain = null;
+ Random rtmp = null;
+
+ if (props != null) {
+ domain = (String) props.get(NTLM_DOMAIN);
+ version = (String)props.get(NTLM_VERSION);
+ rtmp = (Random)props.get(NTLM_RANDOM);
+ }
+ random = rtmp != null ? rtmp : new Random();
+
+ if (version == null) {
+ version = System.getProperty("ntlm.version");
+ }
+ if (domain == null) {
+ domain = serverName;
+ }
+ if (domain == null) {
+ throw new NullPointerException("Domain must be provided as"
+ + " the serverName argument or in props");
+ }
+
+ try {
+ server = new Server(version, domain) {
+ public char[] getPassword(String ntdomain, String username) {
+ try {
+ RealmCallback rcb = new RealmCallback(
+ "Domain: ", ntdomain);
+ NameCallback ncb = new NameCallback(
+ "Name: ", username);
+ PasswordCallback pcb = new PasswordCallback(
+ "Password: ", false);
+ cbh.handle(new Callback[] { rcb, ncb, pcb });
+ char[] passwd = pcb.getPassword();
+ pcb.clearPassword();
+ return passwd;
+ } catch (IOException ioe) {
+ return null;
+ } catch (UnsupportedCallbackException uce) {
+ return null;
+ }
+ }
+ };
+ } catch (NTLMException ne) {
+ throw new SaslException(
+ "NTLM: Invalid version string: " + version, ne);
+ }
+ nonce = new byte[8];
+ }
+
+ @Override
+ public String getMechanismName() {
+ return mech;
+ }
+
+ @Override
+ public byte[] evaluateResponse(byte[] response) throws SaslException {
+ try {
+ step++;
+ if (step == 1) {
+ random.nextBytes(nonce);
+ return server.type2(response, nonce);
+ } else {
+ String[] out = server.verify(response, nonce);
+ authzId = out[0];
+ hostname = out[1];
+ return null;
+ }
+ } catch (GeneralSecurityException ex) {
+ throw new SaslException("", ex);
+ }
+ }
+
+ @Override
+ public boolean isComplete() {
+ return step >= 2;
+ }
+
+ @Override
+ public String getAuthorizationID() {
+ return authzId;
+ }
+
+ @Override
+ public byte[] unwrap(byte[] incoming, int offset, int len)
+ throws SaslException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public byte[] wrap(byte[] outgoing, int offset, int len)
+ throws SaslException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Object getNegotiatedProperty(String propName) {
+ if (propName.equals(Sasl.QOP)) {
+ return "auth";
+ } else if (propName.equals(NTLM_HOSTNAME)) {
+ return hostname;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void dispose() throws SaslException {
+ return;
+ }
+}
--- a/jdk/src/share/classes/java/lang/AutoCloseable.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/lang/AutoCloseable.java Thu Sep 16 11:19:43 2010 -0700
@@ -34,8 +34,8 @@
public interface AutoCloseable {
/**
* Close this resource, relinquishing any underlying resources.
- * This method is invoked automatically by the automatic resource
- * management block construct.
+ * This method is invoked automatically by the {@code
+ * try}-with-resources statement.
*
* <p>Classes implementing this method are strongly encouraged to
* be declared to throw more specific exceptions (or no exception
--- a/jdk/src/share/classes/java/lang/ClassLoader.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java Thu Sep 16 11:19:43 2010 -0700
@@ -823,7 +823,7 @@
* </tt></blockquote>
*
* @param name
- * The expected <a href="#name">binary name</a. of the class, or
+ * The expected <a href="#name">binary name</a>. of the class, or
* <tt>null</tt> if not known
*
* @param b
--- a/jdk/src/share/classes/java/lang/Object.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/lang/Object.java Thu Sep 16 11:19:43 2010 -0700
@@ -189,7 +189,9 @@
* specific cloning operation. First, if the class of this object does
* not implement the interface {@code Cloneable}, then a
* {@code CloneNotSupportedException} is thrown. Note that all arrays
- * are considered to implement the interface {@code Cloneable}.
+ * are considered to implement the interface {@code Cloneable} and that
+ * the return type of the {@code clone} method of an array type {@code T[]}
+ * is {@code T[]} where T is any reference or primitive type.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
--- a/jdk/src/share/classes/java/lang/Throwable.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/lang/Throwable.java Thu Sep 16 11:19:43 2010 -0700
@@ -498,8 +498,8 @@
* }
* </pre>
* As of release 7, the platform supports the notion of
- * <i>suppressed exceptions</i> (in conjunction with automatic
- * resource management blocks). Any exceptions that were
+ * <i>suppressed exceptions</i> (in conjunction with the {@code
+ * try}-with-resources statement). Any exceptions that were
* suppressed in order to deliver an exception are printed out
* beneath the stack trace. The format of this information
* depends on the implementation, but the following example may be
@@ -805,7 +805,7 @@
/**
* Adds the specified exception to the list of exceptions that
- * were suppressed, typically by the automatic resource management
+ * were suppressed, typically by the {@code try}-with-resources
* statement, in order to deliver this exception.
*
* <p>Note that when one exception {@linkplain
@@ -839,7 +839,7 @@
/**
* Returns an array containing all of the exceptions that were
- * suppressed, typically by the automatic resource management
+ * suppressed, typically by the {@code try}-with-resources
* statement, in order to deliver this exception.
*
* @return an array containing all of the exceptions that were
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java Thu Sep 16 11:19:43 2010 -0700
@@ -166,8 +166,7 @@
/**
* Returns the name of this constructor, as a string. This is
- * always the same as the simple name of the constructor's declaring
- * class.
+ * the binary name of the constructor's declaring class.
*/
public String getName() {
return getDeclaringClass().getName();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/net/SdpSocketImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+
+import sun.net.sdp.SdpSupport;
+
+/**
+ * SocketImpl that supports the SDP protocol
+ */
+class SdpSocketImpl extends PlainSocketImpl {
+ SdpSocketImpl() { }
+
+ @Override
+ protected void create(boolean stream) throws IOException {
+ if (!stream)
+ throw new UnsupportedOperationException("Must be a stream socket");
+ fd = SdpSupport.createSocket();
+ if (socket != null)
+ socket.setCreated();
+ if (serverSocket != null)
+ serverSocket.setCreated();
+ }
+}
--- a/jdk/src/share/classes/java/net/ServerSocket.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/net/ServerSocket.java Thu Sep 16 11:19:43 2010 -0700
@@ -69,6 +69,15 @@
private boolean oldImpl = false;
/**
+ * Package-private constructor to create a ServerSocket associated with
+ * the given SocketImpl.
+ */
+ ServerSocket(SocketImpl impl) {
+ this.impl = impl;
+ impl.setServerSocket(this);
+ }
+
+ /**
* Creates an unbound server socket.
*
* @exception IOException IO error when opening the socket.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/DirectoryIteratorException.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.util.ConcurrentModificationException;
+import java.util.Objects;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.InvalidObjectException;
+
+/**
+ * Runtime exception thrown if an I/O error is encountered when iterating over
+ * the entries in a directory. The I/O error is retrieved as an {@link
+ * IOException} using the {@link #getCause() getCause()} method.
+ *
+ * @since 1.7
+ * @see DirectoryStream
+ */
+
+public final class DirectoryIteratorException
+ extends ConcurrentModificationException
+{
+ private static final long serialVersionUID = -6012699886086212874L;
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param cause
+ * the {@code IOException} that caused the directory iteration
+ * to fail
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public DirectoryIteratorException(IOException cause) {
+ super(Objects.nonNull(cause));
+ }
+
+ /**
+ * Returns the cause of this exception.
+ *
+ * @return the cause
+ */
+ @Override
+ public IOException getCause() {
+ return (IOException)super.getCause();
+ }
+
+ /**
+ * Called to read the object from a stream.
+ *
+ * @throws InvalidObjectException
+ * if the object is invalid or has a cause that is not
+ * an {@code IOException}
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ Throwable cause = super.getCause();
+ if (!(cause instanceof IOException))
+ throw new InvalidObjectException("Cause must be an IOException");
+ }
+}
--- a/jdk/src/share/classes/java/nio/file/DirectoryStream.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java Thu Sep 16 11:19:43 2010 -0700
@@ -31,60 +31,84 @@
/**
* An object to iterate over the entries in a directory. A directory stream
- * allows for convenient use of the for-each construct:
+ * allows for the convenient use of the for-each construct to iterate over a
+ * directory.
+ *
+ * <p> <b> While {@code DirectoryStream} extends {@code Iterable}, it is not a
+ * general-purpose {@code Iterable} as it supports only a single {@code
+ * Iterator}; invoking the {@link #iterator iterator} method to obtain a second
+ * or subsequent iterator throws {@code IllegalStateException}. </b>
+ *
+ * <p> An important property of the directory stream's {@code Iterator} is that
+ * its {@link Iterator#hasNext() hasNext} method is guaranteed to read-ahead by
+ * at least one element. If {@code hasNext} method returns {@code true}, and is
+ * followed by a call to the {@code next} method, it is guaranteed that the
+ * {@code next} method will not throw an exception due to an I/O error, or
+ * because the stream has been {@link #close closed}. The {@code Iterator} does
+ * not support the {@link Iterator#remove remove} operation.
+ *
+ * <p> A {@code DirectoryStream} is opened upon creation and is closed by
+ * invoking the {@code close} method. Closing a directory stream releases any
+ * resources associated with the stream. Failure to close the stream may result
+ * in a resource leak. The try-with-resources statement provides a useful
+ * construct to ensure that the stream is closed:
* <pre>
* Path dir = ...
- * DirectoryStream<Path> stream = dir.newDirectoryStream();
- * try {
+ * try (DirectoryStream<Path> stream = dir.newDirectoryStream()) {
* for (Path entry: stream) {
- * ..
+ * ...
* }
- * } finally {
- * stream.close();
* }
* </pre>
*
- * <p><b> A {@code DirectoryStream} is not a general-purpose {@code Iterable}.
- * While this interface extends {@code Iterable}, the {@code iterator} method
- * may only be invoked once to obtain the iterator; a second, or subsequent,
- * call to the {@code iterator} method throws {@code IllegalStateException}. </b>
- *
- * <p> A {@code DirectoryStream} is opened upon creation and is closed by
- * invoking the {@link #close close} method. Closing the directory stream
- * releases any resources associated with the stream. Once a directory stream
- * is closed, all further method invocations on the iterator throw {@link
- * java.util.ConcurrentModificationException} with cause {@link
- * ClosedDirectoryStreamException}.
+ * <p> Once a directory stream is closed, then further access to the directory,
+ * using the {@code Iterator}, behaves as if the end of stream has been reached.
+ * Due to read-ahead, the {@code Iterator} may return one or more elements
+ * after the directory stream has been closed. Once these buffered elements
+ * have been read, then subsequent calls to the {@code hasNext} method returns
+ * {@code false}, and subsequent calls to the {@code next} method will throw
+ * {@code NoSuchElementException}.
*
* <p> A directory stream is not required to be <i>asynchronously closeable</i>.
* If a thread is blocked on the directory stream's iterator reading from the
* directory, and another thread invokes the {@code close} method, then the
* second thread may block until the read operation is complete.
*
- * <p> The {@link Iterator#hasNext() hasNext} and {@link Iterator#next() next}
- * methods can encounter an I/O error when iterating over the directory in which
- * case {@code ConcurrentModificationException} is thrown with cause
- * {@link java.io.IOException}. The {@code hasNext} method is guaranteed to
- * read-ahead by at least one element. This means that if the {@code hasNext}
- * method returns {@code true} and is followed by a call to the {@code next}
- * method then it is guaranteed not to fail with a {@code
- * ConcurrentModificationException}.
+ * <p> If an I/O error is encountered when accessing the directory then it
+ * causes the {@code Iterator}'s {@code hasNext} or {@code next} methods to
+ * throw {@link DirectoryIteratorException} with the {@link IOException} as the
+ * cause. As stated above, the {@code hasNext} method is guaranteed to
+ * read-ahead by at least one element. This means that if {@code hasNext} method
+ * returns {@code true}, and is followed by a call to the {@code next} method,
+ * then it is guaranteed that the {@code next} method will not fail with a
+ * {@code DirectoryIteratorException}.
*
* <p> The elements returned by the iterator are in no specific order. Some file
* systems maintain special links to the directory itself and the directory's
* parent directory. Entries representing these links are not returned by the
* iterator.
*
- * <p> The iterator's {@link Iterator#remove() remove} method removes the
- * directory entry for the last element returned by the iterator, as if by
- * invoking the {@link Path#delete delete} method. If an I/O error or
- * security exception occurs then {@code ConcurrentModificationException} is
- * thrown with the cause.
- *
* <p> The iterator is <i>weakly consistent</i>. It is thread safe but does not
* freeze the directory while iterating, so it may (or may not) reflect updates
* to the directory that occur after the {@code DirectoryStream} is created.
*
+ * <p> <b>Usage Examples:</b>
+ * Suppose we want a list of the source files in a directory. This example uses
+ * both the for-each and try-with-resources constructs.
+ * <pre>
+ * List<Path> listSourceFiles(Path dir) throws IOException {
+ * List<Path> result = new ArrayList<Path>();
+ * try (DirectoryStream<Path> stream = dir.newDirectoryStream("*.{c,h,cpp,hpp,java}")) {
+ * for (Path entry: stream) {
+ * result.add(entry);
+ * }
+ * } catch (DirectoryIteratorException ex) {
+ * // I/O error encounted during the iteration, the cause is an IOException
+ * throw ex.getCause();
+ * }
+ * return result;
+ * }
+ * </pre>
* @param <T> The type of element returned by the iterator
*
* @since 1.7
--- a/jdk/src/share/classes/java/nio/file/Path.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/nio/file/Path.java Thu Sep 16 11:19:43 2010 -0700
@@ -984,11 +984,11 @@
* directory.
*
* <p> Where the filter terminates due to an uncaught error or runtime
- * exception then it is propogated to the iterator's {@link Iterator#hasNext()
+ * exception then it is propagated to the {@link Iterator#hasNext()
* hasNext} or {@link Iterator#next() next} method. Where an {@code
- * IOException} is thrown, it is propogated as a {@link
- * java.util.ConcurrentModificationException} with the {@code
- * IOException} as the cause.
+ * IOException} is thrown, it results in the {@code hasNext} or {@code
+ * next} method throwing a {@link DirectoryIteratorException} with the
+ * {@code IOException} as the cause.
*
* <p> When an implementation supports operations on entries in the
* directory that execute in a race-free manner then the returned directory
--- a/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java Thu Sep 16 11:19:43 2010 -0700
@@ -47,15 +47,6 @@
* newDirectoryStream} method will be a {@code SecureDirectoryStream} and must
* be cast to that type in order to invoke the methods defined by this interface.
*
- * <p> As specified by {@code DirectoryStream}, the iterator's {@link
- * java.util.Iterator#remove() remove} method removes the directory entry for
- * the last element returned by the iterator. In the case of a {@code
- * SecureDirectoryStream} the {@code remove} method behaves as if by invoking
- * the {@link #deleteFile deleteFile} or {@link #deleteDirectory deleteDirectory}
- * methods defined by this interface. The {@code remove} may require to examine
- * the file to determine if the file is a directory, and consequently, it may
- * not be atomic with respect to other file system operations.
- *
* <p> In the case of the default {@link java.nio.file.spi.FileSystemProvider
* provider}, and a security manager is set, then the permission checks are
* performed using the path obtained by resolving the given relative path
--- a/jdk/src/share/classes/java/sql/CallableStatement.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/CallableStatement.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2436,4 +2436,64 @@
*/
void setNClob(String parameterName, Reader reader)
throws SQLException;
+
+ //------------------------- JDBC 4.1 -----------------------------------
+
+
+ /**
+ *<p>Returns an object representing the value of OUT parameter
+ * {@code parameterIndex} and will convert from the
+ * SQL type of the parameter to the requested Java data type, if the
+ * conversion is supported. If the conversion is not
+ * supported or null is specified for the type, a
+ * <code>SQLException</code> is thrown.
+ *<p>
+ * At a minimum, an implementation must support the conversions defined in
+ * Appendix B, Table B-3 and conversion of appropriate user defined SQL
+ * types to a Java type which implements {@code SQLData}, or {@code Struct}.
+ * Additional conversions may be supported and are vendor defined.
+ *
+ * @param parameterIndex the first parameter is 1, the second is 2, and so on
+ * @param type Class representing the Java data type to convert the
+ * designated parameter to.
+ * @return an instance of {@code type} holding the OUT parameter value
+ * @throws SQLException if conversion is not supported, type is null or
+ * another error occurs. The getCause() method of the
+ * exception may provide a more detailed exception, for example, if
+ * a conversion error occurs
+ * @throws SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @since 1.7
+ */
+ public <T> T getObject(int parameterIndex, Class<T> type) throws SQLException;
+
+
+ /**
+ *<p>Returns an object representing the value of OUT parameter
+ * {@code parameterName} and will convert from the
+ * SQL type of the parameter to the requested Java data type, if the
+ * conversion is supported. If the conversion is not
+ * supported or null is specified for the type, a
+ * <code>SQLException</code> is thrown.
+ *<p>
+ * At a minimum, an implementation must support the conversions defined in
+ * Appendix B, Table B-3 and conversion of appropriate user defined SQL
+ * types to a Java type which implements {@code SQLData}, or {@code Struct}.
+ * Additional conversions may be supported and are vendor defined.
+ *
+ * @param parameterName the name of the parameter
+ * @param type Class representing the Java data type to convert
+ * the designated parameter to.
+ * @return an instance of {@code type} holding the OUT parameter
+ * value
+ * @throws SQLException if conversion is not supported, type is null or
+ * another error occurs. The getCause() method of the
+ * exception may provide a more detailed exception, for example, if
+ * a conversion error occurs
+ * @throws SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @since 1.7
+ */
+ public <T> T getObject(String parameterName, Class<T> type) throws SQLException;
+
}
--- a/jdk/src/share/classes/java/sql/Connection.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Connection.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package java.sql;
import java.util.Properties;
+import java.util.concurrent.Executor;
/**
* <P>A connection (session) with a specific
@@ -38,7 +39,7 @@
* information is obtained with the <code>getMetaData</code> method.
*
* <P><B>Note:</B> When configuring a <code>Connection</code>, JDBC applications
- * should use the appropritate <code>Connection</code> method such as
+ * should use the appropriate <code>Connection</code> method such as
* <code>setAutoCommit</code> or <code>setTransactionIsolation</code>.
* Applications should not invoke SQL commands directly to change the connection's
* configuration when there is a JDBC method available. By default a <code>Connection</code> object is in
@@ -80,7 +81,7 @@
* @see ResultSet
* @see DatabaseMetaData
*/
-public interface Connection extends Wrapper {
+public interface Connection extends Wrapper, AutoCloseable {
/**
* Creates a <code>Statement</code> object for sending
@@ -347,6 +348,13 @@
* <P>
* If the driver does not support catalogs, it will
* silently ignore this request.
+ * <p>
+ * Calling {@code setCatalog} has no effect on previously created or prepared
+ * {@code Statement} objects. It is implementation defined whether a DBMS
+ * prepare operation takes place immediately when the {@code Connection}
+ * method {@code prepareStatement} or {@code prepareCall} is invoked.
+ * For maximum portability, {@code setCatalog} should be called before a
+ * {@code Statement} is created or prepared.
*
* @param catalog the name of a catalog (subspace in this
* <code>Connection</code> object's database) in which to work
@@ -598,7 +606,17 @@
* <code>Connection</code> object.
* Unless the application has added an entry, the type map returned
* will be empty.
- *
+ * <p>
+ * You must invoke <code>setTypeMap</code> after making changes to the
+ * <code>Map</code> object returned from
+ * <code>getTypeMap</code> as a JDBC driver may create an internal
+ * copy of the <code>Map</code> object passed to <code>setTypeMap</code>:
+ * <p>
+ * <pre>
+ * Map<String,Class<?>> myMap = con.getTypeMap();
+ * myMap.put("mySchemaName.ATHLETES", Athletes.class);
+ * con.setTypeMap(myMap);
+ * </pre>
* @return the <code>java.util.Map</code> object associated
* with this <code>Connection</code> object
* @exception SQLException if a database access error occurs
@@ -614,7 +632,16 @@
* Installs the given <code>TypeMap</code> object as the type map for
* this <code>Connection</code> object. The type map will be used for the
* custom mapping of SQL structured types and distinct types.
- *
+ *<p>
+ * You must set the the values for the <code>TypeMap</code> prior to
+ * callng <code>setMap</code> as a JDBC driver may create an internal copy
+ * of the <code>TypeMap</code>:
+ * <p>
+ * <pre>
+ * Map myMap<String,Class<?>> = new HashMap<String,Class<?>>();
+ * myMap.put("mySchemaName.ATHLETES", Athletes.class);
+ * con.setTypeMap(myMap);
+ * </pre>
* @param map the <code>java.util.Map</code> object to install
* as the replacement for this <code>Connection</code>
* object's default type map
@@ -1274,4 +1301,186 @@
*/
Struct createStruct(String typeName, Object[] attributes)
throws SQLException;
+
+ //--------------------------JDBC 4.1 -----------------------------
+
+ /**
+ * Sets the given schema name to access.
+ * <P>
+ * If the driver does not support schemas, it will
+ * silently ignore this request.
+ * <p>
+ * Calling {@code setSchema} has no effect on previously created or prepared
+ * {@code Statement} objects. It is implementation defined whether a DBMS
+ * prepare operation takes place immediately when the {@code Connection}
+ * method {@code prepareStatement} or {@code prepareCall} is invoked.
+ * For maximum portability, {@code setSchema} should be called before a
+ * {@code Statement} is created or prepared.
+ *
+ * @param schema the name of a schema in which to work
+ * @exception SQLException if a database access error occurs
+ * or this method is called on a closed connection
+ * @see #getSchema
+ * @since 1.7
+ */
+ void setSchema(String schema) throws SQLException;
+
+ /**
+ * Retrieves this <code>Connection</code> object's current schema name.
+ *
+ * @return the current schema name or <code>null</code> if there is none
+ * @exception SQLException if a database access error occurs
+ * or this method is called on a closed connection
+ * @see #setSchema
+ * @since 1.7
+ */
+ String getSchema() throws SQLException;
+
+ /**
+ * Terminates an open connection. Calling <code>abort</code> results in:
+ * <ul>
+ * <li>The connection marked as closed
+ * <li>Closes any physical connection to the database
+ * <li>Releases resources used by the connection
+ * <li>Insures that any thread that is currently accessing the connection
+ * will either progress to completion or throw an <code>SQLException</code>.
+ * </ul>
+ * <p>
+ * Calling <code>abort</code> marks the connection closed and releases any
+ * resources. Calling <code>abort</code> on a closed connection is a
+ * no-op.
+ * <p>
+ * It is possible that the aborting and releasing of the resources that are
+ * held by the connection can take an extended period of time. When the
+ * <code>abort</code> method returns, the connection will have been marked as
+ * closed and the <code>Executor</code> that was passed as a parameter to abort
+ * may still be executing tasks to release resources.
+ * <p>
+ * This method checks to see that there is an <code>SQLPermission</code>
+ * object before allowing the method to proceed. If a
+ * <code>SecurityManager</code> exists and its
+ * <code>checkPermission</code> method denies calling <code>abort</code>,
+ * this method throws a
+ * <code>java.lang.SecurityException</code>.
+ * @param executor The <code>Executor</code> implementation which will
+ * be used by <code>abort</code>.
+ * @throws java.sql.SQLException if a database access error occurs or
+ * the {@code executor} is {@code null},
+ * @throws java.lang.SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies calling <code>abort</code>
+ * @see SecurityManager#checkPermission
+ * @see Executor
+ * @since 1.7
+ */
+ void abort(Executor executor) throws SQLException;
+
+ /**
+ *
+ * Sets the maximum period a <code>Connection</code> or
+ * objects created from the <code>Connection</code>
+ * will wait for the database to reply to any one request. If any
+ * request remains unanswered, the waiting method will
+ * return with a <code>SQLException</code>, and the <code>Connection</code>
+ * or objects created from the <code>Connection</code> will be marked as
+ * closed. Any subsequent use of
+ * the objects, with the exception of the <code>close</code>,
+ * <code>isClosed</code> or <code>Connection.isValid</code>
+ * methods, will result in a <code>SQLException</code>.
+ * <p>
+ * <b>Note</b>: This method is intended to address a rare but serious
+ * condition where network partitions can cause threads issuing JDBC calls
+ * to hang uninterruptedly in socket reads, until the OS TCP-TIMEOUT
+ * (typically 10 minutes). This method is related to the
+ * {@link #abort abort() } method which provides an administrator
+ * thread a means to free any such threads in cases where the
+ * JDBC connection is accessible to the administrator thread.
+ * The <code>setNetworkTimeout</code> method will cover cases where
+ * there is no administrator thread, or it has no access to the
+ * connection. This method is severe in it's effects, and should be
+ * given a high enough value so it is never triggered before any more
+ * normal timeouts, such as transaction timeouts.
+ * <p>
+ * JDBC driver implementations may also choose to support the
+ * {@code setNetworkTimeout} method to impose a limit on database
+ * response time, in environments where no network is present.
+ * <p>
+ * Drivers may internally implement some or all of their API calls with
+ * multiple internal driver-database transmissions, and it is left to the
+ * driver implementation to determine whether the limit will be
+ * applied always to the response to the API call, or to any
+ * single request made during the API call.
+ * <p>
+ *
+ * This method can be invoked more than once, such as to set a limit for an
+ * area of JDBC code, and to reset to the default on exit from this area.
+ * Invocation of this method has no impact on already outstanding
+ * requests.
+ * <p>
+ * The {@code Statement.setQueryTimeout()} timeout value is independent of the
+ * timeout value specified in {@code setNetworkTimeout}. If the query timeout
+ * expires before the network timeout then the
+ * statement execution will be canceled. If the network is still
+ * active the result will be that both the statement and connection
+ * are still usable. However if the network timeout expires before
+ * the query timeout or if the statement timeout fails due to network
+ * problems, the connection will be marked as closed, any resources held by
+ * the connection will be released and both the connection and
+ * statement will be unusable.
+ *<p>
+ * When the driver determines that the {@code setNetworkTimeout} timeout
+ * value has expired, the JDBC driver marks the connection
+ * closed and releases any resources held by the connection.
+ * <p>
+ *
+ * This method checks to see that there is an <code>SQLPermission</code>
+ * object before allowing the method to proceed. If a
+ * <code>SecurityManager</code> exists and its
+ * <code>checkPermission</code> method denies calling
+ * <code>setNetworkTimeout</code>, this method throws a
+ * <code>java.lang.SecurityException</code>.
+ *
+ * @param executor The <code>Executor</code> implementation which will
+ * be used by <code>setNetworkTimeout</code>.
+ * @param milliseconds The time in milliseconds to wait for the database
+ * operation
+ * to complete. If the JDBC driver does not support milliseconds, the
+ * JDBC driver will round the value up to the nearest second. If the
+ * timeout period expires before the operation
+ * completes, a SQLException will be thrown.
+ * A value of 0 indicates that there is not timeout for database operations.
+ * @throws java.sql.SQLException if a database access error occurs, this
+ * method is called on a closed connection,
+ * the {@code executor} is {@code null},
+ * or the value specified for <code>seconds</code> is less than 0.
+ * @throws java.lang.SecurityException if a security manager exists and its
+ * <code>checkPermission</code> method denies calling
+ * <code>setNetworkTimeout</code>.
+ * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @see SecurityManager#checkPermission
+ * @see Statement#setQueryTimeout
+ * @see #getNetworkTimeout
+ * @see #abort
+ * @see Executor
+ * @since 1.7
+ */
+ void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;
+
+
+ /**
+ * Retrieves the number of milliseconds the driver will
+ * wait for a database request to complete.
+ * If the limit is exceeded, a
+ * <code>SQLException</code> is thrown.
+ *
+ * @return the current timeout limit in milliseconds; zero means there is
+ * no limit
+ * @throws SQLException if a database access error occurs or
+ * this method is called on a closed <code>Connection</code>
+ * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @see #setNetworkTimeout
+ * @since 1.7
+ */
+ int getNetworkTimeout() throws SQLException;
}
--- a/jdk/src/share/classes/java/sql/DatabaseMetaData.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/DatabaseMetaData.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1342,10 +1342,10 @@
* defined.
* <LI><B>IS_NULLABLE</B> String => ISO rules are used to determine the nullability for a column.
* <UL>
- * <LI> YES --- if the parameter can include NULLs
- * <LI> NO --- if the parameter cannot include NULLs
+ * <LI> YES --- if the column can include NULLs
+ * <LI> NO --- if the column cannot include NULLs
* <LI> empty string --- if the nullability for the
- * parameter is unknown
+ * column is unknown
* </UL>
* <LI><B>SPECIFIC_NAME</B> String => the name which uniquely identifies this procedure within its schema.
* </OL>
@@ -1610,17 +1610,17 @@
* (starting at 1)
* <LI><B>IS_NULLABLE</B> String => ISO rules are used to determine the nullability for a column.
* <UL>
- * <LI> YES --- if the parameter can include NULLs
- * <LI> NO --- if the parameter cannot include NULLs
+ * <LI> YES --- if the column can include NULLs
+ * <LI> NO --- if the column cannot include NULLs
* <LI> empty string --- if the nullability for the
- * parameter is unknown
+ * column is unknown
* </UL>
- * <LI><B>SCOPE_CATLOG</B> String => catalog of table that is the scope
+ * <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the scope
* of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
* <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the scope
* of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
* <LI><B>SCOPE_TABLE</B> String => table name that this the scope
- * of a reference attribure (<code>null</code> if the DATA_TYPE isn't REF)
+ * of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
* <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
* Ref type, SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
* isn't DISTINCT or user-generated REF)
@@ -1629,11 +1629,16 @@
* <LI> YES --- if the column is auto incremented
* <LI> NO --- if the column is not auto incremented
* <LI> empty string --- if it cannot be determined whether the column is auto incremented
- * parameter is unknown
+ * </UL>
+ * <LI><B>IS_GENERATEDCOLUMN</B> String => Indicates whether this is a generated column
+ * <UL>
+ * <LI> YES --- if this a generated column
+ * <LI> NO --- if this not a generated column
+ * <LI> empty string --- if it cannot be determined whether this is a generated column
* </UL>
* </OL>
*
- * <p>The COLUMN_SIZE column the specified column size for the given column.
+ * <p>The COLUMN_SIZE column specifies the column size for the given column.
* For numeric data, this is the maximum precision. For character data, this is the length in characters.
* For datetime datatypes, this is the length in characters of the String representation (assuming the
* maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes. For the ROWID datatype,
@@ -3186,7 +3191,7 @@
* Retrieves whether this database supports statement pooling.
*
* @return <code>true</code> if so; <code>false</code> otherwise
- * @throws SQLExcpetion if a database access error occurs
+ * @throws SQLException if a database access error occurs
* @since 1.4
*/
boolean supportsStatementPooling() throws SQLException;
@@ -3568,4 +3573,83 @@
*/
int functionReturnsTable = 2;
+ //--------------------------JDBC 4.1 -----------------------------
+
+ /**
+ * Retrieves a description of the pseudo or hidden columns available
+ * in a given table within the specified catalog and schema.
+ * Pseudo or hidden columns may not always be stored within
+ * a table and are not visible in a ResultSet unless they are
+ * specified in the query's outermost SELECT list. Pseudo or hidden
+ * columns may not necessarily be able to be modified. If there are
+ * no pseudo or hidden columns, an empty ResultSet is returned.
+ *
+ * <P>Only column descriptions matching the catalog, schema, table
+ * and column name criteria are returned. They are ordered by
+ * <code>TABLE_CAT</code>,<code>TABLE_SCHEM</code>, <code>TABLE_NAME</code>
+ * and <code>COLUMN_NAME</code>.
+ *
+ * <P>Each column description has the following columns:
+ * <OL>
+ * <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+ * <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+ * <LI><B>TABLE_NAME</B> String => table name
+ * <LI><B>COLUMN_NAME</B> String => column name
+ * <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
+ * <LI><B>COLUMN_SIZE</B> int => column size.
+ * <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits. Null is returned for data types where
+ * DECIMAL_DIGITS is not applicable.
+ * <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
+ * <LI><B>COLUMN_USAGE</B> String => The allowed usage for the column. The
+ * value returned will correspond to the enum name returned by {@link PseudoColumnUsage#name PseudoColumnUsage.name()}
+ * <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
+ * <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
+ * maximum number of bytes in the column
+ * <LI><B>IS_NULLABLE</B> String => ISO rules are used to determine the nullability for a column.
+ * <UL>
+ * <LI> YES --- if the column can include NULLs
+ * <LI> NO --- if the column cannot include NULLs
+ * <LI> empty string --- if the nullability for the column is unknown
+ * </UL>
+ * </OL>
+ *
+ * <p>The COLUMN_SIZE column specifies the column size for the given column.
+ * For numeric data, this is the maximum precision. For character data, this is the length in characters.
+ * For datetime datatypes, this is the length in characters of the String representation (assuming the
+ * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes. For the ROWID datatype,
+ * this is the length in bytes. Null is returned for data types where the
+ * column size is not applicable.
+ *
+ * @param catalog a catalog name; must match the catalog name as it
+ * is stored in the database; "" retrieves those without a catalog;
+ * <code>null</code> means that the catalog name should not be used to narrow
+ * the search
+ * @param schemaPattern a schema name pattern; must match the schema name
+ * as it is stored in the database; "" retrieves those without a schema;
+ * <code>null</code> means that the schema name should not be used to narrow
+ * the search
+ * @param tableNamePattern a table name pattern; must match the
+ * table name as it is stored in the database
+ * @param columnNamePattern a column name pattern; must match the column
+ * name as it is stored in the database
+ * @return <code>ResultSet</code> - each row is a column description
+ * @exception SQLException if a database access error occurs
+ * @see PseudoColumnUsage
+ * @since 1.7
+ */
+ ResultSet getPseudoColumns(String catalog, String schemaPattern,
+ String tableNamePattern, String columnNamePattern)
+ throws SQLException;
+
+ /**
+ * Retrieves whether a generated key will always be returned if the column
+ * name(s) or indexe(s) specified for the auto generated key column(s)
+ * are valid and the statement succeeds. The key that is returned may or
+ * may not be based on the column(s) for the auto generated key.
+ * Consult your JDBC driver documentation for additional details.
+ * @return <code>true</code> if so; <code>false</code> otherwise
+ * @exception SQLException if a database access error occurs
+ * @since 1.7
+ */
+ boolean generatedKeyAlwaysReturned() throws SQLException;
}
--- a/jdk/src/share/classes/java/sql/Date.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Date.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -96,11 +96,12 @@
* a <code>Date</code> value.
*
* @param s a <code>String</code> object representing a date in
- * in the format "yyyy-mm-dd"
+ * in the format "yyyy-[m]m-[d]d". The leading zero for <code>mm</code>
+ * and <code>dd</code> may also be omitted.
* @return a <code>java.sql.Date</code> object representing the
* given date
* @throws IllegalArgumentException if the date given is not in the
- * JDBC date escape format (yyyy-mm-dd)
+ * JDBC date escape format (yyyy-[m]m-[d]d)
*/
public static Date valueOf(String s) {
final int YEAR_LENGTH = 4;
@@ -123,8 +124,9 @@
String yyyy = s.substring(0, firstDash);
String mm = s.substring(firstDash + 1, secondDash);
String dd = s.substring(secondDash + 1);
- if (yyyy.length() == YEAR_LENGTH && mm.length() == MONTH_LENGTH &&
- dd.length() == DAY_LENGTH) {
+ if (yyyy.length() == YEAR_LENGTH &&
+ (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
+ (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
int year = Integer.parseInt(yyyy);
int month = Integer.parseInt(mm);
int day = Integer.parseInt(dd);
--- a/jdk/src/share/classes/java/sql/Driver.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Driver.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
package java.sql;
+import java.util.logging.Logger;
+
/**
* The interface that every driver class must implement.
* <P>The Java SQL framework allows for multiple database drivers.
@@ -150,4 +152,19 @@
* otherwise
*/
boolean jdbcCompliant();
+
+ //------------------------- JDBC 4.1 -----------------------------------
+
+ /**
+ * Return the parent Logger of all the Loggers used by this driver. This
+ * should be the Logger farthest from the root Logger that is
+ * still an ancestor of all of the Loggers used by this driver. Configuring
+ * this Logger will affect all of the log messages generated by the driver.
+ * In the worst case, this may be the root Logger.
+ *
+ * @return the parent Logger for this driver
+ * @throws SQLFeatureNotSupportedException if the driver does not use <code>java.util.logging<code>.
+ * @since 1.7
+ */
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
--- a/jdk/src/share/classes/java/sql/PreparedStatement.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/PreparedStatement.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,6 +69,10 @@
* @exception SQLException if a database access error occurs;
* this method is called on a closed <code>PreparedStatement</code> or the SQL
* statement does not return a <code>ResultSet</code> object
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
*/
ResultSet executeQuery() throws SQLException;
@@ -82,8 +86,11 @@
* or (2) 0 for SQL statements that return nothing
* @exception SQLException if a database access error occurs;
* this method is called on a closed <code>PreparedStatement</code>
- * or the SQL
- * statement returns a <code>ResultSet</code> object
+ * or the SQL statement returns a <code>ResultSet</code> object
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
*/
int executeUpdate() throws SQLException;
@@ -463,6 +470,10 @@
* @exception SQLException if a database access error occurs;
* this method is called on a closed <code>PreparedStatement</code>
* or an argument is supplied to this method
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @see Statement#execute
* @see Statement#getResultSet
* @see Statement#getUpdateCount
@@ -1208,4 +1219,5 @@
void setNClob(int parameterIndex, Reader reader)
throws SQLException;
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/sql/PseudoColumnUsage.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+
+/**
+ * Enumeration for pseudo/hidden column usage.
+ *
+ * @since 1.7
+ * @see DatabaseMetaData#getPseudoColumns
+ */
+public enum PseudoColumnUsage {
+
+ /**
+ * The pseudo/hidden column may only be used in a SELECT list.
+ */
+ SELECT_LIST_ONLY,
+
+ /**
+ * The pseudo/hidden column may only be used in a WHERE clause.
+ */
+ WHERE_CLAUSE_ONLY,
+
+ /**
+ * There are no restrictions on the usage of the pseudo/hidden columns.
+ */
+ NO_USAGE_RESTRICTIONS,
+
+ /**
+ * The usage of the pseudo/hidden column cannot be determined.
+ */
+ USAGE_UNKNOWN
+
+}
--- a/jdk/src/share/classes/java/sql/ResultSet.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/ResultSet.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,7 @@
* @see ResultSetMetaData
*/
-public interface ResultSet extends Wrapper {
+public interface ResultSet extends Wrapper, AutoCloseable {
/**
* Moves the cursor froward one row from its current position.
@@ -1187,6 +1187,9 @@
* cursor on the last row; calling the method <code>absolute(-2)</code>
* moves the cursor to the next-to-last row, and so on.
*
+ * <p>If the row number specified is zero, the cursor is moved to
+ * before the first row.
+ *
* <p>An attempt to position the cursor beyond the first/last row in
* the result set leaves the cursor before the first row or after
* the last row.
@@ -1196,9 +1199,10 @@
* is the same as calling <code>last()</code>.
*
* @param row the number of the row to which the cursor should move.
- * A positive number indicates the row number counting from the
- * beginning of the result set; a negative number indicates the
- * row number counting from the end of the result set
+ * A value of zero indicates that the cursor will be positioned
+ * before the first row; a positive number indicates the row number
+ * counting from the beginning of the result set; a negative number
+ * indicates the row number counting from the end of the result set
* @return <code>true</code> if the cursor is moved to a position in this
* <code>ResultSet</code> object;
* <code>false</code> if the cursor is before the first row or after the
@@ -2529,7 +2533,7 @@
* @exception SQLException if the columnLabel is not valid;
* if a database access error occurs
* or this method is called on a closed result set
- * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+ * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
* this method
* @since 1.2
*/
@@ -4072,4 +4076,64 @@
*/
void updateNClob(String columnLabel, Reader reader) throws SQLException;
+ //------------------------- JDBC 4.1 -----------------------------------
+
+
+ /**
+ *<p>Retrieves the value of the designated column in the current row
+ * of this <code>ResultSet</code> object and will convert from the
+ * SQL type of the column to the requested Java data type, if the
+ * conversion is supported. If the conversion is not
+ * supported or null is specified for the type, a
+ * <code>SQLException</code> is thrown.
+ *<p>
+ * At a minimum, an implementation must support the conversions defined in
+ * Appendix B, Table B-3 and conversion of appropriate user defined SQL
+ * types to a Java type which implements {@code SQLData}, or {@code Struct}.
+ * Additional conversions may be supported and are vendor defined.
+ *
+ * @param columnIndex the first column is 1, the second is 2, ...
+ * @param type Class representing the Java data type to convert the designated
+ * column to.
+ * @return an instance of {@code type} holding the column value
+ * @throws SQLException if conversion is not supported, type is null or
+ * another error occurs. The getCause() method of the
+ * exception may provide a more detailed exception, for example, if
+ * a conversion error occurs
+ * @throws SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @since 1.7
+ */
+ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException;
+
+
+ /**
+ *<p>Retrieves the value of the designated column in the current row
+ * of this <code>ResultSet</code> object and will convert from the
+ * SQL type of the column to the requested Java data type, if the
+ * conversion is supported. If the conversion is not
+ * supported or null is specified for the type, a
+ * <code>SQLException</code> is thrown.
+ *<p>
+ * At a minimum, an implementation must support the conversions defined in
+ * Appendix B, Table B-3 and conversion of appropriate user defined SQL
+ * types to a Java type which implements {@code SQLData}, or {@code Struct}.
+ * Additional conversions may be supported and are vendor defined.
+ *
+ * @param columnLabel the label for the column specified with the SQL AS clause.
+ * If the SQL AS clause was not specified, then the label is the name
+ * of the column
+ * @param type Class representing the Java data type to convert the designated
+ * column to.
+ * @return an instance of {@code type} holding the column value
+ * @throws SQLException if conversion is not supported, type is null or
+ * another error occurs. The getCause() method of the
+ * exception may provide a more detailed exception, for example, if
+ * a conversion error occurs
+ * @throws SQLFeatureNotSupportedException if the JDBC driver does not support
+ * this method
+ * @since 1.7
+ */
+ public <T> T getObject(String columnLabel, Class<T> type) throws SQLException;
+
}
--- a/jdk/src/share/classes/java/sql/SQLDataException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLDataException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,13 @@
package java.sql;
/**
- * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>22</i>'. This indicates
- * various data errors, including but not limited to not-allowed conversion, division by 0
- * and invalid arguments to functions.
- *
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>22</i>', or under vendor-specified conditions. This indicates
+ * various data errors, including but not limited to data conversion errors,
+ * division by 0, and invalid arguments to functions.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLDataException extends SQLNonTransientException {
--- a/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLIntegrityConstraintViolationException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,13 @@
package java.sql;
/**
- * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>23</i>'. This indicates that an integrity
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>23</i>', or under vendor-specified conditions.
+ * This indicates that an integrity
* constraint (foreign key, primary key or unique key) has been violated.
- *
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLIntegrityConstraintViolationException extends SQLNonTransientException {
--- a/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLInvalidAuthorizationSpecException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,13 @@
package java.sql;
/**
- * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>28</i>'. This indicated that the
- * authorization credentials presented during connection establishment are not valid.
- *
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>28</i>', or under vendor-specified conditions. This indicates that
+ * the authorization credentials presented during connection establishment
+ * are not valid.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLInvalidAuthorizationSpecException extends SQLNonTransientException {
--- a/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLNonTransientConnectionException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,13 @@
package java.sql;
/**
- * <P> The subclass of {@link SQLException} thrown for the SQLState
- * class value '<i>08</i>', representing
- * that the connection operation that failed will not succeed when
+ * The subclass of {@link SQLException} thrown for the SQLState
+ * class value '<i>08</i>', or under vendor-specified conditions. This
+ * indicates that the connection operation that failed will not succeed if
* the operation is retried without the cause of the failure being corrected.
* <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLNonTransientConnectionException extends java.sql.SQLNonTransientException {
--- a/jdk/src/share/classes/java/sql/SQLPermission.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLPermission.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,9 +30,14 @@
/**
* The permission for which the <code>SecurityManager</code> will check
- * when code that is running in an applet calls the
- * <code>DriverManager.setLogWriter</code> method or the
- * <code>DriverManager.setLogStream</code> (deprecated) method.
+ * when code that is running in an applet, or an application with a
+ * <code>SecurityManager</code> enabled, calls the
+ * <code>DriverManager.setLogWriter</code> method,
+ * <code>DriverManager.setLogStream</code> (deprecated) method,
+ * {@code SyncFactory.setJNDIContext} method,
+ * {@code SyncFactory.setLogger} method,
+ * {@code Connection.setNetworktimeout} method,
+ * or the <code>Connection.abort</code> method.
* If there is no <code>SQLPermission</code> object, these methods
* throw a <code>java.lang.SecurityException</code> as a runtime exception.
* <P>
@@ -48,7 +53,6 @@
* but <code>*loadLibrary</code> or <code>a*b</code> is not valid.
* <P>
* The following table lists all the possible <code>SQLPermission</code> target names.
- * Currently, the only name allowed is <code>setLog</code>.
* The table gives a description of what the permission allows
* and a discussion of the risks of granting code the permission.
* <P>
@@ -67,9 +71,33 @@
* The contents of the log may contain usernames and passwords,
* SQL statements, and SQL data.</td>
* </tr>
+ * <tr>
+ * <td>callAbort</td>
+ * <td>Allows the invocation of the {@code Connection} method
+ * {@code abort}</td>
+ * <td>Permits an application to terminate a physical connection to a
+ * database.</td>
+ * </tr>
+ * <tr>
+ * <td>setSyncFactory</td>
+ * <td>Allows the invocation of the {@code SyncFactory} methods
+ * {@code setJNDIContext} and {@code setLogger}</td>
+ * <td>Permits an application to specify the JNDI context from which the
+ * {@code SyncProvider} implementations can be retrieved from and the logging
+ * object to be used by the{@codeSyncProvider} implementation.</td>
+ * </tr>
*
+ * <tr>
+ * <td>setNetworkTimeout</td>
+ * <td>Allows the invocation of the {@code Connection} method
+ * {@code setNetworkTimeout}</td>
+ * <td>Permits an application to specify the maximum period a
+ * <code>Connection</code> or
+ * objects created from the <code>Connection</code>
+ * will wait for the database to reply to any one request.</td>
+ * </tr>
* </table>
- *
+ *<p>
* The person running an applet decides what permissions to allow
* and will run the <code>Policy Tool</code> to create an
* <code>SQLPermission</code> in a policy file. A programmer does
--- a/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLSyntaxErrorException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,12 @@
package java.sql;
/**
- * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>42</i>'. This indicates that the
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>42</i>', or under vendor-specified conditions. This indicates that the
* in-progress query has violated SQL syntax rules.
- *
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLSyntaxErrorException extends SQLNonTransientException {
--- a/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLTransactionRollbackException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,13 @@
package java.sql;
/**
- * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>40</i>'. This indicates that the
- * current statement was automatically rolled back by the database becuase of deadlock or other
- * transaction serialization failures.
- *
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>40</i>', or under vendor-specified conditions. This indicates that the
+ * current statement was automatically rolled back by the database because
+ * of deadlock or other transaction serialization failures.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLTransactionRollbackException extends SQLTransientException {
--- a/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/SQLTransientConnectionException.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,11 +27,12 @@
/**
* The subclass of {@link SQLException} for the SQLState class
- * value '<i>08</i>', representing
- * that the connection operation that failed might be able to succeed when
+ * value '<i>08</i>', or under vendor-specified conditions. This indicates
+ * that the connection operation that failed might be able to succeed if
* the operation is retried without any application-level changes.
- *<p>
- *
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
* @since 1.6
*/
public class SQLTransientConnectionException extends java.sql.SQLTransientException {
--- a/jdk/src/share/classes/java/sql/Statement.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Statement.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,20 +40,27 @@
* @see Connection#createStatement
* @see ResultSet
*/
-public interface Statement extends Wrapper {
+public interface Statement extends Wrapper, AutoCloseable {
/**
* Executes the given SQL statement, which returns a single
* <code>ResultSet</code> object.
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql an SQL statement to be sent to the database, typically a
* static SQL <code>SELECT</code> statement
* @return a <code>ResultSet</code> object that contains the data produced
* by the given query; never <code>null</code>
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the given
+ * this method is called on a closed <code>Statement</code>, the given
* SQL statement produces anything other than a single
- * <code>ResultSet</code> object
+ * <code>ResultSet</code> object, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
*/
ResultSet executeQuery(String sql) throws SQLException;
@@ -61,7 +68,9 @@
* Executes the given SQL statement, which may be an <code>INSERT</code>,
* <code>UPDATE</code>, or <code>DELETE</code> statement or an
* SQL statement that returns nothing, such as an SQL DDL statement.
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
* <code>DELETE</code>; or an SQL statement that returns nothing,
* such as a DDL statement.
@@ -70,8 +79,13 @@
* or (2) 0 for SQL statements that return nothing
*
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the given
- * SQL statement produces a <code>ResultSet</code> object
+ * this method is called on a closed <code>Statement</code>, the given
+ * SQL statement produces a <code>ResultSet</code> object, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
*/
int executeUpdate(String sql) throws SQLException;
@@ -198,11 +212,21 @@
/**
* Sets the number of seconds the driver will wait for a
* <code>Statement</code> object to execute to the given number of seconds.
- * If the limit is exceeded, an <code>SQLException</code> is thrown. A JDBC
- * driver must apply this limit to the <code>execute</code>,
- * <code>executeQuery</code> and <code>executeUpdate</code> methods. JDBC driver
- * implementations may also apply this limit to <code>ResultSet</code> methods
+ *By default there is no limit on the amount of time allowed for a running
+ * statement to complete. If the limit is exceeded, an
+ * <code>SQLTimeoutException</code> is thrown.
+ * A JDBC driver must apply this limit to the <code>execute</code>,
+ * <code>executeQuery</code> and <code>executeUpdate</code> methods.
+ * <p>
+ * <strong>Note:</strong> JDBC driver implementations may also apply this
+ * limit to {@code ResultSet} methods
* (consult your driver vendor documentation for details).
+ * <p>
+ * <strong>Note:</strong> In the case of {@code Statement} batching, it is
+ * implementation defined as to whether the time-out is applied to
+ * individual SQL commands added via the {@code addBatch} method or to
+ * the entire batch of SQL commands invoked by the {@code executeBatch}
+ * method (consult your driver vendor documentation for details).
*
* @param seconds the new query timeout limit in seconds; zero means
* there is no limit
@@ -300,13 +324,21 @@
* <code>getResultSet</code> or <code>getUpdateCount</code>
* to retrieve the result, and <code>getMoreResults</code> to
* move to any subsequent result(s).
- *
+ * <p>
+ *<strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql any SQL statement
* @return <code>true</code> if the first result is a <code>ResultSet</code>
* object; <code>false</code> if it is an update count or there are
* no results
- * @exception SQLException if a database access error occurs or
- * this method is called on a closed <code>Statement</code>
+ * @exception SQLException if a database access error occurs,
+ * this method is called on a closed <code>Statement</code>,
+ * the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @see #getResultSet
* @see #getUpdateCount
* @see #getMoreResults
@@ -465,12 +497,14 @@
* <code>Statement</code> object. The commands in this list can be
* executed as a batch by calling the method <code>executeBatch</code>.
* <P>
- *
+ *<strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql typically this is a SQL <code>INSERT</code> or
* <code>UPDATE</code> statement
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the
- * driver does not support batch updates
+ * this method is called on a closed <code>Statement</code>, the
+ * driver does not support batch updates, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @see #executeBatch
* @see DatabaseMetaData#supportsBatchUpdates
* @since 1.2
@@ -536,7 +570,10 @@
* driver does not support batch statements. Throws {@link BatchUpdateException}
* (a subclass of <code>SQLException</code>) if one of the commands sent to the
* database fails to execute properly or attempts to return a result set.
- *
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
*
* @see #addBatch
* @see DatabaseMetaData#supportsBatchUpdates
@@ -678,7 +715,9 @@
* flag if the SQL statement
* is not an <code>INSERT</code> statement, or an SQL statement able to return
* auto-generated keys (the list of such statements is vendor-specific).
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
* <code>DELETE</code>; or an SQL statement that returns nothing,
* such as a DDL statement.
@@ -693,10 +732,15 @@
*
* @exception SQLException if a database access error occurs,
* this method is called on a closed <code>Statement</code>, the given
- * SQL statement returns a <code>ResultSet</code> object, or
- * the given constant is not one of those allowed
+ * SQL statement returns a <code>ResultSet</code> object,
+ * the given constant is not one of those allowed, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @exception SQLFeatureNotSupportedException if the JDBC driver does not support
* this method with a constant of Statement.RETURN_GENERATED_KEYS
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @since 1.4
*/
int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
@@ -709,7 +753,9 @@
* available. The driver will ignore the array if the SQL statement
* is not an <code>INSERT</code> statement, or an SQL statement able to return
* auto-generated keys (the list of such statements is vendor-specific).
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
* <code>DELETE</code>; or an SQL statement that returns nothing,
* such as a DDL statement.
@@ -721,10 +767,15 @@
*
* @exception SQLException if a database access error occurs,
* this method is called on a closed <code>Statement</code>, the SQL
- * statement returns a <code>ResultSet</code> object, or the
- * second argument supplied to this method is not an <code>int</code> array
- * whose elements are valid column indexes
+ * statement returns a <code>ResultSet</code> object,the second argument
+ * supplied to this method is not an
+ * <code>int</code> array whose elements are valid column indexes, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @since 1.4
*/
int executeUpdate(String sql, int columnIndexes[]) throws SQLException;
@@ -737,7 +788,9 @@
* available. The driver will ignore the array if the SQL statement
* is not an <code>INSERT</code> statement, or an SQL statement able to return
* auto-generated keys (the list of such statements is vendor-specific).
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
* <code>DELETE</code>; or an SQL statement that returns nothing,
* such as a DDL statement.
@@ -748,11 +801,15 @@
* that return nothing
* @exception SQLException if a database access error occurs,
* this method is called on a closed <code>Statement</code>, the SQL
- * statement returns a <code>ResultSet</code> object, or the
+ * statement returns a <code>ResultSet</code> object, the
* second argument supplied to this method is not a <code>String</code> array
- * whose elements are valid column names
- *
+ * whose elements are valid column names, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @since 1.4
*/
int executeUpdate(String sql, String columnNames[]) throws SQLException;
@@ -776,7 +833,9 @@
* <code>getResultSet</code> or <code>getUpdateCount</code>
* to retrieve the result, and <code>getMoreResults</code> to
* move to any subsequent result(s).
- *
+ *<p>
+ *<strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql any SQL statement
* @param autoGeneratedKeys a constant indicating whether auto-generated
* keys should be made available for retrieval using the method
@@ -787,12 +846,18 @@
* object; <code>false</code> if it is an update count or there are
* no results
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the second
+ * this method is called on a closed <code>Statement</code>, the second
* parameter supplied to this method is not
* <code>Statement.RETURN_GENERATED_KEYS</code> or
- * <code>Statement.NO_GENERATED_KEYS</code>.
+ * <code>Statement.NO_GENERATED_KEYS</code>,
+ * the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @exception SQLFeatureNotSupportedException if the JDBC driver does not support
* this method with a constant of Statement.RETURN_GENERATED_KEYS
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @see #getResultSet
* @see #getUpdateCount
* @see #getMoreResults
@@ -823,7 +888,9 @@
* <code>getResultSet</code> or <code>getUpdateCount</code>
* to retrieve the result, and <code>getMoreResults</code> to
* move to any subsequent result(s).
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql any SQL statement
* @param columnIndexes an array of the indexes of the columns in the
* inserted row that should be made available for retrieval by a
@@ -832,10 +899,15 @@
* object; <code>false</code> if it is an update count or there
* are no results
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the
+ * this method is called on a closed <code>Statement</code>, the
* elements in the <code>int</code> array passed to this method
- * are not valid column indexes
+ * are not valid column indexes, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @see #getResultSet
* @see #getUpdateCount
* @see #getMoreResults
@@ -865,7 +937,9 @@
* <code>getResultSet</code> or <code>getUpdateCount</code>
* to retrieve the result, and <code>getMoreResults</code> to
* move to any subsequent result(s).
- *
+ *<p>
+ * <strong>Note:</strong>This method cannot be called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>.
* @param sql any SQL statement
* @param columnNames an array of the names of the columns in the inserted
* row that should be made available for retrieval by a call to the
@@ -874,10 +948,15 @@
* object; <code>false</code> if it is an update count or there
* are no more results
* @exception SQLException if a database access error occurs,
- * this method is called on a closed <code>Statement</code> or the
+ * this method is called on a closed <code>Statement</code>,the
* elements of the <code>String</code> array passed to this
- * method are not valid column names
+ * method are not valid column names, the method is called on a
+ * <code>PreparedStatement</code> or <code>CallableStatement</code>
* @throws SQLFeatureNotSupportedException if the JDBC driver does not support this method
+ * @throws SQLTimeoutException when the driver has determined that the
+ * timeout value that was specified by the {@code setQueryTimeout}
+ * method has been exceeded and has at least attempted to cancel
+ * the currently running {@code Statement}
* @see #getResultSet
* @see #getUpdateCount
* @see #getMoreResults
@@ -951,4 +1030,34 @@
boolean isPoolable()
throws SQLException;
+ //--------------------------JDBC 4.1 -----------------------------
+
+ /**
+ * Specifies that this {@code Statement} will be closed when all its
+ * dependent result sets are closed. If execution of the {@code Statement}
+ * does not produce any result sets, this method has no effect.
+ * <p>
+ * <strong>Note:</strong> Multiple calls to {@code closeOnCompletion} do
+ * not toggle the effect on this {@code Statement}. However, a call to
+ * {@code closeOnCompletion} does effect both the subsequent execution of
+ * statements, and statements that currently have open, dependent,
+ * result sets.
+ *
+ * @throws SQLException if this method is called on a closed
+ * {@code Statement}
+ * @since 1.7
+ */
+ public void closeOnCompletion() throws SQLException;
+
+ /**
+ * Returns a value indicating whether this {@code Statement} will be
+ * closed when all dependent objects such as resultsets are closed.
+ * @return {@code true} if the {@code Statement} will be closed when all
+ * of its dependent objects are closed; {@code false} otherwise
+ * @throws SQLException if this method is called on a closed
+ * {@code Statement}
+ * @since 1.7
+ */
+ public boolean isCloseOnCompletion() throws SQLException;
+
}
--- a/jdk/src/share/classes/java/sql/Timestamp.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/sql/Timestamp.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -155,19 +155,26 @@
* Converts a <code>String</code> object in JDBC timestamp escape format to a
* <code>Timestamp</code> value.
*
- * @param s timestamp in format <code>yyyy-mm-dd hh:mm:ss[.f...]</code>. The
- * fractional seconds may be omitted.
+ * @param s timestamp in format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>. The
+ * fractional seconds may be omitted. The leading zero for <code>mm</code>
+ * and <code>dd</code> may also be omitted.
+ *
* @return corresponding <code>Timestamp</code> value
* @exception java.lang.IllegalArgumentException if the given argument
- * does not have the format <code>yyyy-mm-dd hh:mm:ss[.f...]</code>
+ * does not have the format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>
*/
public static Timestamp valueOf(String s) {
+ final int YEAR_LENGTH = 4;
+ final int MONTH_LENGTH = 2;
+ final int DAY_LENGTH = 2;
+ final int MAX_MONTH = 12;
+ final int MAX_DAY = 31;
String date_s;
String time_s;
String nanos_s;
- int year;
- int month;
- int day;
+ int year = 0;
+ int month = 0;
+ int day = 0;
int hour;
int minute;
int second;
@@ -182,17 +189,9 @@
String zeros = "000000000";
String delimiterDate = "-";
String delimiterTime = ":";
- StringTokenizer stringTokeninzerDate;
- StringTokenizer stringTokeninzerTime;
if (s == null) throw new java.lang.IllegalArgumentException("null string");
- int counterD = 0;
- int intDate[] = {4,2,2};
-
- int counterT = 0;
- int intTime[] = {2,2,12};
-
// Split the string into date and time components
s = s.trim();
dividingSpace = s.indexOf(' ');
@@ -203,30 +202,6 @@
throw new java.lang.IllegalArgumentException(formatError);
}
- stringTokeninzerTime = new StringTokenizer(time_s, delimiterTime);
- stringTokeninzerDate = new StringTokenizer(date_s, delimiterDate);
-
- while(stringTokeninzerDate.hasMoreTokens()) {
- String tokenDate = stringTokeninzerDate.nextToken();
- if(tokenDate.length() != intDate[counterD] ) {
- throw new java.lang.IllegalArgumentException(formatError);
- }
- counterD++;
- }
-
- /*
- //Commenting this portion out for checking of time
-
- while(stringTokeninzerTime.hasMoreTokens()) {
- String tokenTime = stringTokeninzerTime.nextToken();
-
- if (counterT < 2 && tokenTime.length() != intTime[counterT] ) {
- throw new java.lang.IllegalArgumentException(formatError);
- }
- counterT++;
- }
- */
-
// Parse the date
firstDash = date_s.indexOf('-');
secondDash = date_s.indexOf('-', firstDash+1);
@@ -239,14 +214,24 @@
period = time_s.indexOf('.', secondColon+1);
// Convert the date
- if ((firstDash > 0) && (secondDash > 0) &&
- (secondDash < date_s.length()-1)) {
- year = Integer.parseInt(date_s.substring(0, firstDash)) - 1900;
- month =
- Integer.parseInt(date_s.substring
- (firstDash+1, secondDash)) - 1;
- day = Integer.parseInt(date_s.substring(secondDash+1));
- } else {
+ boolean parsedDate = false;
+ if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) {
+ String yyyy = date_s.substring(0, firstDash);
+ String mm = date_s.substring(firstDash + 1, secondDash);
+ String dd = date_s.substring(secondDash + 1);
+ if (yyyy.length() == YEAR_LENGTH &&
+ (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
+ (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
+ year = Integer.parseInt(yyyy);
+ month = Integer.parseInt(mm);
+ day = Integer.parseInt(dd);
+
+ if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
+ parsedDate = true;
+ }
+ }
+ }
+ if (! parsedDate) {
throw new java.lang.IllegalArgumentException(formatError);
}
@@ -272,10 +257,10 @@
second = Integer.parseInt(time_s.substring(secondColon+1));
}
} else {
- throw new java.lang.IllegalArgumentException();
+ throw new java.lang.IllegalArgumentException(formatError);
}
- return new Timestamp(year, month, day, hour, minute, second, a_nanos);
+ return new Timestamp(year - 1900, month - 1, day, hour, minute, second, a_nanos);
}
/**
@@ -502,14 +487,10 @@
/**
* Compares this <code>Timestamp</code> object to the given
- * <code>Date</code>, which must be a <code>Timestamp</code>
- * object. If the argument is not a <code>Timestamp</code> object,
- * this method throws a <code>ClassCastException</code> object.
- * (<code>Timestamp</code> objects are
- * comparable only to other <code>Timestamp</code> objects.)
+ * <code>Date</code> object.
*
- * @param o the <code>Date</code> to be compared, which must be a
- * <code>Timestamp</code> object
+ * @param o the <code>Date</code> to be compared to
+ * this <code>Timestamp</code> object
* @return the value <code>0</code> if this <code>Timestamp</code> object
* and the given object are equal; a value less than <code>0</code>
* if this <code>Timestamp</code> object is before the given argument;
--- a/jdk/src/share/classes/java/util/ConcurrentModificationException.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/ConcurrentModificationException.java Thu Sep 16 11:19:43 2010 -0700
@@ -49,9 +49,9 @@
* <p>Note that fail-fast behavior cannot be guaranteed as it is, generally
* speaking, impossible to make any hard guarantees in the presence of
* unsynchronized concurrent modification. Fail-fast operations
- * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
- * exception for its correctness: <i><tt>ConcurrentModificationException</tt>
+ * exception for its correctness: <i>{@code ConcurrentModificationException}
* should be used only to detect bugs.</i>
*
* @author Josh Bloch
@@ -77,7 +77,7 @@
}
/**
- * Constructs a <tt>ConcurrentModificationException</tt> with the
+ * Constructs a {@code ConcurrentModificationException} with the
* specified detail message.
*
* @param message the detail message pertaining to this exception.
@@ -85,4 +85,39 @@
public ConcurrentModificationException(String message) {
super(message);
}
+
+ /**
+ * Constructs a new exception with the specified cause and a detail
+ * message of {@code (cause==null ? null : cause.toString())} (which
+ * typically contains the class and detail message of {@code cause}.
+ *
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link Throwable#getCause()} method). (A {@code null} value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.7
+ */
+ public ConcurrentModificationException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause.
+ *
+ * <p>Note that the detail message associated with <code>cause</code> is
+ * <i>not</i> automatically incorporated in this exception's detail
+ * message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link Throwable#getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link Throwable#getCause()} method). (A {@code null} value
+ * is permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.7
+ */
+ public ConcurrentModificationException(String message, Throwable cause) {
+ super(message, cause);
+ }
}
--- a/jdk/src/share/classes/java/util/Properties.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/Properties.java Thu Sep 16 11:19:43 2010 -0700
@@ -912,9 +912,13 @@
*
* <p>The specified stream remains open after this method returns.
*
- * @param os the output stream on which to emit the XML document.
- * @param comment a description of the property list, or <code>null</code>
- * if no comment is desired.
+ * @param os the output stream on which to emit the XML document.
+ * @param comment a description of the property list, or <code>null</code>
+ * if no comment is desired.
+ * @param encoding the name of a supported
+ * <a href="../lang/package-summary.html#charenc">
+ * character encoding</a>
+ *
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
* @throws NullPointerException if <code>os</code> is <code>null</code>,
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java Thu Sep 16 11:19:43 2010 -0700
@@ -40,16 +40,23 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.locks.Condition;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.RunnableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
/**
* An {@link ExecutorService} for running {@link ForkJoinTask}s.
* A {@code ForkJoinPool} provides the entry point for submissions
- * from non-{@code ForkJoinTask}s, as well as management and
+ * from non-{@code ForkJoinTask} clients, as well as management and
* monitoring operations.
*
* <p>A {@code ForkJoinPool} differs from other kinds of {@link
@@ -58,29 +65,19 @@
* execute subtasks created by other active tasks (eventually blocking
* waiting for work if none exist). This enables efficient processing
* when most tasks spawn other subtasks (as do most {@code
- * ForkJoinTask}s). A {@code ForkJoinPool} may also be used for mixed
- * execution of some plain {@code Runnable}- or {@code Callable}-
- * based activities along with {@code ForkJoinTask}s. When setting
- * {@linkplain #setAsyncMode async mode}, a {@code ForkJoinPool} may
- * also be appropriate for use with fine-grained tasks of any form
- * that are never joined. Otherwise, other {@code ExecutorService}
- * implementations are typically more appropriate choices.
+ * ForkJoinTask}s). When setting <em>asyncMode</em> to true in
+ * constructors, {@code ForkJoinPool}s may also be appropriate for use
+ * with event-style tasks that are never joined.
*
* <p>A {@code ForkJoinPool} is constructed with a given target
* parallelism level; by default, equal to the number of available
- * processors. Unless configured otherwise via {@link
- * #setMaintainsParallelism}, the pool attempts to maintain this
- * number of active (or available) threads by dynamically adding,
- * suspending, or resuming internal worker threads, even if some tasks
- * are stalled waiting to join others. However, no such adjustments
- * are performed in the face of blocked IO or other unmanaged
- * synchronization. The nested {@link ManagedBlocker} interface
- * enables extension of the kinds of synchronization accommodated.
- * The target parallelism level may also be changed dynamically
- * ({@link #setParallelism}). The total number of threads may be
- * limited using method {@link #setMaximumPoolSize}, in which case it
- * may become possible for the activities of a pool to stall due to
- * the lack of available threads to process new tasks.
+ * processors. The pool attempts to maintain enough active (or
+ * available) threads by dynamically adding, suspending, or resuming
+ * internal worker threads, even if some tasks are stalled waiting to
+ * join others. However, no such adjustments are guaranteed in the
+ * face of blocked IO or other unmanaged synchronization. The nested
+ * {@link ManagedBlocker} interface enables extension of the kinds of
+ * synchronization accommodated.
*
* <p>In addition to execution and lifecycle control methods, this
* class provides status check methods (for example
@@ -89,6 +86,40 @@
* {@link #toString} returns indications of pool state in a
* convenient form for informal monitoring.
*
+ * <p> As is the case with other ExecutorServices, there are three
+ * main task execution methods summarized in the following
+ * table. These are designed to be used by clients not already engaged
+ * in fork/join computations in the current pool. The main forms of
+ * these methods accept instances of {@code ForkJoinTask}, but
+ * overloaded forms also allow mixed execution of plain {@code
+ * Runnable}- or {@code Callable}- based activities as well. However,
+ * tasks that are already executing in a pool should normally
+ * <em>NOT</em> use these pool execution methods, but instead use the
+ * within-computation forms listed in the table.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <tr>
+ * <td></td>
+ * <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
+ * <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ * </tr>
+ * <tr>
+ * <td> <b>Arrange async execution</td>
+ * <td> {@link #execute(ForkJoinTask)}</td>
+ * <td> {@link ForkJoinTask#fork}</td>
+ * </tr>
+ * <tr>
+ * <td> <b>Await and obtain result</td>
+ * <td> {@link #invoke(ForkJoinTask)}</td>
+ * <td> {@link ForkJoinTask#invoke}</td>
+ * </tr>
+ * <tr>
+ * <td> <b>Arrange exec and obtain Future</td>
+ * <td> {@link #submit(ForkJoinTask)}</td>
+ * <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
+ * </tr>
+ * </table>
+ *
* <p><b>Sample Usage.</b> Normally a single {@code ForkJoinPool} is
* used for all parallel task execution in a program or subsystem.
* Otherwise, use would not usually outweigh the construction and
@@ -113,7 +144,8 @@
* {@code IllegalArgumentException}.
*
* <p>This implementation rejects submitted tasks (that is, by throwing
- * {@link RejectedExecutionException}) only when the pool is shut down.
+ * {@link RejectedExecutionException}) only when the pool is shut down
+ * or internal resources have been exhausted.
*
* @since 1.7
* @author Doug Lea
@@ -121,16 +153,247 @@
public class ForkJoinPool extends AbstractExecutorService {
/*
- * See the extended comments interspersed below for design,
- * rationale, and walkthroughs.
+ * Implementation Overview
+ *
+ * This class provides the central bookkeeping and control for a
+ * set of worker threads: Submissions from non-FJ threads enter
+ * into a submission queue. Workers take these tasks and typically
+ * split them into subtasks that may be stolen by other workers.
+ * The main work-stealing mechanics implemented in class
+ * ForkJoinWorkerThread give first priority to processing tasks
+ * from their own queues (LIFO or FIFO, depending on mode), then
+ * to randomized FIFO steals of tasks in other worker queues, and
+ * lastly to new submissions. These mechanics do not consider
+ * affinities, loads, cache localities, etc, so rarely provide the
+ * best possible performance on a given machine, but portably
+ * provide good throughput by averaging over these factors.
+ * (Further, even if we did try to use such information, we do not
+ * usually have a basis for exploiting it. For example, some sets
+ * of tasks profit from cache affinities, but others are harmed by
+ * cache pollution effects.)
+ *
+ * Beyond work-stealing support and essential bookkeeping, the
+ * main responsibility of this framework is to take actions when
+ * one worker is waiting to join a task stolen (or always held by)
+ * another. Because we are multiplexing many tasks on to a pool
+ * of workers, we can't just let them block (as in Thread.join).
+ * We also cannot just reassign the joiner's run-time stack with
+ * another and replace it later, which would be a form of
+ * "continuation", that even if possible is not necessarily a good
+ * idea. Given that the creation costs of most threads on most
+ * systems mainly surrounds setting up runtime stacks, thread
+ * creation and switching is usually not much more expensive than
+ * stack creation and switching, and is more flexible). Instead we
+ * combine two tactics:
+ *
+ * Helping: Arranging for the joiner to execute some task that it
+ * would be running if the steal had not occurred. Method
+ * ForkJoinWorkerThread.helpJoinTask tracks joining->stealing
+ * links to try to find such a task.
+ *
+ * Compensating: Unless there are already enough live threads,
+ * method helpMaintainParallelism() may create or
+ * re-activate a spare thread to compensate for blocked
+ * joiners until they unblock.
+ *
+ * It is impossible to keep exactly the target (parallelism)
+ * number of threads running at any given time. Determining
+ * existence of conservatively safe helping targets, the
+ * availability of already-created spares, and the apparent need
+ * to create new spares are all racy and require heuristic
+ * guidance, so we rely on multiple retries of each. Compensation
+ * occurs in slow-motion. It is triggered only upon timeouts of
+ * Object.wait used for joins. This reduces poor decisions that
+ * would otherwise be made when threads are waiting for others
+ * that are stalled because of unrelated activities such as
+ * garbage collection.
+ *
+ * The ManagedBlocker extension API can't use helping so relies
+ * only on compensation in method awaitBlocker.
+ *
+ * The main throughput advantages of work-stealing stem from
+ * decentralized control -- workers mostly steal tasks from each
+ * other. We do not want to negate this by creating bottlenecks
+ * implementing other management responsibilities. So we use a
+ * collection of techniques that avoid, reduce, or cope well with
+ * contention. These entail several instances of bit-packing into
+ * CASable fields to maintain only the minimally required
+ * atomicity. To enable such packing, we restrict maximum
+ * parallelism to (1<<15)-1 (enabling twice this (to accommodate
+ * unbalanced increments and decrements) to fit into a 16 bit
+ * field, which is far in excess of normal operating range. Even
+ * though updates to some of these bookkeeping fields do sometimes
+ * contend with each other, they don't normally cache-contend with
+ * updates to others enough to warrant memory padding or
+ * isolation. So they are all held as fields of ForkJoinPool
+ * objects. The main capabilities are as follows:
+ *
+ * 1. Creating and removing workers. Workers are recorded in the
+ * "workers" array. This is an array as opposed to some other data
+ * structure to support index-based random steals by workers.
+ * Updates to the array recording new workers and unrecording
+ * terminated ones are protected from each other by a lock
+ * (workerLock) but the array is otherwise concurrently readable,
+ * and accessed directly by workers. To simplify index-based
+ * operations, the array size is always a power of two, and all
+ * readers must tolerate null slots. Currently, all worker thread
+ * creation is on-demand, triggered by task submissions,
+ * replacement of terminated workers, and/or compensation for
+ * blocked workers. However, all other support code is set up to
+ * work with other policies.
+ *
+ * To ensure that we do not hold on to worker references that
+ * would prevent GC, ALL accesses to workers are via indices into
+ * the workers array (which is one source of some of the unusual
+ * code constructions here). In essence, the workers array serves
+ * as a WeakReference mechanism. Thus for example the event queue
+ * stores worker indices, not worker references. Access to the
+ * workers in associated methods (for example releaseEventWaiters)
+ * must both index-check and null-check the IDs. All such accesses
+ * ignore bad IDs by returning out early from what they are doing,
+ * since this can only be associated with shutdown, in which case
+ * it is OK to give up. On termination, we just clobber these
+ * data structures without trying to use them.
+ *
+ * 2. Bookkeeping for dynamically adding and removing workers. We
+ * aim to approximately maintain the given level of parallelism.
+ * When some workers are known to be blocked (on joins or via
+ * ManagedBlocker), we may create or resume others to take their
+ * place until they unblock (see below). Implementing this
+ * requires counts of the number of "running" threads (i.e., those
+ * that are neither blocked nor artificially suspended) as well as
+ * the total number. These two values are packed into one field,
+ * "workerCounts" because we need accurate snapshots when deciding
+ * to create, resume or suspend. Note however that the
+ * correspondence of these counts to reality is not guaranteed. In
+ * particular updates for unblocked threads may lag until they
+ * actually wake up.
+ *
+ * 3. Maintaining global run state. The run state of the pool
+ * consists of a runLevel (SHUTDOWN, TERMINATING, etc) similar to
+ * those in other Executor implementations, as well as a count of
+ * "active" workers -- those that are, or soon will be, or
+ * recently were executing tasks. The runLevel and active count
+ * are packed together in order to correctly trigger shutdown and
+ * termination. Without care, active counts can be subject to very
+ * high contention. We substantially reduce this contention by
+ * relaxing update rules. A worker must claim active status
+ * prospectively, by activating if it sees that a submitted or
+ * stealable task exists (it may find after activating that the
+ * task no longer exists). It stays active while processing this
+ * task (if it exists) and any other local subtasks it produces,
+ * until it cannot find any other tasks. It then tries
+ * inactivating (see method preStep), but upon update contention
+ * instead scans for more tasks, later retrying inactivation if it
+ * doesn't find any.
+ *
+ * 4. Managing idle workers waiting for tasks. We cannot let
+ * workers spin indefinitely scanning for tasks when none are
+ * available. On the other hand, we must quickly prod them into
+ * action when new tasks are submitted or generated. We
+ * park/unpark these idle workers using an event-count scheme.
+ * Field eventCount is incremented upon events that may enable
+ * workers that previously could not find a task to now find one:
+ * Submission of a new task to the pool, or another worker pushing
+ * a task onto a previously empty queue. (We also use this
+ * mechanism for configuration and termination actions that
+ * require wakeups of idle workers). Each worker maintains its
+ * last known event count, and blocks when a scan for work did not
+ * find a task AND its lastEventCount matches the current
+ * eventCount. Waiting idle workers are recorded in a variant of
+ * Treiber stack headed by field eventWaiters which, when nonzero,
+ * encodes the thread index and count awaited for by the worker
+ * thread most recently calling eventSync. This thread in turn has
+ * a record (field nextEventWaiter) for the next waiting worker.
+ * In addition to allowing simpler decisions about need for
+ * wakeup, the event count bits in eventWaiters serve the role of
+ * tags to avoid ABA errors in Treiber stacks. Upon any wakeup,
+ * released threads also try to release at most two others. The
+ * net effect is a tree-like diffusion of signals, where released
+ * threads (and possibly others) help with unparks. To further
+ * reduce contention effects a bit, failed CASes to increment
+ * field eventCount are tolerated without retries in signalWork.
+ * Conceptually they are merged into the same event, which is OK
+ * when their only purpose is to enable workers to scan for work.
+ *
+ * 5. Managing suspension of extra workers. When a worker notices
+ * (usually upon timeout of a wait()) that there are too few
+ * running threads, we may create a new thread to maintain
+ * parallelism level, or at least avoid starvation. Usually, extra
+ * threads are needed for only very short periods, yet join
+ * dependencies are such that we sometimes need them in
+ * bursts. Rather than create new threads each time this happens,
+ * we suspend no-longer-needed extra ones as "spares". For most
+ * purposes, we don't distinguish "extra" spare threads from
+ * normal "core" threads: On each call to preStep (the only point
+ * at which we can do this) a worker checks to see if there are
+ * now too many running workers, and if so, suspends itself.
+ * Method helpMaintainParallelism looks for suspended threads to
+ * resume before considering creating a new replacement. The
+ * spares themselves are encoded on another variant of a Treiber
+ * Stack, headed at field "spareWaiters". Note that the use of
+ * spares is intrinsically racy. One thread may become a spare at
+ * about the same time as another is needlessly being created. We
+ * counteract this and related slop in part by requiring resumed
+ * spares to immediately recheck (in preStep) to see whether they
+ * should re-suspend.
+ *
+ * 6. Killing off unneeded workers. A timeout mechanism is used to
+ * shed unused workers: The oldest (first) event queue waiter uses
+ * a timed rather than hard wait. When this wait times out without
+ * a normal wakeup, it tries to shutdown any one (for convenience
+ * the newest) other spare or event waiter via
+ * tryShutdownUnusedWorker. This eventually reduces the number of
+ * worker threads to a minimum of one after a long enough period
+ * without use.
+ *
+ * 7. Deciding when to create new workers. The main dynamic
+ * control in this class is deciding when to create extra threads
+ * in method helpMaintainParallelism. We would like to keep
+ * exactly #parallelism threads running, which is an impossible
+ * task. We always need to create one when the number of running
+ * threads would become zero and all workers are busy. Beyond
+ * this, we must rely on heuristics that work well in the
+ * presence of transient phenomena such as GC stalls, dynamic
+ * compilation, and wake-up lags. These transients are extremely
+ * common -- we are normally trying to fully saturate the CPUs on
+ * a machine, so almost any activity other than running tasks
+ * impedes accuracy. Our main defense is to allow parallelism to
+ * lapse for a while during joins, and use a timeout to see if,
+ * after the resulting settling, there is still a need for
+ * additional workers. This also better copes with the fact that
+ * some of the methods in this class tend to never become compiled
+ * (but are interpreted), so some components of the entire set of
+ * controls might execute 100 times faster than others. And
+ * similarly for cases where the apparent lack of work is just due
+ * to GC stalls and other transient system activity.
+ *
+ * Beware that there is a lot of representation-level coupling
+ * among classes ForkJoinPool, ForkJoinWorkerThread, and
+ * ForkJoinTask. For example, direct access to "workers" array by
+ * workers, and direct access to ForkJoinTask.status by both
+ * ForkJoinPool and ForkJoinWorkerThread. There is little point
+ * trying to reduce this, since any associated future changes in
+ * representations will need to be accompanied by algorithmic
+ * changes anyway.
+ *
+ * Style notes: There are lots of inline assignments (of form
+ * "while ((local = field) != 0)") which are usually the simplest
+ * way to ensure the required read orderings (which are sometimes
+ * critical). Also several occurrences of the unusual "do {}
+ * while (!cas...)" which is the simplest way to force an update of
+ * a CAS'ed variable. There are also other coding oddities that
+ * help some methods perform reasonably even when interpreted (not
+ * compiled), at the expense of some messy constructions that
+ * reduce byte code counts.
+ *
+ * The order of declarations in this file is: (1) statics (2)
+ * fields (along with constants used when unpacking some of them)
+ * (3) internal control methods (4) callbacks and other support
+ * for ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
+ * methods (plus a few little helpers).
*/
- /** Mask for packing and unpacking shorts */
- private static final int shortMask = 0xffff;
-
- /** Max pool size -- must be a power of two minus 1 */
- private static final int MAX_THREADS = 0x7FFF;
-
/**
* Factory for creating new {@link ForkJoinWorkerThread}s.
* A {@code ForkJoinWorkerThreadFactory} must be defined and used
@@ -151,14 +414,10 @@
* Default ForkJoinWorkerThreadFactory implementation; creates a
* new ForkJoinWorkerThread.
*/
- static class DefaultForkJoinWorkerThreadFactory
+ static class DefaultForkJoinWorkerThreadFactory
implements ForkJoinWorkerThreadFactory {
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
- try {
- return new ForkJoinWorkerThread(pool);
- } catch (OutOfMemoryError oom) {
- return null;
- }
+ return new ForkJoinWorkerThread(pool);
}
}
@@ -194,47 +453,44 @@
new AtomicInteger();
/**
- * Array holding all worker threads in the pool. Initialized upon
- * first use. Array size must be a power of two. Updates and
- * replacements are protected by workerLock, but it is always kept
- * in a consistent enough state to be randomly accessed without
- * locking by workers performing work-stealing.
+ * The time to block in a join (see awaitJoin) before checking if
+ * a new worker should be (re)started to maintain parallelism
+ * level. The value should be short enough to maintain global
+ * responsiveness and progress but long enough to avoid
+ * counterproductive firings during GC stalls or unrelated system
+ * activity, and to not bog down systems with continual re-firings
+ * on GCs or legitimately long waits.
*/
- volatile ForkJoinWorkerThread[] workers;
-
- /**
- * Lock protecting access to workers.
- */
- private final ReentrantLock workerLock;
-
- /**
- * Condition for awaitTermination.
- */
- private final Condition termination;
+ private static final long JOIN_TIMEOUT_MILLIS = 250L; // 4 per second
/**
- * The uncaught exception handler used when any worker
- * abruptly terminates
+ * The wakeup interval (in nanoseconds) for the oldest worker
+ * waiting for an event to invoke tryShutdownUnusedWorker to
+ * shrink the number of workers. The exact value does not matter
+ * too much. It must be short enough to release resources during
+ * sustained periods of idleness, but not so short that threads
+ * are continually re-created.
*/
- private Thread.UncaughtExceptionHandler ueh;
-
- /**
- * Creation factory for worker threads.
- */
- private final ForkJoinWorkerThreadFactory factory;
+ private static final long SHRINK_RATE_NANOS =
+ 30L * 1000L * 1000L * 1000L; // 2 per minute
/**
- * Head of stack of threads that were created to maintain
- * parallelism when other threads blocked, but have since
- * suspended when the parallelism level rose.
+ * Absolute bound for parallelism level. Twice this number plus
+ * one (i.e., 0xfff) must fit into a 16bit field to enable
+ * word-packing for some counts and indices.
*/
- private volatile WaitQueueNode spareStack;
+ private static final int MAX_WORKERS = 0x7fff;
/**
- * Sum of per-thread steal counts, updated only when threads are
- * idle or terminating.
+ * Array holding all worker threads in the pool. Array size must
+ * be a power of two. Updates and replacements are protected by
+ * workerLock, but the array is always kept in a consistent enough
+ * state to be randomly accessed without locking by workers
+ * performing work-stealing, as well as other traversal-based
+ * methods in this class. All readers must tolerate that some
+ * array slots may be null.
*/
- private final AtomicLong stealCount;
+ volatile ForkJoinWorkerThread[] workers;
/**
* Queue for external submissions.
@@ -242,160 +498,732 @@
private final LinkedTransferQueue<ForkJoinTask<?>> submissionQueue;
/**
- * Head of Treiber stack for barrier sync. See below for explanation.
+ * Lock protecting updates to workers array.
+ */
+ private final ReentrantLock workerLock;
+
+ /**
+ * Latch released upon termination.
+ */
+ private final Phaser termination;
+
+ /**
+ * Creation factory for worker threads.
+ */
+ private final ForkJoinWorkerThreadFactory factory;
+
+ /**
+ * Sum of per-thread steal counts, updated only when threads are
+ * idle or terminating.
*/
- private volatile WaitQueueNode syncStack;
+ private volatile long stealCount;
+
+ /**
+ * Encoded record of top of Treiber stack of threads waiting for
+ * events. The top 32 bits contain the count being waited for. The
+ * bottom 16 bits contains one plus the pool index of waiting
+ * worker thread. (Bits 16-31 are unused.)
+ */
+ private volatile long eventWaiters;
+
+ private static final int EVENT_COUNT_SHIFT = 32;
+ private static final long WAITER_ID_MASK = (1L << 16) - 1L;
+
+ /**
+ * A counter for events that may wake up worker threads:
+ * - Submission of a new task to the pool
+ * - A worker pushing a task on an empty queue
+ * - termination
+ */
+ private volatile int eventCount;
+
+ /**
+ * Encoded record of top of Treiber stack of spare threads waiting
+ * for resumption. The top 16 bits contain an arbitrary count to
+ * avoid ABA effects. The bottom 16bits contains one plus the pool
+ * index of waiting worker thread.
+ */
+ private volatile int spareWaiters;
+
+ private static final int SPARE_COUNT_SHIFT = 16;
+ private static final int SPARE_ID_MASK = (1 << 16) - 1;
/**
- * The count for event barrier
+ * Lifecycle control. The low word contains the number of workers
+ * that are (probably) executing tasks. This value is atomically
+ * incremented before a worker gets a task to run, and decremented
+ * when a worker has no tasks and cannot find any. Bits 16-18
+ * contain runLevel value. When all are zero, the pool is
+ * running. Level transitions are monotonic (running -> shutdown
+ * -> terminating -> terminated) so each transition adds a bit.
+ * These are bundled together to ensure consistent read for
+ * termination checks (i.e., that runLevel is at least SHUTDOWN
+ * and active threads is zero).
+ *
+ * Notes: Most direct CASes are dependent on these bitfield
+ * positions. Also, this field is non-private to enable direct
+ * performance-sensitive CASes in ForkJoinWorkerThread.
*/
- private volatile long eventCount;
+ volatile int runState;
+
+ // Note: The order among run level values matters.
+ private static final int RUNLEVEL_SHIFT = 16;
+ private static final int SHUTDOWN = 1 << RUNLEVEL_SHIFT;
+ private static final int TERMINATING = 1 << (RUNLEVEL_SHIFT + 1);
+ private static final int TERMINATED = 1 << (RUNLEVEL_SHIFT + 2);
+ private static final int ACTIVE_COUNT_MASK = (1 << RUNLEVEL_SHIFT) - 1;
+
+ /**
+ * Holds number of total (i.e., created and not yet terminated)
+ * and running (i.e., not blocked on joins or other managed sync)
+ * threads, packed together to ensure consistent snapshot when
+ * making decisions about creating and suspending spare
+ * threads. Updated only by CAS. Note that adding a new worker
+ * requires incrementing both counts, since workers start off in
+ * running state.
+ */
+ private volatile int workerCounts;
+
+ private static final int TOTAL_COUNT_SHIFT = 16;
+ private static final int RUNNING_COUNT_MASK = (1 << TOTAL_COUNT_SHIFT) - 1;
+ private static final int ONE_RUNNING = 1;
+ private static final int ONE_TOTAL = 1 << TOTAL_COUNT_SHIFT;
+
+ /**
+ * The target parallelism level.
+ * Accessed directly by ForkJoinWorkerThreads.
+ */
+ final int parallelism;
+
+ /**
+ * True if use local fifo, not default lifo, for local polling
+ * Read by, and replicated by ForkJoinWorkerThreads
+ */
+ final boolean locallyFifo;
+
+ /**
+ * The uncaught exception handler used when any worker abruptly
+ * terminates.
+ */
+ private final Thread.UncaughtExceptionHandler ueh;
/**
* Pool number, just for assigning useful names to worker threads
*/
private final int poolNumber;
- /**
- * The maximum allowed pool size
- */
- private volatile int maxPoolSize;
-
- /**
- * The desired parallelism level, updated only under workerLock.
- */
- private volatile int parallelism;
-
- /**
- * True if use local fifo, not default lifo, for local polling
- */
- private volatile boolean locallyFifo;
+ // Utilities for CASing fields. Note that most of these
+ // are usually manually inlined by callers
/**
- * Holds number of total (i.e., created and not yet terminated)
- * and running (i.e., not blocked on joins or other managed sync)
- * threads, packed into one int to ensure consistent snapshot when
- * making decisions about creating and suspending spare
- * threads. Updated only by CAS. Note: CASes in
- * updateRunningCount and preJoin assume that running active count
- * is in low word, so need to be modified if this changes.
+ * Increments running count part of workerCounts
*/
- private volatile int workerCounts;
-
- private static int totalCountOf(int s) { return s >>> 16; }
- private static int runningCountOf(int s) { return s & shortMask; }
- private static int workerCountsFor(int t, int r) { return (t << 16) + r; }
-
- /**
- * Adds delta (which may be negative) to running count. This must
- * be called before (with negative arg) and after (with positive)
- * any managed synchronization (i.e., mainly, joins).
- *
- * @param delta the number to add
- */
- final void updateRunningCount(int delta) {
- int s;
- do {} while (!casWorkerCounts(s = workerCounts, s + delta));
+ final void incrementRunningCount() {
+ int c;
+ do {} while (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ c = workerCounts,
+ c + ONE_RUNNING));
}
/**
- * Adds delta (which may be negative) to both total and running
- * count. This must be called upon creation and termination of
- * worker threads.
- *
- * @param delta the number to add
+ * Tries to decrement running count unless already zero
*/
- private void updateWorkerCount(int delta) {
- int d = delta + (delta << 16); // add to both lo and hi parts
- int s;
- do {} while (!casWorkerCounts(s = workerCounts, s + d));
+ final boolean tryDecrementRunningCount() {
+ int wc = workerCounts;
+ if ((wc & RUNNING_COUNT_MASK) == 0)
+ return false;
+ return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ wc, wc - ONE_RUNNING);
}
/**
- * Lifecycle control. High word contains runState, low word
- * contains the number of workers that are (probably) executing
- * tasks. This value is atomically incremented before a worker
- * gets a task to run, and decremented when worker has no tasks
- * and cannot find any. These two fields are bundled together to
- * support correct termination triggering. Note: activeCount
- * CAS'es cheat by assuming active count is in low word, so need
- * to be modified if this changes
+ * Forces decrement of encoded workerCounts, awaiting nonzero if
+ * (rarely) necessary when other count updates lag.
+ *
+ * @param dr -- either zero or ONE_RUNNING
+ * @param dt -- either zero or ONE_TOTAL
*/
- private volatile int runControl;
-
- // RunState values. Order among values matters
- private static final int RUNNING = 0;
- private static final int SHUTDOWN = 1;
- private static final int TERMINATING = 2;
- private static final int TERMINATED = 3;
-
- private static int runStateOf(int c) { return c >>> 16; }
- private static int activeCountOf(int c) { return c & shortMask; }
- private static int runControlFor(int r, int a) { return (r << 16) + a; }
-
- /**
- * Tries incrementing active count; fails on contention.
- * Called by workers before/during executing tasks.
- *
- * @return true on success
- */
- final boolean tryIncrementActiveCount() {
- int c = runControl;
- return casRunControl(c, c+1);
+ private void decrementWorkerCounts(int dr, int dt) {
+ for (;;) {
+ int wc = workerCounts;
+ if ((wc & RUNNING_COUNT_MASK) - dr < 0 ||
+ (wc >>> TOTAL_COUNT_SHIFT) - dt < 0) {
+ if ((runState & TERMINATED) != 0)
+ return; // lagging termination on a backout
+ Thread.yield();
+ }
+ if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ wc, wc - (dr + dt)))
+ return;
+ }
}
/**
* Tries decrementing active count; fails on contention.
- * Possibly triggers termination on success.
- * Called by workers when they can't find tasks.
- *
- * @return true on success
+ * Called when workers cannot find tasks to run.
*/
final boolean tryDecrementActiveCount() {
- int c = runControl;
- int nextc = c - 1;
- if (!casRunControl(c, nextc))
+ int c;
+ return UNSAFE.compareAndSwapInt(this, runStateOffset,
+ c = runState, c - 1);
+ }
+
+ /**
+ * Advances to at least the given level. Returns true if not
+ * already in at least the given level.
+ */
+ private boolean advanceRunLevel(int level) {
+ for (;;) {
+ int s = runState;
+ if ((s & level) != 0)
+ return false;
+ if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, s | level))
+ return true;
+ }
+ }
+
+ // workers array maintenance
+
+ /**
+ * Records and returns a workers array index for new worker.
+ */
+ private int recordWorker(ForkJoinWorkerThread w) {
+ // Try using slot totalCount-1. If not available, scan and/or resize
+ int k = (workerCounts >>> TOTAL_COUNT_SHIFT) - 1;
+ final ReentrantLock lock = this.workerLock;
+ lock.lock();
+ try {
+ ForkJoinWorkerThread[] ws = workers;
+ int n = ws.length;
+ if (k < 0 || k >= n || ws[k] != null) {
+ for (k = 0; k < n && ws[k] != null; ++k)
+ ;
+ if (k == n)
+ ws = Arrays.copyOf(ws, n << 1);
+ }
+ ws[k] = w;
+ workers = ws; // volatile array write ensures slot visibility
+ } finally {
+ lock.unlock();
+ }
+ return k;
+ }
+
+ /**
+ * Nulls out record of worker in workers array.
+ */
+ private void forgetWorker(ForkJoinWorkerThread w) {
+ int idx = w.poolIndex;
+ // Locking helps method recordWorker avoid unnecessary expansion
+ final ReentrantLock lock = this.workerLock;
+ lock.lock();
+ try {
+ ForkJoinWorkerThread[] ws = workers;
+ if (idx >= 0 && idx < ws.length && ws[idx] == w) // verify
+ ws[idx] = null;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Final callback from terminating worker. Removes record of
+ * worker from array, and adjusts counts. If pool is shutting
+ * down, tries to complete termination.
+ *
+ * @param w the worker
+ */
+ final void workerTerminated(ForkJoinWorkerThread w) {
+ forgetWorker(w);
+ decrementWorkerCounts(w.isTrimmed()? 0 : ONE_RUNNING, ONE_TOTAL);
+ while (w.stealCount != 0) // collect final count
+ tryAccumulateStealCount(w);
+ tryTerminate(false);
+ }
+
+ // Waiting for and signalling events
+
+ /**
+ * Releases workers blocked on a count not equal to current count.
+ * Normally called after precheck that eventWaiters isn't zero to
+ * avoid wasted array checks. Gives up upon a change in count or
+ * upon releasing two workers, letting others take over.
+ */
+ private void releaseEventWaiters() {
+ ForkJoinWorkerThread[] ws = workers;
+ int n = ws.length;
+ long h = eventWaiters;
+ int ec = eventCount;
+ boolean releasedOne = false;
+ ForkJoinWorkerThread w; int id;
+ while ((id = ((int)(h & WAITER_ID_MASK)) - 1) >= 0 &&
+ (int)(h >>> EVENT_COUNT_SHIFT) != ec &&
+ id < n && (w = ws[id]) != null) {
+ if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
+ h, w.nextWaiter)) {
+ LockSupport.unpark(w);
+ if (releasedOne) // exit on second release
+ break;
+ releasedOne = true;
+ }
+ if (eventCount != ec)
+ break;
+ h = eventWaiters;
+ }
+ }
+
+ /**
+ * Tries to advance eventCount and releases waiters. Called only
+ * from workers.
+ */
+ final void signalWork() {
+ int c; // try to increment event count -- CAS failure OK
+ UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
+ if (eventWaiters != 0L)
+ releaseEventWaiters();
+ }
+
+ /**
+ * Adds the given worker to event queue and blocks until
+ * terminating or event count advances from the given value
+ *
+ * @param w the calling worker thread
+ * @param ec the count
+ */
+ private void eventSync(ForkJoinWorkerThread w, int ec) {
+ long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1));
+ long h;
+ while ((runState < SHUTDOWN || !tryTerminate(false)) &&
+ (((int)((h = eventWaiters) & WAITER_ID_MASK)) == 0 ||
+ (int)(h >>> EVENT_COUNT_SHIFT) == ec) &&
+ eventCount == ec) {
+ if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
+ w.nextWaiter = h, nh)) {
+ awaitEvent(w, ec);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Blocks the given worker (that has already been entered as an
+ * event waiter) until terminating or event count advances from
+ * the given value. The oldest (first) waiter uses a timed wait to
+ * occasionally one-by-one shrink the number of workers (to a
+ * minimum of one) if the pool has not been used for extended
+ * periods.
+ *
+ * @param w the calling worker thread
+ * @param ec the count
+ */
+ private void awaitEvent(ForkJoinWorkerThread w, int ec) {
+ while (eventCount == ec) {
+ if (tryAccumulateStealCount(w)) { // transfer while idle
+ boolean untimed = (w.nextWaiter != 0L ||
+ (workerCounts & RUNNING_COUNT_MASK) <= 1);
+ long startTime = untimed? 0 : System.nanoTime();
+ Thread.interrupted(); // clear/ignore interrupt
+ if (eventCount != ec || w.runState != 0 ||
+ runState >= TERMINATING) // recheck after clear
+ break;
+ if (untimed)
+ LockSupport.park(w);
+ else {
+ LockSupport.parkNanos(w, SHRINK_RATE_NANOS);
+ if (eventCount != ec || w.runState != 0 ||
+ runState >= TERMINATING)
+ break;
+ if (System.nanoTime() - startTime >= SHRINK_RATE_NANOS)
+ tryShutdownUnusedWorker(ec);
+ }
+ }
+ }
+ }
+
+ // Maintaining parallelism
+
+ /**
+ * Pushes worker onto the spare stack.
+ */
+ final void pushSpare(ForkJoinWorkerThread w) {
+ int ns = (++w.spareCount << SPARE_COUNT_SHIFT) | (w.poolIndex + 1);
+ do {} while (!UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
+ w.nextSpare = spareWaiters,ns));
+ }
+
+ /**
+ * Tries (once) to resume a spare if the number of running
+ * threads is less than target.
+ */
+ private void tryResumeSpare() {
+ int sw, id;
+ ForkJoinWorkerThread[] ws = workers;
+ int n = ws.length;
+ ForkJoinWorkerThread w;
+ if ((sw = spareWaiters) != 0 &&
+ (id = (sw & SPARE_ID_MASK) - 1) >= 0 &&
+ id < n && (w = ws[id]) != null &&
+ (workerCounts & RUNNING_COUNT_MASK) < parallelism &&
+ spareWaiters == sw &&
+ UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
+ sw, w.nextSpare)) {
+ int c; // increment running count before resume
+ do {} while (!UNSAFE.compareAndSwapInt
+ (this, workerCountsOffset,
+ c = workerCounts, c + ONE_RUNNING));
+ if (w.tryUnsuspend())
+ LockSupport.unpark(w);
+ else // back out if w was shutdown
+ decrementWorkerCounts(ONE_RUNNING, 0);
+ }
+ }
+
+ /**
+ * Tries to increase the number of running workers if below target
+ * parallelism: If a spare exists tries to resume it via
+ * tryResumeSpare. Otherwise, if not enough total workers or all
+ * existing workers are busy, adds a new worker. In all cases also
+ * helps wake up releasable workers waiting for work.
+ */
+ private void helpMaintainParallelism() {
+ int pc = parallelism;
+ int wc, rs, tc;
+ while (((wc = workerCounts) & RUNNING_COUNT_MASK) < pc &&
+ (rs = runState) < TERMINATING) {
+ if (spareWaiters != 0)
+ tryResumeSpare();
+ else if ((tc = wc >>> TOTAL_COUNT_SHIFT) >= MAX_WORKERS ||
+ (tc >= pc && (rs & ACTIVE_COUNT_MASK) != tc))
+ break; // enough total
+ else if (runState == rs && workerCounts == wc &&
+ UNSAFE.compareAndSwapInt(this, workerCountsOffset, wc,
+ wc + (ONE_RUNNING|ONE_TOTAL))) {
+ ForkJoinWorkerThread w = null;
+ try {
+ w = factory.newThread(this);
+ } finally { // adjust on null or exceptional factory return
+ if (w == null) {
+ decrementWorkerCounts(ONE_RUNNING, ONE_TOTAL);
+ tryTerminate(false); // handle failure during shutdown
+ }
+ }
+ if (w == null)
+ break;
+ w.start(recordWorker(w), ueh);
+ if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc) {
+ int c; // advance event count
+ UNSAFE.compareAndSwapInt(this, eventCountOffset,
+ c = eventCount, c+1);
+ break; // add at most one unless total below target
+ }
+ }
+ }
+ if (eventWaiters != 0L)
+ releaseEventWaiters();
+ }
+
+ /**
+ * Callback from the oldest waiter in awaitEvent waking up after a
+ * period of non-use. If all workers are idle, tries (once) to
+ * shutdown an event waiter or a spare, if one exists. Note that
+ * we don't need CAS or locks here because the method is called
+ * only from one thread occasionally waking (and even misfires are
+ * OK). Note that until the shutdown worker fully terminates,
+ * workerCounts will overestimate total count, which is tolerable.
+ *
+ * @param ec the event count waited on by caller (to abort
+ * attempt if count has since changed).
+ */
+ private void tryShutdownUnusedWorker(int ec) {
+ if (runState == 0 && eventCount == ec) { // only trigger if all idle
+ ForkJoinWorkerThread[] ws = workers;
+ int n = ws.length;
+ ForkJoinWorkerThread w = null;
+ boolean shutdown = false;
+ int sw;
+ long h;
+ if ((sw = spareWaiters) != 0) { // prefer killing spares
+ int id = (sw & SPARE_ID_MASK) - 1;
+ if (id >= 0 && id < n && (w = ws[id]) != null &&
+ UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
+ sw, w.nextSpare))
+ shutdown = true;
+ }
+ else if ((h = eventWaiters) != 0L) {
+ long nh;
+ int id = ((int)(h & WAITER_ID_MASK)) - 1;
+ if (id >= 0 && id < n && (w = ws[id]) != null &&
+ (nh = w.nextWaiter) != 0L && // keep at least one worker
+ UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh))
+ shutdown = true;
+ }
+ if (w != null && shutdown) {
+ w.shutdown();
+ LockSupport.unpark(w);
+ }
+ }
+ releaseEventWaiters(); // in case of interference
+ }
+
+ /**
+ * Callback from workers invoked upon each top-level action (i.e.,
+ * stealing a task or taking a submission and running it).
+ * Performs one or more of the following:
+ *
+ * 1. If the worker is active and either did not run a task
+ * or there are too many workers, try to set its active status
+ * to inactive and update activeCount. On contention, we may
+ * try again in this or a subsequent call.
+ *
+ * 2. If not enough total workers, help create some.
+ *
+ * 3. If there are too many running workers, suspend this worker
+ * (first forcing inactive if necessary). If it is not needed,
+ * it may be shutdown while suspended (via
+ * tryShutdownUnusedWorker). Otherwise, upon resume it
+ * rechecks running thread count and need for event sync.
+ *
+ * 4. If worker did not run a task, await the next task event via
+ * eventSync if necessary (first forcing inactivation), upon
+ * which the worker may be shutdown via
+ * tryShutdownUnusedWorker. Otherwise, help release any
+ * existing event waiters that are now releasable,
+ *
+ * @param w the worker
+ * @param ran true if worker ran a task since last call to this method
+ */
+ final void preStep(ForkJoinWorkerThread w, boolean ran) {
+ int wec = w.lastEventCount;
+ boolean active = w.active;
+ boolean inactivate = false;
+ int pc = parallelism;
+ int rs;
+ while (w.runState == 0 && (rs = runState) < TERMINATING) {
+ if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) &&
+ UNSAFE.compareAndSwapInt(this, runStateOffset, rs, rs - 1))
+ inactivate = active = w.active = false;
+ int wc = workerCounts;
+ if ((wc & RUNNING_COUNT_MASK) > pc) {
+ if (!(inactivate |= active) && // must inactivate to suspend
+ workerCounts == wc && // try to suspend as spare
+ UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ wc, wc - ONE_RUNNING))
+ w.suspendAsSpare();
+ }
+ else if ((wc >>> TOTAL_COUNT_SHIFT) < pc)
+ helpMaintainParallelism(); // not enough workers
+ else if (!ran) {
+ long h = eventWaiters;
+ int ec = eventCount;
+ if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec)
+ releaseEventWaiters(); // release others before waiting
+ else if (ec != wec) {
+ w.lastEventCount = ec; // no need to wait
+ break;
+ }
+ else if (!(inactivate |= active))
+ eventSync(w, wec); // must inactivate before sync
+ }
+ else
+ break;
+ }
+ }
+
+ /**
+ * Helps and/or blocks awaiting join of the given task.
+ * See above for explanation.
+ *
+ * @param joinMe the task to join
+ * @param worker the current worker thread
+ */
+ final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker) {
+ int retries = 2 + (parallelism >> 2); // #helpJoins before blocking
+ while (joinMe.status >= 0) {
+ int wc;
+ worker.helpJoinTask(joinMe);
+ if (joinMe.status < 0)
+ break;
+ else if (retries > 0)
+ --retries;
+ else if (((wc = workerCounts) & RUNNING_COUNT_MASK) != 0 &&
+ UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ wc, wc - ONE_RUNNING)) {
+ int stat, c; long h;
+ while ((stat = joinMe.status) >= 0 &&
+ (h = eventWaiters) != 0L && // help release others
+ (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
+ releaseEventWaiters();
+ if (stat >= 0 &&
+ ((workerCounts & RUNNING_COUNT_MASK) == 0 ||
+ (stat =
+ joinMe.internalAwaitDone(JOIN_TIMEOUT_MILLIS)) >= 0))
+ helpMaintainParallelism(); // timeout or no running workers
+ do {} while (!UNSAFE.compareAndSwapInt
+ (this, workerCountsOffset,
+ c = workerCounts, c + ONE_RUNNING));
+ if (stat < 0)
+ break; // else restart
+ }
+ }
+ }
+
+ /**
+ * Same idea as awaitJoin, but no helping, retries, or timeouts.
+ */
+ final void awaitBlocker(ManagedBlocker blocker)
+ throws InterruptedException {
+ while (!blocker.isReleasable()) {
+ int wc = workerCounts;
+ if ((wc & RUNNING_COUNT_MASK) != 0 &&
+ UNSAFE.compareAndSwapInt(this, workerCountsOffset,
+ wc, wc - ONE_RUNNING)) {
+ try {
+ while (!blocker.isReleasable()) {
+ long h = eventWaiters;
+ if (h != 0L &&
+ (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
+ releaseEventWaiters();
+ else if ((workerCounts & RUNNING_COUNT_MASK) == 0 &&
+ runState < TERMINATING)
+ helpMaintainParallelism();
+ else if (blocker.block())
+ break;
+ }
+ } finally {
+ int c;
+ do {} while (!UNSAFE.compareAndSwapInt
+ (this, workerCountsOffset,
+ c = workerCounts, c + ONE_RUNNING));
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Possibly initiates and/or completes termination.
+ *
+ * @param now if true, unconditionally terminate, else only
+ * if shutdown and empty queue and no active workers
+ * @return true if now terminating or terminated
+ */
+ private boolean tryTerminate(boolean now) {
+ if (now)
+ advanceRunLevel(SHUTDOWN); // ensure at least SHUTDOWN
+ else if (runState < SHUTDOWN ||
+ !submissionQueue.isEmpty() ||
+ (runState & ACTIVE_COUNT_MASK) != 0)
return false;
- if (canTerminateOnShutdown(nextc))
- terminateOnShutdown();
+
+ if (advanceRunLevel(TERMINATING))
+ startTerminating();
+
+ // Finish now if all threads terminated; else in some subsequent call
+ if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) {
+ advanceRunLevel(TERMINATED);
+ termination.arrive();
+ }
return true;
}
/**
- * Returns {@code true} if argument represents zero active count
- * and nonzero runstate, which is the triggering condition for
- * terminating on shutdown.
+ * Actions on transition to TERMINATING
+ *
+ * Runs up to four passes through workers: (0) shutting down each
+ * (without waking up if parked) to quickly spread notifications
+ * without unnecessary bouncing around event queues etc (1) wake
+ * up and help cancel tasks (2) interrupt (3) mop up races with
+ * interrupted workers
*/
- private static boolean canTerminateOnShutdown(int c) {
- // i.e. least bit is nonzero runState bit
- return ((c & -c) >>> 16) != 0;
- }
-
- /**
- * Transition run state to at least the given state. Return true
- * if not already at least given state.
- */
- private boolean transitionRunStateTo(int state) {
- for (;;) {
- int c = runControl;
- if (runStateOf(c) >= state)
- return false;
- if (casRunControl(c, runControlFor(state, activeCountOf(c))))
- return true;
+ private void startTerminating() {
+ cancelSubmissions();
+ for (int passes = 0; passes < 4 && workerCounts != 0; ++passes) {
+ int c; // advance event count
+ UNSAFE.compareAndSwapInt(this, eventCountOffset,
+ c = eventCount, c+1);
+ eventWaiters = 0L; // clobber lists
+ spareWaiters = 0;
+ for (ForkJoinWorkerThread w : workers) {
+ if (w != null) {
+ w.shutdown();
+ if (passes > 0 && !w.isTerminated()) {
+ w.cancelTasks();
+ LockSupport.unpark(w);
+ if (passes > 1) {
+ try {
+ w.interrupt();
+ } catch (SecurityException ignore) {
+ }
+ }
+ }
+ }
+ }
}
}
/**
- * Controls whether to add spares to maintain parallelism
+ * Clears out and cancels submissions, ignoring exceptions.
+ */
+ private void cancelSubmissions() {
+ ForkJoinTask<?> task;
+ while ((task = submissionQueue.poll()) != null) {
+ try {
+ task.cancel(false);
+ } catch (Throwable ignore) {
+ }
+ }
+ }
+
+ // misc support for ForkJoinWorkerThread
+
+ /**
+ * Returns pool number.
+ */
+ final int getPoolNumber() {
+ return poolNumber;
+ }
+
+ /**
+ * Tries to accumulate steal count from a worker, clearing
+ * the worker's value if successful.
+ *
+ * @return true if worker steal count now zero
*/
- private volatile boolean maintainsParallelism;
+ final boolean tryAccumulateStealCount(ForkJoinWorkerThread w) {
+ int sc = w.stealCount;
+ long c = stealCount;
+ // CAS even if zero, for fence effects
+ if (UNSAFE.compareAndSwapLong(this, stealCountOffset, c, c + sc)) {
+ if (sc != 0)
+ w.stealCount = 0;
+ return true;
+ }
+ return sc == 0;
+ }
+
+ /**
+ * Returns the approximate (non-atomic) number of idle threads per
+ * active thread.
+ */
+ final int idlePerActive() {
+ int pc = parallelism; // use parallelism, not rc
+ int ac = runState; // no mask -- artificially boosts during shutdown
+ // Use exact results for small values, saturate past 4
+ return ((pc <= ac) ? 0 :
+ (pc >>> 1 <= ac) ? 1 :
+ (pc >>> 2 <= ac) ? 3 :
+ pc >>> 3);
+ }
+
+ // Public and protected methods
// Constructors
/**
* Creates a {@code ForkJoinPool} with parallelism equal to {@link
- * java.lang.Runtime#availableProcessors}, and using the {@linkplain
- * #defaultForkJoinWorkerThreadFactory default thread factory}.
+ * java.lang.Runtime#availableProcessors}, using the {@linkplain
+ * #defaultForkJoinWorkerThreadFactory default thread factory},
+ * no UncaughtExceptionHandler, and non-async LIFO processing mode.
*
* @throws SecurityException if a security manager exists and
* the caller is not permitted to modify threads
@@ -404,13 +1232,14 @@
*/
public ForkJoinPool() {
this(Runtime.getRuntime().availableProcessors(),
- defaultForkJoinWorkerThreadFactory);
+ defaultForkJoinWorkerThreadFactory, null, false);
}
/**
* Creates a {@code ForkJoinPool} with the indicated parallelism
- * level and using the {@linkplain
- * #defaultForkJoinWorkerThreadFactory default thread factory}.
+ * level, the {@linkplain
+ * #defaultForkJoinWorkerThreadFactory default thread factory},
+ * no UncaughtExceptionHandler, and non-async LIFO processing mode.
*
* @param parallelism the parallelism level
* @throws IllegalArgumentException if parallelism less than or
@@ -421,31 +1250,25 @@
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
public ForkJoinPool(int parallelism) {
- this(parallelism, defaultForkJoinWorkerThreadFactory);
+ this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}
/**
- * Creates a {@code ForkJoinPool} with parallelism equal to {@link
- * java.lang.Runtime#availableProcessors}, and using the given
- * thread factory.
+ * Creates a {@code ForkJoinPool} with the given parameters.
*
- * @param factory the factory for creating new threads
- * @throws NullPointerException if the factory is null
- * @throws SecurityException if a security manager exists and
- * the caller is not permitted to modify threads
- * because it does not hold {@link
- * java.lang.RuntimePermission}{@code ("modifyThread")}
- */
- public ForkJoinPool(ForkJoinWorkerThreadFactory factory) {
- this(Runtime.getRuntime().availableProcessors(), factory);
- }
-
- /**
- * Creates a {@code ForkJoinPool} with the given parallelism and
- * thread factory.
- *
- * @param parallelism the parallelism level
- * @param factory the factory for creating new threads
+ * @param parallelism the parallelism level. For default value,
+ * use {@link java.lang.Runtime#availableProcessors}.
+ * @param factory the factory for creating new threads. For default value,
+ * use {@link #defaultForkJoinWorkerThreadFactory}.
+ * @param handler the handler for internal worker threads that
+ * terminate due to unrecoverable errors encountered while executing
+ * tasks. For default value, use {@code null}.
+ * @param asyncMode if true,
+ * establishes local first-in-first-out scheduling mode for forked
+ * tasks that are never joined. This mode may be more appropriate
+ * than default locally stack-based mode in applications in which
+ * worker threads only process event-style asynchronous tasks.
+ * For default value, use {@code false}.
* @throws IllegalArgumentException if parallelism less than or
* equal to zero, or greater than implementation limit
* @throws NullPointerException if the factory is null
@@ -454,153 +1277,40 @@
* because it does not hold {@link
* java.lang.RuntimePermission}{@code ("modifyThread")}
*/
- public ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory) {
- if (parallelism <= 0 || parallelism > MAX_THREADS)
- throw new IllegalArgumentException();
+ public ForkJoinPool(int parallelism,
+ ForkJoinWorkerThreadFactory factory,
+ Thread.UncaughtExceptionHandler handler,
+ boolean asyncMode) {
+ checkPermission();
if (factory == null)
throw new NullPointerException();
- checkPermission();
- this.factory = factory;
+ if (parallelism <= 0 || parallelism > MAX_WORKERS)
+ throw new IllegalArgumentException();
this.parallelism = parallelism;
- this.maxPoolSize = MAX_THREADS;
- this.maintainsParallelism = true;
- this.poolNumber = poolNumberGenerator.incrementAndGet();
- this.workerLock = new ReentrantLock();
- this.termination = workerLock.newCondition();
- this.stealCount = new AtomicLong();
+ this.factory = factory;
+ this.ueh = handler;
+ this.locallyFifo = asyncMode;
+ int arraySize = initialArraySizeFor(parallelism);
+ this.workers = new ForkJoinWorkerThread[arraySize];
this.submissionQueue = new LinkedTransferQueue<ForkJoinTask<?>>();
- // worker array and workers are lazily constructed
- }
-
- /**
- * Creates a new worker thread using factory.
- *
- * @param index the index to assign worker
- * @return new worker, or null if factory failed
- */
- private ForkJoinWorkerThread createWorker(int index) {
- Thread.UncaughtExceptionHandler h = ueh;
- ForkJoinWorkerThread w = factory.newThread(this);
- if (w != null) {
- w.poolIndex = index;
- w.setDaemon(true);
- w.setAsyncMode(locallyFifo);
- w.setName("ForkJoinPool-" + poolNumber + "-worker-" + index);
- if (h != null)
- w.setUncaughtExceptionHandler(h);
- }
- return w;
- }
-
- /**
- * Returns a good size for worker array given pool size.
- * Currently requires size to be a power of two.
- */
- private static int arraySizeFor(int poolSize) {
- if (poolSize <= 1)
- return 1;
- // See Hackers Delight, sec 3.2
- int c = poolSize >= MAX_THREADS ? MAX_THREADS : (poolSize - 1);
- c |= c >>> 1;
- c |= c >>> 2;
- c |= c >>> 4;
- c |= c >>> 8;
- c |= c >>> 16;
- return c + 1;
- }
-
- /**
- * Creates or resizes array if necessary to hold newLength.
- * Call only under exclusion.
- *
- * @return the array
- */
- private ForkJoinWorkerThread[] ensureWorkerArrayCapacity(int newLength) {
- ForkJoinWorkerThread[] ws = workers;
- if (ws == null)
- return workers = new ForkJoinWorkerThread[arraySizeFor(newLength)];
- else if (newLength > ws.length)
- return workers = Arrays.copyOf(ws, arraySizeFor(newLength));
- else
- return ws;
+ this.workerLock = new ReentrantLock();
+ this.termination = new Phaser(1);
+ this.poolNumber = poolNumberGenerator.incrementAndGet();
}
/**
- * Tries to shrink workers into smaller array after one or more terminate.
- */
- private void tryShrinkWorkerArray() {
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- int len = ws.length;
- int last = len - 1;
- while (last >= 0 && ws[last] == null)
- --last;
- int newLength = arraySizeFor(last+1);
- if (newLength < len)
- workers = Arrays.copyOf(ws, newLength);
- }
- }
-
- /**
- * Initializes workers if necessary.
+ * Returns initial power of two size for workers array.
+ * @param pc the initial parallelism level
*/
- final void ensureWorkerInitialization() {
- ForkJoinWorkerThread[] ws = workers;
- if (ws == null) {
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ws = workers;
- if (ws == null) {
- int ps = parallelism;
- ws = ensureWorkerArrayCapacity(ps);
- for (int i = 0; i < ps; ++i) {
- ForkJoinWorkerThread w = createWorker(i);
- if (w != null) {
- ws[i] = w;
- w.start();
- updateWorkerCount(1);
- }
- }
- }
- } finally {
- lock.unlock();
- }
- }
- }
-
- /**
- * Worker creation and startup for threads added via setParallelism.
- */
- private void createAndStartAddedWorkers() {
- resumeAllSpares(); // Allow spares to convert to nonspare
- int ps = parallelism;
- ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(ps);
- int len = ws.length;
- // Sweep through slots, to keep lowest indices most populated
- int k = 0;
- while (k < len) {
- if (ws[k] != null) {
- ++k;
- continue;
- }
- int s = workerCounts;
- int tc = totalCountOf(s);
- int rc = runningCountOf(s);
- if (rc >= ps || tc >= ps)
- break;
- if (casWorkerCounts (s, workerCountsFor(tc+1, rc+1))) {
- ForkJoinWorkerThread w = createWorker(k);
- if (w != null) {
- ws[k++] = w;
- w.start();
- }
- else {
- updateWorkerCount(-1); // back out on failed creation
- break;
- }
- }
- }
+ private static int initialArraySizeFor(int pc) {
+ // If possible, initially allocate enough space for one spare
+ int size = pc < MAX_WORKERS ? pc + 1 : MAX_WORKERS;
+ // See Hackers Delight, sec 3.2. We know MAX_WORKERS < (1 >>> 16)
+ size |= size >>> 1;
+ size |= size >>> 2;
+ size |= size >>> 4;
+ size |= size >>> 8;
+ return size + 1;
}
// Execution methods
@@ -611,12 +1321,12 @@
private <T> void doSubmit(ForkJoinTask<T> task) {
if (task == null)
throw new NullPointerException();
- if (isShutdown())
+ if (runState >= SHUTDOWN)
throw new RejectedExecutionException();
- if (workers == null)
- ensureWorkerInitialization();
submissionQueue.offer(task);
- signalIdleWorkers();
+ int c; // try to increment event count -- CAS failure OK
+ UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
+ helpMaintainParallelism(); // create, start, or resume some workers
}
/**
@@ -662,6 +1372,20 @@
}
/**
+ * Submits a ForkJoinTask for execution.
+ *
+ * @param task the task to submit
+ * @return the task
+ * @throws NullPointerException if the task is null
+ * @throws RejectedExecutionException if the task cannot be
+ * scheduled for execution
+ */
+ public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
+ doSubmit(task);
+ return task;
+ }
+
+ /**
* @throws NullPointerException if the task is null
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
@@ -699,21 +1423,6 @@
}
/**
- * Submits a ForkJoinTask for execution.
- *
- * @param task the task to submit
- * @return the task
- * @throws NullPointerException if the task is null
- * @throws RejectedExecutionException if the task cannot be
- * scheduled for execution
- */
- public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
- doSubmit(task);
- return task;
- }
-
-
- /**
* @throws NullPointerException {@inheritDoc}
* @throws RejectedExecutionException {@inheritDoc}
*/
@@ -725,7 +1434,7 @@
invoke(new InvokeAll<T>(forkJoinTasks));
@SuppressWarnings({"unchecked", "rawtypes"})
- List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks;
+ List<Future<T>> futures = (List<Future<T>>) (List) forkJoinTasks;
return futures;
}
@@ -739,8 +1448,6 @@
private static final long serialVersionUID = -7914297376763021607L;
}
- // Configuration and status settings and queries
-
/**
* Returns the factory used for constructing new workers.
*
@@ -757,84 +1464,7 @@
* @return the handler, or {@code null} if none
*/
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() {
- Thread.UncaughtExceptionHandler h;
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- h = ueh;
- } finally {
- lock.unlock();
- }
- return h;
- }
-
- /**
- * Sets the handler for internal worker threads that terminate due
- * to unrecoverable errors encountered while executing tasks.
- * Unless set, the current default or ThreadGroup handler is used
- * as handler.
- *
- * @param h the new handler
- * @return the old handler, or {@code null} if none
- * @throws SecurityException if a security manager exists and
- * the caller is not permitted to modify threads
- * because it does not hold {@link
- * java.lang.RuntimePermission}{@code ("modifyThread")}
- */
- public Thread.UncaughtExceptionHandler
- setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler h) {
- checkPermission();
- Thread.UncaughtExceptionHandler old = null;
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- old = ueh;
- ueh = h;
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread w = ws[i];
- if (w != null)
- w.setUncaughtExceptionHandler(h);
- }
- }
- } finally {
- lock.unlock();
- }
- return old;
- }
-
-
- /**
- * Sets the target parallelism level of this pool.
- *
- * @param parallelism the target parallelism
- * @throws IllegalArgumentException if parallelism less than or
- * equal to zero or greater than maximum size bounds
- * @throws SecurityException if a security manager exists and
- * the caller is not permitted to modify threads
- * because it does not hold {@link
- * java.lang.RuntimePermission}{@code ("modifyThread")}
- */
- public void setParallelism(int parallelism) {
- checkPermission();
- if (parallelism <= 0 || parallelism > maxPoolSize)
- throw new IllegalArgumentException();
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- if (isProcessingTasks()) {
- int p = this.parallelism;
- this.parallelism = parallelism;
- if (parallelism > p)
- createAndStartAddedWorkers();
- else
- trimSpares();
- }
- } finally {
- lock.unlock();
- }
- signalIdleWorkers();
+ return ueh;
}
/**
@@ -848,92 +1478,14 @@
/**
* Returns the number of worker threads that have started but not
- * yet terminated. This result returned by this method may differ
+ * yet terminated. The result returned by this method may differ
* from {@link #getParallelism} when threads are created to
* maintain parallelism when others are cooperatively blocked.
*
* @return the number of worker threads
*/
public int getPoolSize() {
- return totalCountOf(workerCounts);
- }
-
- /**
- * Returns the maximum number of threads allowed to exist in the
- * pool. Unless set using {@link #setMaximumPoolSize}, the
- * maximum is an implementation-defined value designed only to
- * prevent runaway growth.
- *
- * @return the maximum
- */
- public int getMaximumPoolSize() {
- return maxPoolSize;
- }
-
- /**
- * Sets the maximum number of threads allowed to exist in the
- * pool. The given value should normally be greater than or equal
- * to the {@link #getParallelism parallelism} level. Setting this
- * value has no effect on current pool size. It controls
- * construction of new threads.
- *
- * @throws IllegalArgumentException if negative or greater than
- * internal implementation limit
- */
- public void setMaximumPoolSize(int newMax) {
- if (newMax < 0 || newMax > MAX_THREADS)
- throw new IllegalArgumentException();
- maxPoolSize = newMax;
- }
-
-
- /**
- * Returns {@code true} if this pool dynamically maintains its
- * target parallelism level. If false, new threads are added only
- * to avoid possible starvation. This setting is by default true.
- *
- * @return {@code true} if maintains parallelism
- */
- public boolean getMaintainsParallelism() {
- return maintainsParallelism;
- }
-
- /**
- * Sets whether this pool dynamically maintains its target
- * parallelism level. If false, new threads are added only to
- * avoid possible starvation.
- *
- * @param enable {@code true} to maintain parallelism
- */
- public void setMaintainsParallelism(boolean enable) {
- maintainsParallelism = enable;
- }
-
- /**
- * Establishes local first-in-first-out scheduling mode for forked
- * tasks that are never joined. This mode may be more appropriate
- * than default locally stack-based mode in applications in which
- * worker threads only process asynchronous tasks. This method is
- * designed to be invoked only when the pool is quiescent, and
- * typically only before any tasks are submitted. The effects of
- * invocations at other times may be unpredictable.
- *
- * @param async if {@code true}, use locally FIFO scheduling
- * @return the previous mode
- * @see #getAsyncMode
- */
- public boolean setAsyncMode(boolean async) {
- boolean oldMode = locallyFifo;
- locallyFifo = async;
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread t = ws[i];
- if (t != null)
- t.setAsyncMode(async);
- }
- }
- return oldMode;
+ return workerCounts >>> TOTAL_COUNT_SHIFT;
}
/**
@@ -941,7 +1493,6 @@
* scheduling mode for forked tasks that are never joined.
*
* @return {@code true} if this pool uses async mode
- * @see #setAsyncMode
*/
public boolean getAsyncMode() {
return locallyFifo;
@@ -950,12 +1501,13 @@
/**
* Returns an estimate of the number of worker threads that are
* not blocked waiting to join tasks or for other managed
- * synchronization.
+ * synchronization. This method may overestimate the
+ * number of running threads.
*
* @return the number of worker threads
*/
public int getRunningThreadCount() {
- return runningCountOf(workerCounts);
+ return workerCounts & RUNNING_COUNT_MASK;
}
/**
@@ -966,19 +1518,7 @@
* @return the number of active threads
*/
public int getActiveThreadCount() {
- return activeCountOf(runControl);
- }
-
- /**
- * Returns an estimate of the number of threads that are currently
- * idle waiting for tasks. This method may underestimate the
- * number of idle threads.
- *
- * @return the number of idle threads
- */
- final int getIdleThreadCount() {
- int c = runningCountOf(workerCounts) - activeCountOf(runControl);
- return (c <= 0) ? 0 : c;
+ return runState & ACTIVE_COUNT_MASK;
}
/**
@@ -993,7 +1533,7 @@
* @return {@code true} if all threads are currently idle
*/
public boolean isQuiescent() {
- return activeCountOf(runControl) == 0;
+ return (runState & ACTIVE_COUNT_MASK) == 0;
}
/**
@@ -1008,17 +1548,7 @@
* @return the number of steals
*/
public long getStealCount() {
- return stealCount.get();
- }
-
- /**
- * Accumulates steal count from a worker.
- * Call only when worker known to be idle.
- */
- private void updateStealCount(ForkJoinWorkerThread w) {
- int sc = w.getAndClearStealCount();
- if (sc != 0)
- stealCount.addAndGet(sc);
+ return stealCount;
}
/**
@@ -1033,14 +1563,9 @@
*/
public long getQueuedTaskCount() {
long count = 0;
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread t = ws[i];
- if (t != null)
- count += t.getQueueSize();
- }
- }
+ for (ForkJoinWorkerThread w : workers)
+ if (w != null)
+ count += w.getQueueSize();
return count;
}
@@ -1094,16 +1619,11 @@
* @return the number of elements transferred
*/
protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
- int n = submissionQueue.drainTo(c);
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread w = ws[i];
- if (w != null)
- n += w.drainTasksTo(c);
- }
- }
- return n;
+ int count = submissionQueue.drainTo(c);
+ for (ForkJoinWorkerThread w : workers)
+ if (w != null)
+ count += w.drainTasksTo(c);
+ return count;
}
/**
@@ -1114,36 +1634,34 @@
* @return a string identifying this pool, as well as its state
*/
public String toString() {
- int ps = parallelism;
- int wc = workerCounts;
- int rc = runControl;
long st = getStealCount();
long qt = getQueuedTaskCount();
long qs = getQueuedSubmissionCount();
+ int wc = workerCounts;
+ int tc = wc >>> TOTAL_COUNT_SHIFT;
+ int rc = wc & RUNNING_COUNT_MASK;
+ int pc = parallelism;
+ int rs = runState;
+ int ac = rs & ACTIVE_COUNT_MASK;
return super.toString() +
- "[" + runStateToString(runStateOf(rc)) +
- ", parallelism = " + ps +
- ", size = " + totalCountOf(wc) +
- ", active = " + activeCountOf(rc) +
- ", running = " + runningCountOf(wc) +
+ "[" + runLevelToString(rs) +
+ ", parallelism = " + pc +
+ ", size = " + tc +
+ ", active = " + ac +
+ ", running = " + rc +
", steals = " + st +
", tasks = " + qt +
", submissions = " + qs +
"]";
}
- private static String runStateToString(int rs) {
- switch(rs) {
- case RUNNING: return "Running";
- case SHUTDOWN: return "Shutting down";
- case TERMINATING: return "Terminating";
- case TERMINATED: return "Terminated";
- default: throw new Error("Unknown run state");
- }
+ private static String runLevelToString(int s) {
+ return ((s & TERMINATED) != 0 ? "Terminated" :
+ ((s & TERMINATING) != 0 ? "Terminating" :
+ ((s & SHUTDOWN) != 0 ? "Shutting down" :
+ "Running")));
}
- // lifecycle control
-
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
@@ -1158,23 +1676,8 @@
*/
public void shutdown() {
checkPermission();
- transitionRunStateTo(SHUTDOWN);
- if (canTerminateOnShutdown(runControl)) {
- if (workers == null) { // shutting down before workers created
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- if (workers == null) {
- terminate();
- transitionRunStateTo(TERMINATED);
- termination.signalAll();
- }
- } finally {
- lock.unlock();
- }
- }
- terminateOnShutdown();
- }
+ advanceRunLevel(SHUTDOWN);
+ tryTerminate(false);
}
/**
@@ -1195,7 +1698,7 @@
*/
public List<Runnable> shutdownNow() {
checkPermission();
- terminate();
+ tryTerminate(true);
return Collections.emptyList();
}
@@ -1205,7 +1708,7 @@
* @return {@code true} if all tasks have completed following shut down
*/
public boolean isTerminated() {
- return runStateOf(runControl) == TERMINATED;
+ return runState >= TERMINATED;
}
/**
@@ -1219,7 +1722,7 @@
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
- return runStateOf(runControl) == TERMINATING;
+ return (runState & (TERMINATING|TERMINATED)) == TERMINATING;
}
/**
@@ -1228,15 +1731,7 @@
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
- return runStateOf(runControl) >= SHUTDOWN;
- }
-
- /**
- * Returns true if pool is not terminating or terminated.
- * Used internally to suppress execution when terminating.
- */
- final boolean isProcessingTasks() {
- return runStateOf(runControl) < TERMINATING;
+ return runState >= SHUTDOWN;
}
/**
@@ -1252,585 +1747,10 @@
*/
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.workerLock;
- lock.lock();
try {
- for (;;) {
- if (isTerminated())
- return true;
- if (nanos <= 0)
- return false;
- nanos = termination.awaitNanos(nanos);
- }
- } finally {
- lock.unlock();
- }
- }
-
- // Shutdown and termination support
-
- /**
- * Callback from terminating worker. Nulls out the corresponding
- * workers slot, and if terminating, tries to terminate; else
- * tries to shrink workers array.
- *
- * @param w the worker
- */
- final void workerTerminated(ForkJoinWorkerThread w) {
- updateStealCount(w);
- updateWorkerCount(-1);
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- int idx = w.poolIndex;
- if (idx >= 0 && idx < ws.length && ws[idx] == w)
- ws[idx] = null;
- if (totalCountOf(workerCounts) == 0) {
- terminate(); // no-op if already terminating
- transitionRunStateTo(TERMINATED);
- termination.signalAll();
- }
- else if (isProcessingTasks()) {
- tryShrinkWorkerArray();
- tryResumeSpare(true); // allow replacement
- }
- }
- } finally {
- lock.unlock();
- }
- signalIdleWorkers();
- }
-
- /**
- * Initiates termination.
- */
- private void terminate() {
- if (transitionRunStateTo(TERMINATING)) {
- stopAllWorkers();
- resumeAllSpares();
- signalIdleWorkers();
- cancelQueuedSubmissions();
- cancelQueuedWorkerTasks();
- interruptUnterminatedWorkers();
- signalIdleWorkers(); // resignal after interrupt
- }
- }
-
- /**
- * Possibly terminates when on shutdown state.
- */
- private void terminateOnShutdown() {
- if (!hasQueuedSubmissions() && canTerminateOnShutdown(runControl))
- terminate();
- }
-
- /**
- * Clears out and cancels submissions.
- */
- private void cancelQueuedSubmissions() {
- ForkJoinTask<?> task;
- while ((task = pollSubmission()) != null)
- task.cancel(false);
- }
-
- /**
- * Cleans out worker queues.
- */
- private void cancelQueuedWorkerTasks() {
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread t = ws[i];
- if (t != null)
- t.cancelTasks();
- }
- }
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Sets each worker's status to terminating. Requires lock to avoid
- * conflicts with add/remove.
- */
- private void stopAllWorkers() {
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread t = ws[i];
- if (t != null)
- t.shutdownNow();
- }
- }
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Interrupts all unterminated workers. This is not required for
- * sake of internal control, but may help unstick user code during
- * shutdown.
- */
- private void interruptUnterminatedWorkers() {
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ForkJoinWorkerThread[] ws = workers;
- if (ws != null) {
- for (int i = 0; i < ws.length; ++i) {
- ForkJoinWorkerThread t = ws[i];
- if (t != null && !t.isTerminated()) {
- try {
- t.interrupt();
- } catch (SecurityException ignore) {
- }
- }
- }
- }
- } finally {
- lock.unlock();
- }
- }
-
-
- /*
- * Nodes for event barrier to manage idle threads. Queue nodes
- * are basic Treiber stack nodes, also used for spare stack.
- *
- * The event barrier has an event count and a wait queue (actually
- * a Treiber stack). Workers are enabled to look for work when
- * the eventCount is incremented. If they fail to find work, they
- * may wait for next count. Upon release, threads help others wake
- * up.
- *
- * Synchronization events occur only in enough contexts to
- * maintain overall liveness:
- *
- * - Submission of a new task to the pool
- * - Resizes or other changes to the workers array
- * - pool termination
- * - A worker pushing a task on an empty queue
- *
- * The case of pushing a task occurs often enough, and is heavy
- * enough compared to simple stack pushes, to require special
- * handling: Method signalWork returns without advancing count if
- * the queue appears to be empty. This would ordinarily result in
- * races causing some queued waiters not to be woken up. To avoid
- * this, the first worker enqueued in method sync (see
- * syncIsReleasable) rescans for tasks after being enqueued, and
- * helps signal if any are found. This works well because the
- * worker has nothing better to do, and so might as well help
- * alleviate the overhead and contention on the threads actually
- * doing work. Also, since event counts increments on task
- * availability exist to maintain liveness (rather than to force
- * refreshes etc), it is OK for callers to exit early if
- * contending with another signaller.
- */
- static final class WaitQueueNode {
- WaitQueueNode next; // only written before enqueued
- volatile ForkJoinWorkerThread thread; // nulled to cancel wait
- final long count; // unused for spare stack
-
- WaitQueueNode(long c, ForkJoinWorkerThread w) {
- count = c;
- thread = w;
- }
-
- /**
- * Wakes up waiter, returning false if known to already
- */
- boolean signal() {
- ForkJoinWorkerThread t = thread;
- if (t == null)
- return false;
- thread = null;
- LockSupport.unpark(t);
- return true;
- }
-
- /**
- * Awaits release on sync.
- */
- void awaitSyncRelease(ForkJoinPool p) {
- while (thread != null && !p.syncIsReleasable(this))
- LockSupport.park(this);
- }
-
- /**
- * Awaits resumption as spare.
- */
- void awaitSpareRelease() {
- while (thread != null) {
- if (!Thread.interrupted())
- LockSupport.park(this);
- }
- }
- }
-
- /**
- * Ensures that no thread is waiting for count to advance from the
- * current value of eventCount read on entry to this method, by
- * releasing waiting threads if necessary.
- *
- * @return the count
- */
- final long ensureSync() {
- long c = eventCount;
- WaitQueueNode q;
- while ((q = syncStack) != null && q.count < c) {
- if (casBarrierStack(q, null)) {
- do {
- q.signal();
- } while ((q = q.next) != null);
- break;
- }
- }
- return c;
- }
-
- /**
- * Increments event count and releases waiting threads.
- */
- private void signalIdleWorkers() {
- long c;
- do {} while (!casEventCount(c = eventCount, c+1));
- ensureSync();
- }
-
- /**
- * Signals threads waiting to poll a task. Because method sync
- * rechecks availability, it is OK to only proceed if queue
- * appears to be non-empty, and OK to skip under contention to
- * increment count (since some other thread succeeded).
- */
- final void signalWork() {
- long c;
- WaitQueueNode q;
- if (syncStack != null &&
- casEventCount(c = eventCount, c+1) &&
- (((q = syncStack) != null && q.count <= c) &&
- (!casBarrierStack(q, q.next) || !q.signal())))
- ensureSync();
- }
-
- /**
- * Waits until event count advances from last value held by
- * caller, or if excess threads, caller is resumed as spare, or
- * caller or pool is terminating. Updates caller's event on exit.
- *
- * @param w the calling worker thread
- */
- final void sync(ForkJoinWorkerThread w) {
- updateStealCount(w); // Transfer w's count while it is idle
-
- while (!w.isShutdown() && isProcessingTasks() && !suspendIfSpare(w)) {
- long prev = w.lastEventCount;
- WaitQueueNode node = null;
- WaitQueueNode h;
- while (eventCount == prev &&
- ((h = syncStack) == null || h.count == prev)) {
- if (node == null)
- node = new WaitQueueNode(prev, w);
- if (casBarrierStack(node.next = h, node)) {
- node.awaitSyncRelease(this);
- break;
- }
- }
- long ec = ensureSync();
- if (ec != prev) {
- w.lastEventCount = ec;
- break;
- }
- }
- }
-
- /**
- * Returns {@code true} if worker waiting on sync can proceed:
- * - on signal (thread == null)
- * - on event count advance (winning race to notify vs signaller)
- * - on interrupt
- * - if the first queued node, we find work available
- * If node was not signalled and event count not advanced on exit,
- * then we also help advance event count.
- *
- * @return {@code true} if node can be released
- */
- final boolean syncIsReleasable(WaitQueueNode node) {
- long prev = node.count;
- if (!Thread.interrupted() && node.thread != null &&
- (node.next != null ||
- !ForkJoinWorkerThread.hasQueuedTasks(workers)) &&
- eventCount == prev)
+ return termination.awaitAdvanceInterruptibly(0, timeout, unit) > 0;
+ } catch (TimeoutException ex) {
return false;
- if (node.thread != null) {
- node.thread = null;
- long ec = eventCount;
- if (prev <= ec) // help signal
- casEventCount(ec, ec+1);
- }
- return true;
- }
-
- /**
- * Returns {@code true} if a new sync event occurred since last
- * call to sync or this method, if so, updating caller's count.
- */
- final boolean hasNewSyncEvent(ForkJoinWorkerThread w) {
- long lc = w.lastEventCount;
- long ec = ensureSync();
- if (ec == lc)
- return false;
- w.lastEventCount = ec;
- return true;
- }
-
- // Parallelism maintenance
-
- /**
- * Decrements running count; if too low, adds spare.
- *
- * Conceptually, all we need to do here is add or resume a
- * spare thread when one is about to block (and remove or
- * suspend it later when unblocked -- see suspendIfSpare).
- * However, implementing this idea requires coping with
- * several problems: we have imperfect information about the
- * states of threads. Some count updates can and usually do
- * lag run state changes, despite arrangements to keep them
- * accurate (for example, when possible, updating counts
- * before signalling or resuming), especially when running on
- * dynamic JVMs that don't optimize the infrequent paths that
- * update counts. Generating too many threads can make these
- * problems become worse, because excess threads are more
- * likely to be context-switched with others, slowing them all
- * down, especially if there is no work available, so all are
- * busy scanning or idling. Also, excess spare threads can
- * only be suspended or removed when they are idle, not
- * immediately when they aren't needed. So adding threads will
- * raise parallelism level for longer than necessary. Also,
- * FJ applications often encounter highly transient peaks when
- * many threads are blocked joining, but for less time than it
- * takes to create or resume spares.
- *
- * @param joinMe if non-null, return early if done
- * @param maintainParallelism if true, try to stay within
- * target counts, else create only to avoid starvation
- * @return true if joinMe known to be done
- */
- final boolean preJoin(ForkJoinTask<?> joinMe,
- boolean maintainParallelism) {
- maintainParallelism &= maintainsParallelism; // overrride
- boolean dec = false; // true when running count decremented
- while (spareStack == null || !tryResumeSpare(dec)) {
- int counts = workerCounts;
- if (dec || (dec = casWorkerCounts(counts, --counts))) {
- if (!needSpare(counts, maintainParallelism))
- break;
- if (joinMe.status < 0)
- return true;
- if (tryAddSpare(counts))
- break;
- }
- }
- return false;
- }
-
- /**
- * Same idea as preJoin
- */
- final boolean preBlock(ManagedBlocker blocker,
- boolean maintainParallelism) {
- maintainParallelism &= maintainsParallelism;
- boolean dec = false;
- while (spareStack == null || !tryResumeSpare(dec)) {
- int counts = workerCounts;
- if (dec || (dec = casWorkerCounts(counts, --counts))) {
- if (!needSpare(counts, maintainParallelism))
- break;
- if (blocker.isReleasable())
- return true;
- if (tryAddSpare(counts))
- break;
- }
- }
- return false;
- }
-
- /**
- * Returns {@code true} if a spare thread appears to be needed.
- * If maintaining parallelism, returns true when the deficit in
- * running threads is more than the surplus of total threads, and
- * there is apparently some work to do. This self-limiting rule
- * means that the more threads that have already been added, the
- * less parallelism we will tolerate before adding another.
- *
- * @param counts current worker counts
- * @param maintainParallelism try to maintain parallelism
- */
- private boolean needSpare(int counts, boolean maintainParallelism) {
- int ps = parallelism;
- int rc = runningCountOf(counts);
- int tc = totalCountOf(counts);
- int runningDeficit = ps - rc;
- int totalSurplus = tc - ps;
- return (tc < maxPoolSize &&
- (rc == 0 || totalSurplus < 0 ||
- (maintainParallelism &&
- runningDeficit > totalSurplus &&
- ForkJoinWorkerThread.hasQueuedTasks(workers))));
- }
-
- /**
- * Adds a spare worker if lock available and no more than the
- * expected numbers of threads exist.
- *
- * @return true if successful
- */
- private boolean tryAddSpare(int expectedCounts) {
- final ReentrantLock lock = this.workerLock;
- int expectedRunning = runningCountOf(expectedCounts);
- int expectedTotal = totalCountOf(expectedCounts);
- boolean success = false;
- boolean locked = false;
- // confirm counts while locking; CAS after obtaining lock
- try {
- for (;;) {
- int s = workerCounts;
- int tc = totalCountOf(s);
- int rc = runningCountOf(s);
- if (rc > expectedRunning || tc > expectedTotal)
- break;
- if (!locked && !(locked = lock.tryLock()))
- break;
- if (casWorkerCounts(s, workerCountsFor(tc+1, rc+1))) {
- createAndStartSpare(tc);
- success = true;
- break;
- }
- }
- } finally {
- if (locked)
- lock.unlock();
- }
- return success;
- }
-
- /**
- * Adds the kth spare worker. On entry, pool counts are already
- * adjusted to reflect addition.
- */
- private void createAndStartSpare(int k) {
- ForkJoinWorkerThread w = null;
- ForkJoinWorkerThread[] ws = ensureWorkerArrayCapacity(k + 1);
- int len = ws.length;
- // Probably, we can place at slot k. If not, find empty slot
- if (k < len && ws[k] != null) {
- for (k = 0; k < len && ws[k] != null; ++k)
- ;
- }
- if (k < len && isProcessingTasks() && (w = createWorker(k)) != null) {
- ws[k] = w;
- w.start();
- }
- else
- updateWorkerCount(-1); // adjust on failure
- signalIdleWorkers();
- }
-
- /**
- * Suspends calling thread w if there are excess threads. Called
- * only from sync. Spares are enqueued in a Treiber stack using
- * the same WaitQueueNodes as barriers. They are resumed mainly
- * in preJoin, but are also woken on pool events that require all
- * threads to check run state.
- *
- * @param w the caller
- */
- private boolean suspendIfSpare(ForkJoinWorkerThread w) {
- WaitQueueNode node = null;
- int s;
- while (parallelism < runningCountOf(s = workerCounts)) {
- if (node == null)
- node = new WaitQueueNode(0, w);
- if (casWorkerCounts(s, s-1)) { // representation-dependent
- // push onto stack
- do {} while (!casSpareStack(node.next = spareStack, node));
- // block until released by resumeSpare
- node.awaitSpareRelease();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Tries to pop and resume a spare thread.
- *
- * @param updateCount if true, increment running count on success
- * @return true if successful
- */
- private boolean tryResumeSpare(boolean updateCount) {
- WaitQueueNode q;
- while ((q = spareStack) != null) {
- if (casSpareStack(q, q.next)) {
- if (updateCount)
- updateRunningCount(1);
- q.signal();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Pops and resumes all spare threads. Same idea as ensureSync.
- *
- * @return true if any spares released
- */
- private boolean resumeAllSpares() {
- WaitQueueNode q;
- while ( (q = spareStack) != null) {
- if (casSpareStack(q, null)) {
- do {
- updateRunningCount(1);
- q.signal();
- } while ((q = q.next) != null);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Pops and shuts down excessive spare threads. Call only while
- * holding lock. This is not guaranteed to eliminate all excess
- * threads, only those suspended as spares, which are the ones
- * unlikely to be needed in the future.
- */
- private void trimSpares() {
- int surplus = totalCountOf(workerCounts) - parallelism;
- WaitQueueNode q;
- while (surplus > 0 && (q = spareStack) != null) {
- if (casSpareStack(q, null)) {
- do {
- updateRunningCount(1);
- ForkJoinWorkerThread w = q.thread;
- if (w != null && surplus > 0 &&
- runningCountOf(workerCounts) > 0 && w.shutdown())
- --surplus;
- q.signal();
- } while ((q = q.next) != null);
- }
}
}
@@ -1838,11 +1758,17 @@
* Interface for extending managed parallelism for tasks running
* in {@link ForkJoinPool}s.
*
- * <p>A {@code ManagedBlocker} provides two methods.
- * Method {@code isReleasable} must return {@code true} if
- * blocking is not necessary. Method {@code block} blocks the
- * current thread if necessary (perhaps internally invoking
- * {@code isReleasable} before actually blocking).
+ * <p>A {@code ManagedBlocker} provides two methods. Method
+ * {@code isReleasable} must return {@code true} if blocking is
+ * not necessary. Method {@code block} blocks the current thread
+ * if necessary (perhaps internally invoking {@code isReleasable}
+ * before actually blocking). The unusual methods in this API
+ * accommodate synchronizers that may, but don't usually, block
+ * for long periods. Similarly, they allow more efficient internal
+ * handling of cases in which additional workers may be, but
+ * usually are not, needed to ensure sufficient parallelism.
+ * Toward this end, implementations of method {@code isReleasable}
+ * must be amenable to repeated invocation.
*
* <p>For example, here is a ManagedBlocker based on a
* ReentrantLock:
@@ -1860,6 +1786,26 @@
* return hasLock || (hasLock = lock.tryLock());
* }
* }}</pre>
+ *
+ * <p>Here is a class that possibly blocks waiting for an
+ * item on a given queue:
+ * <pre> {@code
+ * class QueueTaker<E> implements ManagedBlocker {
+ * final BlockingQueue<E> queue;
+ * volatile E item = null;
+ * QueueTaker(BlockingQueue<E> q) { this.queue = q; }
+ * public boolean block() throws InterruptedException {
+ * if (item == null)
+ * item = queue.take();
+ * return true;
+ * }
+ * public boolean isReleasable() {
+ * return item != null || (item = queue.poll()) != null;
+ * }
+ * public E getItem() { // call after pool.managedBlock completes
+ * return item;
+ * }
+ * }}</pre>
*/
public static interface ManagedBlocker {
/**
@@ -1883,14 +1829,7 @@
* Blocks in accord with the given blocker. If the current thread
* is a {@link ForkJoinWorkerThread}, this method possibly
* arranges for a spare thread to be activated if necessary to
- * ensure parallelism while the current thread is blocked.
- *
- * <p>If {@code maintainParallelism} is {@code true} and the pool
- * supports it ({@link #getMaintainsParallelism}), this method
- * attempts to maintain the pool's nominal parallelism. Otherwise
- * it activates a thread only if necessary to avoid complete
- * starvation. This option may be preferable when blockages use
- * timeouts, or are almost always brief.
+ * ensure sufficient parallelism while the current thread is blocked.
*
* <p>If the caller is not a {@link ForkJoinTask}, this method is
* behaviorally equivalent to
@@ -1904,33 +1843,18 @@
* first be expanded to ensure parallelism, and later adjusted.
*
* @param blocker the blocker
- * @param maintainParallelism if {@code true} and supported by
- * this pool, attempt to maintain the pool's nominal parallelism;
- * otherwise activate a thread only if necessary to avoid
- * complete starvation.
* @throws InterruptedException if blocker.block did so
*/
- public static void managedBlock(ManagedBlocker blocker,
- boolean maintainParallelism)
+ public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
Thread t = Thread.currentThread();
- ForkJoinPool pool = ((t instanceof ForkJoinWorkerThread) ?
- ((ForkJoinWorkerThread) t).pool : null);
- if (!blocker.isReleasable()) {
- try {
- if (pool == null ||
- !pool.preBlock(blocker, maintainParallelism))
- awaitBlocker(blocker);
- } finally {
- if (pool != null)
- pool.updateRunningCount(1);
- }
+ if (t instanceof ForkJoinWorkerThread) {
+ ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+ w.pool.awaitBlocker(blocker);
}
- }
-
- private static void awaitBlocker(ManagedBlocker blocker)
- throws InterruptedException {
- do {} while (!blocker.isReleasable() && !blocker.block());
+ else {
+ do {} while (!blocker.isReleasable() && !blocker.block());
+ }
}
// AbstractExecutorService overrides. These rely on undocumented
@@ -1948,32 +1872,18 @@
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
- private static final long eventCountOffset =
- objectFieldOffset("eventCount", ForkJoinPool.class);
private static final long workerCountsOffset =
objectFieldOffset("workerCounts", ForkJoinPool.class);
- private static final long runControlOffset =
- objectFieldOffset("runControl", ForkJoinPool.class);
- private static final long syncStackOffset =
- objectFieldOffset("syncStack",ForkJoinPool.class);
- private static final long spareStackOffset =
- objectFieldOffset("spareStack", ForkJoinPool.class);
-
- private boolean casEventCount(long cmp, long val) {
- return UNSAFE.compareAndSwapLong(this, eventCountOffset, cmp, val);
- }
- private boolean casWorkerCounts(int cmp, int val) {
- return UNSAFE.compareAndSwapInt(this, workerCountsOffset, cmp, val);
- }
- private boolean casRunControl(int cmp, int val) {
- return UNSAFE.compareAndSwapInt(this, runControlOffset, cmp, val);
- }
- private boolean casSpareStack(WaitQueueNode cmp, WaitQueueNode val) {
- return UNSAFE.compareAndSwapObject(this, spareStackOffset, cmp, val);
- }
- private boolean casBarrierStack(WaitQueueNode cmp, WaitQueueNode val) {
- return UNSAFE.compareAndSwapObject(this, syncStackOffset, cmp, val);
- }
+ private static final long runStateOffset =
+ objectFieldOffset("runState", ForkJoinPool.class);
+ private static final long eventCountOffset =
+ objectFieldOffset("eventCount", ForkJoinPool.class);
+ private static final long eventWaitersOffset =
+ objectFieldOffset("eventWaiters", ForkJoinPool.class);
+ private static final long stealCountOffset =
+ objectFieldOffset("stealCount", ForkJoinPool.class);
+ private static final long spareWaitersOffset =
+ objectFieldOffset("spareWaiters", ForkJoinPool.class);
private static long objectFieldOffset(String field, Class<?> klazz) {
try {
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java Thu Sep 16 11:19:43 2010 -0700
@@ -91,10 +91,7 @@
* results of a task is {@link #join}, but there are several variants:
* The {@link Future#get} methods support interruptible and/or timed
* waits for completion and report results using {@code Future}
- * conventions. Method {@link #helpJoin} enables callers to actively
- * execute other tasks while awaiting joins, which is sometimes more
- * efficient but only applies when all subtasks are known to be
- * strictly tree-structured. Method {@link #invoke} is semantically
+ * conventions. Method {@link #invoke} is semantically
* equivalent to {@code fork(); join()} but always attempts to begin
* execution in the current thread. The "<em>quiet</em>" forms of
* these methods do not extract results or report exceptions. These
@@ -130,7 +127,7 @@
* ForkJoinTasks (as may be determined using method {@link
* #inForkJoinPool}). Attempts to invoke them in other contexts
* result in exceptions or errors, possibly including
- * ClassCastException.
+ * {@code ClassCastException}.
*
* <p>Most base support methods are {@code final}, to prevent
* overriding of implementations that are intrinsically tied to the
@@ -152,9 +149,8 @@
*
* <p>This class provides {@code adapt} methods for {@link Runnable}
* and {@link Callable}, that may be of use when mixing execution of
- * {@code ForkJoinTasks} with other kinds of tasks. When all tasks
- * are of this form, consider using a pool in
- * {@linkplain ForkJoinPool#setAsyncMode async mode}.
+ * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
+ * of this form, consider using a pool constructed in <em>asyncMode</em>.
*
* <p>ForkJoinTasks are {@code Serializable}, which enables them to be
* used in extensions such as remote execution frameworks. It is
@@ -166,33 +162,43 @@
*/
public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
- /**
- * Run control status bits packed into a single int to minimize
- * footprint and to ensure atomicity (via CAS). Status is
- * initially zero, and takes on nonnegative values until
- * completed, upon which status holds COMPLETED. CANCELLED, or
- * EXCEPTIONAL, which use the top 3 bits. Tasks undergoing
- * blocking waits by other threads have SIGNAL_MASK bits set --
- * bit 15 for external (nonFJ) waits, and the rest a count of
- * waiting FJ threads. (This representation relies on
- * ForkJoinPool max thread limits). Completion of a stolen task
- * with SIGNAL_MASK bits set awakens waiter via notifyAll. Even
- * though suboptimal for some purposes, we use basic builtin
- * wait/notify to take advantage of "monitor inflation" in JVMs
- * that we would otherwise need to emulate to avoid adding further
- * per-task bookkeeping overhead. Note that bits 16-28 are
- * currently unused. Also value 0x80000000 is available as spare
- * completion value.
+ /*
+ * See the internal documentation of class ForkJoinPool for a
+ * general implementation overview. ForkJoinTasks are mainly
+ * responsible for maintaining their "status" field amidst relays
+ * to methods in ForkJoinWorkerThread and ForkJoinPool. The
+ * methods of this class are more-or-less layered into (1) basic
+ * status maintenance (2) execution and awaiting completion (3)
+ * user-level methods that additionally report results. This is
+ * sometimes hard to see because this file orders exported methods
+ * in a way that flows well in javadocs. In particular, most
+ * join mechanics are in method quietlyJoin, below.
*/
+
+ /*
+ * The status field holds run control status bits packed into a
+ * single int to minimize footprint and to ensure atomicity (via
+ * CAS). Status is initially zero, and takes on nonnegative
+ * values until completed, upon which status holds value
+ * NORMAL, CANCELLED, or EXCEPTIONAL. Tasks undergoing blocking
+ * waits by other threads have the SIGNAL bit set. Completion of
+ * a stolen task with SIGNAL set awakens any waiters via
+ * notifyAll. Even though suboptimal for some purposes, we use
+ * basic builtin wait/notify to take advantage of "monitor
+ * inflation" in JVMs that we would otherwise need to emulate to
+ * avoid adding further per-task bookkeeping overhead. We want
+ * these monitors to be "fat", i.e., not use biasing or thin-lock
+ * techniques, so use some odd coding idioms that tend to avoid
+ * them.
+ */
+
+ /** The run status of this task */
volatile int status; // accessed directly by pool and workers
- static final int COMPLETION_MASK = 0xe0000000;
- static final int NORMAL = 0xe0000000; // == mask
- static final int CANCELLED = 0xc0000000;
- static final int EXCEPTIONAL = 0xa0000000;
- static final int SIGNAL_MASK = 0x0000ffff;
- static final int INTERNAL_SIGNAL_MASK = 0x00007fff;
- static final int EXTERNAL_SIGNAL = 0x00008000; // top bit of low word
+ private static final int NORMAL = -1;
+ private static final int CANCELLED = -2;
+ private static final int EXCEPTIONAL = -3;
+ private static final int SIGNAL = 1;
/**
* Table of exceptions thrown by tasks, to enable reporting by
@@ -206,176 +212,94 @@
Collections.synchronizedMap
(new WeakHashMap<ForkJoinTask<?>, Throwable>());
- // within-package utilities
+ // Maintaining completion status
/**
- * Gets current worker thread, or null if not a worker thread.
- */
- static ForkJoinWorkerThread getWorker() {
- Thread t = Thread.currentThread();
- return ((t instanceof ForkJoinWorkerThread) ?
- (ForkJoinWorkerThread) t : null);
- }
-
- final boolean casStatus(int cmp, int val) {
- return UNSAFE.compareAndSwapInt(this, statusOffset, cmp, val);
- }
-
- /**
- * Workaround for not being able to rethrow unchecked exceptions.
- */
- static void rethrowException(Throwable ex) {
- if (ex != null)
- UNSAFE.throwException(ex);
- }
-
- // Setting completion status
-
- /**
- * Marks completion and wakes up threads waiting to join this task.
+ * Marks completion and wakes up threads waiting to join this task,
+ * also clearing signal request bits.
*
* @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
*/
- final void setCompletion(int completion) {
- ForkJoinPool pool = getPool();
- if (pool != null) {
- int s; // Clear signal bits while setting completion status
- do {} while ((s = status) >= 0 && !casStatus(s, completion));
-
- if ((s & SIGNAL_MASK) != 0) {
- if ((s &= INTERNAL_SIGNAL_MASK) != 0)
- pool.updateRunningCount(s);
- synchronized (this) { notifyAll(); }
- }
- }
- else
- externallySetCompletion(completion);
- }
-
- /**
- * Version of setCompletion for non-FJ threads. Leaves signal
- * bits for unblocked threads to adjust, and always notifies.
- */
- private void externallySetCompletion(int completion) {
+ private void setCompletion(int completion) {
int s;
- do {} while ((s = status) >= 0 &&
- !casStatus(s, (s & SIGNAL_MASK) | completion));
- synchronized (this) { notifyAll(); }
- }
-
- /**
- * Sets status to indicate normal completion.
- */
- final void setNormalCompletion() {
- // Try typical fast case -- single CAS, no signal, not already done.
- // Manually expand casStatus to improve chances of inlining it
- if (!UNSAFE.compareAndSwapInt(this, statusOffset, 0, NORMAL))
- setCompletion(NORMAL);
- }
-
- // internal waiting and notification
-
- /**
- * Performs the actual monitor wait for awaitDone.
- */
- private void doAwaitDone() {
- // Minimize lock bias and in/de-flation effects by maximizing
- // chances of waiting inside sync
- try {
- while (status >= 0)
- synchronized (this) { if (status >= 0) wait(); }
- } catch (InterruptedException ie) {
- onInterruptedWait();
+ while ((s = status) >= 0) {
+ if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
+ if (s != 0)
+ synchronized (this) { notifyAll(); }
+ break;
+ }
}
}
/**
- * Performs the actual timed monitor wait for awaitDone.
+ * Records exception and sets exceptional completion.
+ *
+ * @return status on exit
*/
- private void doAwaitDone(long startTime, long nanos) {
- synchronized (this) {
+ private void setExceptionalCompletion(Throwable rex) {
+ exceptionMap.put(this, rex);
+ setCompletion(EXCEPTIONAL);
+ }
+
+ /**
+ * Blocks a worker thread until completion. Called only by
+ * pool. Currently unused -- pool-based waits use timeout
+ * version below.
+ */
+ final void internalAwaitDone() {
+ int s; // the odd construction reduces lock bias effects
+ while ((s = status) >= 0) {
try {
- while (status >= 0) {
- long nt = nanos - (System.nanoTime() - startTime);
- if (nt <= 0)
- break;
- wait(nt / 1000000, (int) (nt % 1000000));
+ synchronized(this) {
+ if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
+ wait();
}
} catch (InterruptedException ie) {
- onInterruptedWait();
+ cancelIfTerminating();
}
}
}
- // Awaiting completion
-
/**
- * Sets status to indicate there is joiner, then waits for join,
- * surrounded with pool notifications.
+ * Blocks a worker thread until completed or timed out. Called
+ * only by pool.
*
- * @return status upon exit
+ * @return status on exit
*/
- private int awaitDone(ForkJoinWorkerThread w,
- boolean maintainParallelism) {
- ForkJoinPool pool = (w == null) ? null : w.pool;
+ final int internalAwaitDone(long millis) {
int s;
- while ((s = status) >= 0) {
- if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) {
- if (pool == null || !pool.preJoin(this, maintainParallelism))
- doAwaitDone();
- if (((s = status) & INTERNAL_SIGNAL_MASK) != 0)
- adjustPoolCountsOnUnblock(pool);
- break;
+ if ((s = status) >= 0) {
+ try {
+ synchronized(this) {
+ if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
+ wait(millis, 0);
+ }
+ } catch (InterruptedException ie) {
+ cancelIfTerminating();
}
+ s = status;
}
return s;
}
/**
- * Timed version of awaitDone
- *
- * @return status upon exit
+ * Blocks a non-worker-thread until completion.
*/
- private int awaitDone(ForkJoinWorkerThread w, long nanos) {
- ForkJoinPool pool = (w == null) ? null : w.pool;
+ private void externalAwaitDone() {
int s;
while ((s = status) >= 0) {
- if (casStatus(s, (pool == null) ? s|EXTERNAL_SIGNAL : s+1)) {
- long startTime = System.nanoTime();
- if (pool == null || !pool.preJoin(this, false))
- doAwaitDone(startTime, nanos);
- if ((s = status) >= 0) {
- adjustPoolCountsOnCancelledWait(pool);
- s = status;
- }
- if (s < 0 && (s & INTERNAL_SIGNAL_MASK) != 0)
- adjustPoolCountsOnUnblock(pool);
- break;
- }
- }
- return s;
- }
-
- /**
- * Notifies pool that thread is unblocked. Called by signalled
- * threads when woken by non-FJ threads (which is atypical).
- */
- private void adjustPoolCountsOnUnblock(ForkJoinPool pool) {
- int s;
- do {} while ((s = status) < 0 && !casStatus(s, s & COMPLETION_MASK));
- if (pool != null && (s &= INTERNAL_SIGNAL_MASK) != 0)
- pool.updateRunningCount(s);
- }
-
- /**
- * Notifies pool to adjust counts on cancelled or timed out wait.
- */
- private void adjustPoolCountsOnCancelledWait(ForkJoinPool pool) {
- if (pool != null) {
- int s;
- while ((s = status) >= 0 && (s & INTERNAL_SIGNAL_MASK) != 0) {
- if (casStatus(s, s - 1)) {
- pool.updateRunningCount(1);
+ synchronized(this) {
+ if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)){
+ boolean interrupted = false;
+ while (status >= 0) {
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
+ }
+ if (interrupted)
+ Thread.currentThread().interrupt();
break;
}
}
@@ -383,153 +307,19 @@
}
/**
- * Handles interruptions during waits.
- */
- private void onInterruptedWait() {
- ForkJoinWorkerThread w = getWorker();
- if (w == null)
- Thread.currentThread().interrupt(); // re-interrupt
- else if (w.isTerminating())
- cancelIgnoringExceptions();
- // else if FJworker, ignore interrupt
- }
-
- // Recording and reporting exceptions
-
- private void setDoneExceptionally(Throwable rex) {
- exceptionMap.put(this, rex);
- setCompletion(EXCEPTIONAL);
- }
-
- /**
- * Throws the exception associated with status s.
- *
- * @throws the exception
- */
- private void reportException(int s) {
- if ((s &= COMPLETION_MASK) < NORMAL) {
- if (s == CANCELLED)
- throw new CancellationException();
- else
- rethrowException(exceptionMap.get(this));
- }
- }
-
- /**
- * Returns result or throws exception using j.u.c.Future conventions.
- * Only call when {@code isDone} known to be true or thread known
- * to be interrupted.
- */
- private V reportFutureResult()
- throws InterruptedException, ExecutionException {
- if (Thread.interrupted())
- throw new InterruptedException();
- int s = status & COMPLETION_MASK;
- if (s < NORMAL) {
- Throwable ex;
- if (s == CANCELLED)
- throw new CancellationException();
- if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
- throw new ExecutionException(ex);
- }
- return getRawResult();
- }
-
- /**
- * Returns result or throws exception using j.u.c.Future conventions
- * with timeouts.
- */
- private V reportTimedFutureResult()
- throws InterruptedException, ExecutionException, TimeoutException {
- if (Thread.interrupted())
- throw new InterruptedException();
- Throwable ex;
- int s = status & COMPLETION_MASK;
- if (s == NORMAL)
- return getRawResult();
- else if (s == CANCELLED)
- throw new CancellationException();
- else if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
- throw new ExecutionException(ex);
- else
- throw new TimeoutException();
- }
-
- // internal execution methods
-
- /**
- * Calls exec, recording completion, and rethrowing exception if
- * encountered. Caller should normally check status before calling.
- *
- * @return true if completed normally
- */
- private boolean tryExec() {
- try { // try block must contain only call to exec
- if (!exec())
- return false;
- } catch (Throwable rex) {
- setDoneExceptionally(rex);
- rethrowException(rex);
- return false; // not reached
- }
- setNormalCompletion();
- return true;
- }
-
- /**
- * Main execution method used by worker threads. Invokes
- * base computation unless already complete.
+ * Unless done, calls exec and records status if completed, but
+ * doesn't wait for completion otherwise. Primary execution method
+ * for ForkJoinWorkerThread.
*/
final void quietlyExec() {
- if (status >= 0) {
- try {
- if (!exec())
- return;
- } catch (Throwable rex) {
- setDoneExceptionally(rex);
+ try {
+ if (status < 0 || !exec())
return;
- }
- setNormalCompletion();
- }
- }
-
- /**
- * Calls exec(), recording but not rethrowing exception.
- * Caller should normally check status before calling.
- *
- * @return true if completed normally
- */
- private boolean tryQuietlyInvoke() {
- try {
- if (!exec())
- return false;
} catch (Throwable rex) {
- setDoneExceptionally(rex);
- return false;
+ setExceptionalCompletion(rex);
+ return;
}
- setNormalCompletion();
- return true;
- }
-
- /**
- * Cancels, ignoring any exceptions it throws.
- */
- final void cancelIgnoringExceptions() {
- try {
- cancel(false);
- } catch (Throwable ignore) {
- }
- }
-
- /**
- * Main implementation of helpJoin
- */
- private int busyJoin(ForkJoinWorkerThread w) {
- int s;
- ForkJoinTask<?> t;
- while ((s = status) >= 0 && (t = w.scanWhileJoining(this)) != null)
- t.quietlyExec();
- return (s >= 0) ? awaitDone(w, false) : s; // block if no work
+ setCompletion(NORMAL); // must be outside try block
}
// public methods
@@ -567,34 +357,41 @@
* @return the computed result
*/
public final V join() {
- ForkJoinWorkerThread w = getWorker();
- if (w == null || status < 0 || !w.unpushTask(this) || !tryExec())
- reportException(awaitDone(w, true));
+ quietlyJoin();
+ Throwable ex;
+ if (status < NORMAL && (ex = getException()) != null)
+ UNSAFE.throwException(ex);
return getRawResult();
}
/**
* Commences performing this task, awaits its completion if
- * necessary, and return its result, or throws an (unchecked)
- * exception if the underlying computation did so.
+ * necessary, and returns its result, or throws an (unchecked)
+ * {@code RuntimeException} or {@code Error} if the underlying
+ * computation did so.
*
* @return the computed result
*/
public final V invoke() {
- if (status >= 0 && tryExec())
- return getRawResult();
- else
- return join();
+ quietlyInvoke();
+ Throwable ex;
+ if (status < NORMAL && (ex = getException()) != null)
+ UNSAFE.throwException(ex);
+ return getRawResult();
}
/**
* Forks the given tasks, returning when {@code isDone} holds for
* each task or an (unchecked) exception is encountered, in which
- * case the exception is rethrown. If either task encounters an
- * exception, the other one may be, but is not guaranteed to be,
- * cancelled. If both tasks throw an exception, then this method
- * throws one of them. The individual status of each task may be
- * checked using {@link #getException()} and related methods.
+ * case the exception is rethrown. If more than one task
+ * encounters an exception, then this method throws any one of
+ * these exceptions. If any task encounters an exception, the
+ * other may be cancelled. However, the execution status of
+ * individual tasks is not guaranteed upon exceptional return. The
+ * status of each task may be obtained using {@link
+ * #getException()} and related methods to check if they have been
+ * cancelled, completed normally or exceptionally, or left
+ * unprocessed.
*
* <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method
@@ -615,12 +412,14 @@
/**
* Forks the given tasks, returning when {@code isDone} holds for
* each task or an (unchecked) exception is encountered, in which
- * case the exception is rethrown. If any task encounters an
- * exception, others may be, but are not guaranteed to be,
- * cancelled. If more than one task encounters an exception, then
- * this method throws any one of these exceptions. The individual
- * status of each task may be checked using {@link #getException()}
- * and related methods.
+ * case the exception is rethrown. If more than one task
+ * encounters an exception, then this method throws any one of
+ * these exceptions. If any task encounters an exception, others
+ * may be cancelled. However, the execution status of individual
+ * tasks is not guaranteed upon exceptional return. The status of
+ * each task may be obtained using {@link #getException()} and
+ * related methods to check if they have been cancelled, completed
+ * normally or exceptionally, or left unprocessed.
*
* <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method
@@ -644,7 +443,7 @@
t.fork();
else {
t.quietlyInvoke();
- if (ex == null)
+ if (ex == null && t.status < NORMAL)
ex = t.getException();
}
}
@@ -655,26 +454,27 @@
t.cancel(false);
else {
t.quietlyJoin();
- if (ex == null)
+ if (ex == null && t.status < NORMAL)
ex = t.getException();
}
}
}
if (ex != null)
- rethrowException(ex);
+ UNSAFE.throwException(ex);
}
/**
* Forks all tasks in the specified collection, returning when
* {@code isDone} holds for each task or an (unchecked) exception
- * is encountered. If any task encounters an exception, others
- * may be, but are not guaranteed to be, cancelled. If more than
- * one task encounters an exception, then this method throws any
- * one of these exceptions. The individual status of each task
- * may be checked using {@link #getException()} and related
- * methods. The behavior of this operation is undefined if the
- * specified collection is modified while the operation is in
- * progress.
+ * is encountered, in which case the exception is rethrown. If
+ * more than one task encounters an exception, then this method
+ * throws any one of these exceptions. If any task encounters an
+ * exception, others may be cancelled. However, the execution
+ * status of individual tasks is not guaranteed upon exceptional
+ * return. The status of each task may be obtained using {@link
+ * #getException()} and related methods to check if they have been
+ * cancelled, completed normally or exceptionally, or left
+ * unprocessed.
*
* <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method
@@ -706,7 +506,7 @@
t.fork();
else {
t.quietlyInvoke();
- if (ex == null)
+ if (ex == null && t.status < NORMAL)
ex = t.getException();
}
}
@@ -717,13 +517,13 @@
t.cancel(false);
else {
t.quietlyJoin();
- if (ex == null)
+ if (ex == null && t.status < NORMAL)
ex = t.getException();
}
}
}
if (ex != null)
- rethrowException(ex);
+ UNSAFE.throwException(ex);
return tasks;
}
@@ -753,7 +553,35 @@
*/
public boolean cancel(boolean mayInterruptIfRunning) {
setCompletion(CANCELLED);
- return (status & COMPLETION_MASK) == CANCELLED;
+ return status == CANCELLED;
+ }
+
+ /**
+ * Cancels, ignoring any exceptions thrown by cancel. Used during
+ * worker and pool shutdown. Cancel is spec'ed not to throw any
+ * exceptions, but if it does anyway, we have no recourse during
+ * shutdown, so guard against this case.
+ */
+ final void cancelIgnoringExceptions() {
+ try {
+ cancel(false);
+ } catch (Throwable ignore) {
+ }
+ }
+
+ /**
+ * Cancels if current thread is a terminating worker thread,
+ * ignoring any exceptions thrown by cancel.
+ */
+ final void cancelIfTerminating() {
+ Thread t = Thread.currentThread();
+ if ((t instanceof ForkJoinWorkerThread) &&
+ ((ForkJoinWorkerThread) t).isTerminating()) {
+ try {
+ cancel(false);
+ } catch (Throwable ignore) {
+ }
+ }
}
public final boolean isDone() {
@@ -761,7 +589,7 @@
}
public final boolean isCancelled() {
- return (status & COMPLETION_MASK) == CANCELLED;
+ return status == CANCELLED;
}
/**
@@ -770,7 +598,7 @@
* @return {@code true} if this task threw an exception or was cancelled
*/
public final boolean isCompletedAbnormally() {
- return (status & COMPLETION_MASK) < NORMAL;
+ return status < NORMAL;
}
/**
@@ -781,7 +609,7 @@
* exception and was not cancelled
*/
public final boolean isCompletedNormally() {
- return (status & COMPLETION_MASK) == NORMAL;
+ return status == NORMAL;
}
/**
@@ -792,7 +620,7 @@
* @return the exception, or {@code null} if none
*/
public final Throwable getException() {
- int s = status & COMPLETION_MASK;
+ int s = status;
return ((s >= NORMAL) ? null :
(s == CANCELLED) ? new CancellationException() :
exceptionMap.get(this));
@@ -813,20 +641,21 @@
* thrown will be a {@code RuntimeException} with cause {@code ex}.
*/
public void completeExceptionally(Throwable ex) {
- setDoneExceptionally((ex instanceof RuntimeException) ||
- (ex instanceof Error) ? ex :
- new RuntimeException(ex));
+ setExceptionalCompletion((ex instanceof RuntimeException) ||
+ (ex instanceof Error) ? ex :
+ new RuntimeException(ex));
}
/**
* Completes this task, and if not already aborted or cancelled,
- * returning a {@code null} result upon {@code join} and related
- * operations. This method may be used to provide results for
- * asynchronous tasks, or to provide alternative handling for
- * tasks that would not otherwise complete normally. Its use in
- * other situations is discouraged. This method is
- * overridable, but overridden versions must invoke {@code super}
- * implementation to maintain guarantees.
+ * returning the given value as the result of subsequent
+ * invocations of {@code join} and related operations. This method
+ * may be used to provide results for asynchronous tasks, or to
+ * provide alternative handling for tasks that would not otherwise
+ * complete normally. Its use in other situations is
+ * discouraged. This method is overridable, but overridden
+ * versions must invoke {@code super} implementation to maintain
+ * guarantees.
*
* @param value the result value for this task
*/
@@ -834,97 +663,151 @@
try {
setRawResult(value);
} catch (Throwable rex) {
- setDoneExceptionally(rex);
+ setExceptionalCompletion(rex);
return;
}
- setNormalCompletion();
+ setCompletion(NORMAL);
}
public final V get() throws InterruptedException, ExecutionException {
- ForkJoinWorkerThread w = getWorker();
- if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke())
- awaitDone(w, true);
- return reportFutureResult();
+ quietlyJoin();
+ if (Thread.interrupted())
+ throw new InterruptedException();
+ int s = status;
+ if (s < NORMAL) {
+ Throwable ex;
+ if (s == CANCELLED)
+ throw new CancellationException();
+ if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
+ throw new ExecutionException(ex);
+ }
+ return getRawResult();
}
public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
+ Thread t = Thread.currentThread();
+ ForkJoinPool pool;
+ if (t instanceof ForkJoinWorkerThread) {
+ ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+ if (status >= 0 && w.unpushTask(this))
+ quietlyExec();
+ pool = w.pool;
+ }
+ else
+ pool = null;
+ /*
+ * Timed wait loop intermixes cases for FJ (pool != null) and
+ * non FJ threads. For FJ, decrement pool count but don't try
+ * for replacement; increment count on completion. For non-FJ,
+ * deal with interrupts. This is messy, but a little less so
+ * than is splitting the FJ and nonFJ cases.
+ */
+ boolean interrupted = false;
+ boolean dec = false; // true if pool count decremented
long nanos = unit.toNanos(timeout);
- ForkJoinWorkerThread w = getWorker();
- if (w == null || status < 0 || !w.unpushTask(this) || !tryQuietlyInvoke())
- awaitDone(w, nanos);
- return reportTimedFutureResult();
- }
-
- /**
- * Possibly executes other tasks until this task {@link #isDone is
- * done}, then returns the result of the computation. This method
- * may be more efficient than {@code join}, but is only applicable
- * when there are no potential dependencies between continuation
- * of the current task and that of any other task that might be
- * executed while helping. (This usually holds for pure
- * divide-and-conquer tasks).
- *
- * <p>This method may be invoked only from within {@code
- * ForkJoinTask} computations (as may be determined using method
- * {@link #inForkJoinPool}). Attempts to invoke in other contexts
- * result in exceptions or errors, possibly including {@code
- * ClassCastException}.
- *
- * @return the computed result
- */
- public final V helpJoin() {
- ForkJoinWorkerThread w = (ForkJoinWorkerThread) Thread.currentThread();
- if (status < 0 || !w.unpushTask(this) || !tryExec())
- reportException(busyJoin(w));
+ for (;;) {
+ if (pool == null && Thread.interrupted()) {
+ interrupted = true;
+ break;
+ }
+ int s = status;
+ if (s < 0)
+ break;
+ if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)) {
+ long startTime = System.nanoTime();
+ long nt; // wait time
+ while (status >= 0 &&
+ (nt = nanos - (System.nanoTime() - startTime)) > 0) {
+ if (pool != null && !dec)
+ dec = pool.tryDecrementRunningCount();
+ else {
+ long ms = nt / 1000000;
+ int ns = (int) (nt % 1000000);
+ try {
+ synchronized(this) {
+ if (status >= 0)
+ wait(ms, ns);
+ }
+ } catch (InterruptedException ie) {
+ if (pool != null)
+ cancelIfTerminating();
+ else {
+ interrupted = true;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (pool != null && dec)
+ pool.incrementRunningCount();
+ if (interrupted)
+ throw new InterruptedException();
+ int es = status;
+ if (es != NORMAL) {
+ Throwable ex;
+ if (es == CANCELLED)
+ throw new CancellationException();
+ if (es == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
+ throw new ExecutionException(ex);
+ throw new TimeoutException();
+ }
return getRawResult();
}
/**
- * Possibly executes other tasks until this task {@link #isDone is
- * done}. This method may be useful when processing collections
- * of tasks when some have been cancelled or otherwise known to
- * have aborted.
- *
- * <p>This method may be invoked only from within {@code
- * ForkJoinTask} computations (as may be determined using method
- * {@link #inForkJoinPool}). Attempts to invoke in other contexts
- * result in exceptions or errors, possibly including {@code
- * ClassCastException}.
- */
- public final void quietlyHelpJoin() {
- if (status >= 0) {
- ForkJoinWorkerThread w =
- (ForkJoinWorkerThread) Thread.currentThread();
- if (!w.unpushTask(this) || !tryQuietlyInvoke())
- busyJoin(w);
- }
- }
-
- /**
- * Joins this task, without returning its result or throwing an
+ * Joins this task, without returning its result or throwing its
* exception. This method may be useful when processing
* collections of tasks when some have been cancelled or otherwise
* known to have aborted.
*/
public final void quietlyJoin() {
- if (status >= 0) {
- ForkJoinWorkerThread w = getWorker();
- if (w == null || !w.unpushTask(this) || !tryQuietlyInvoke())
- awaitDone(w, true);
+ Thread t;
+ if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+ ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+ if (status >= 0) {
+ if (w.unpushTask(this)) {
+ boolean completed;
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ setExceptionalCompletion(rex);
+ return;
+ }
+ if (completed) {
+ setCompletion(NORMAL);
+ return;
+ }
+ }
+ w.joinTask(this);
+ }
}
+ else
+ externalAwaitDone();
}
/**
* Commences performing this task and awaits its completion if
- * necessary, without returning its result or throwing an
- * exception. This method may be useful when processing
- * collections of tasks when some have been cancelled or otherwise
- * known to have aborted.
+ * necessary, without returning its result or throwing its
+ * exception.
*/
public final void quietlyInvoke() {
- if (status >= 0 && !tryQuietlyInvoke())
- quietlyJoin();
+ if (status >= 0) {
+ boolean completed;
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ setExceptionalCompletion(rex);
+ return;
+ }
+ if (completed)
+ setCompletion(NORMAL);
+ else
+ quietlyJoin();
+ }
}
/**
@@ -956,7 +839,7 @@
* pre-constructed trees of subtasks in loops.
*/
public void reinitialize() {
- if ((status & COMPLETION_MASK) == EXCEPTIONAL)
+ if (status == EXCEPTIONAL)
exceptionMap.remove(this);
status = 0;
}
@@ -1246,7 +1129,7 @@
private static final long serialVersionUID = -7721805057305804111L;
/**
- * Saves the state to a stream.
+ * Saves the state to a stream (that is, serializes it).
*
* @serialData the current run status and the exception thrown
* during execution, or {@code null} if none
@@ -1259,18 +1142,16 @@
}
/**
- * Reconstitutes the instance from a stream.
+ * Reconstitutes the instance from a stream (that is, deserializes it).
*
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
- status &= ~INTERNAL_SIGNAL_MASK; // clear internal signal counts
- status |= EXTERNAL_SIGNAL; // conservatively set external signal
Object ex = s.readObject();
if (ex != null)
- setDoneExceptionally((Throwable) ex);
+ setExceptionalCompletion((Throwable) ex);
}
// Unsafe mechanics
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java Thu Sep 16 11:19:43 2010 -0700
@@ -35,7 +35,9 @@
package java.util.concurrent;
+import java.util.Random;
import java.util.Collection;
+import java.util.concurrent.locks.LockSupport;
/**
* A thread managed by a {@link ForkJoinPool}. This class is
@@ -52,46 +54,55 @@
*/
public class ForkJoinWorkerThread extends Thread {
/*
- * Algorithm overview:
+ * Overview:
+ *
+ * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
+ * ForkJoinTasks. This class includes bookkeeping in support of
+ * worker activation, suspension, and lifecycle control described
+ * in more detail in the internal documentation of class
+ * ForkJoinPool. And as described further below, this class also
+ * includes special-cased support for some ForkJoinTask
+ * methods. But the main mechanics involve work-stealing:
*
- * 1. Work-Stealing: Work-stealing queues are special forms of
- * Deques that support only three of the four possible
- * end-operations -- push, pop, and deq (aka steal), and only do
- * so under the constraints that push and pop are called only from
- * the owning thread, while deq may be called from other threads.
- * (If you are unfamiliar with them, you probably want to read
- * Herlihy and Shavit's book "The Art of Multiprocessor
- * programming", chapter 16 describing these in more detail before
- * proceeding.) The main work-stealing queue design is roughly
- * similar to "Dynamic Circular Work-Stealing Deque" by David
- * Chase and Yossi Lev, SPAA 2005
- * (http://research.sun.com/scalable/pubs/index.html). The main
- * difference ultimately stems from gc requirements that we null
- * out taken slots as soon as we can, to maintain as small a
- * footprint as possible even in programs generating huge numbers
- * of tasks. To accomplish this, we shift the CAS arbitrating pop
- * vs deq (steal) from being on the indices ("base" and "sp") to
- * the slots themselves (mainly via method "casSlotNull()"). So,
- * both a successful pop and deq mainly entail CAS'ing a non-null
- * slot to null. Because we rely on CASes of references, we do
- * not need tag bits on base or sp. They are simple ints as used
- * in any circular array-based queue (see for example ArrayDeque).
- * Updates to the indices must still be ordered in a way that
- * guarantees that (sp - base) > 0 means the queue is empty, but
- * otherwise may err on the side of possibly making the queue
- * appear nonempty when a push, pop, or deq have not fully
- * committed. Note that this means that the deq operation,
- * considered individually, is not wait-free. One thief cannot
- * successfully continue until another in-progress one (or, if
- * previously empty, a push) completes. However, in the
- * aggregate, we ensure at least probabilistic
- * non-blockingness. If an attempted steal fails, a thief always
- * chooses a different random victim target to try next. So, in
- * order for one thief to progress, it suffices for any
- * in-progress deq or new push on any empty queue to complete. One
- * reason this works well here is that apparently-nonempty often
- * means soon-to-be-stealable, which gives threads a chance to
- * activate if necessary before stealing (see below).
+ * Work-stealing queues are special forms of Deques that support
+ * only three of the four possible end-operations -- push, pop,
+ * and deq (aka steal), under the further constraints that push
+ * and pop are called only from the owning thread, while deq may
+ * be called from other threads. (If you are unfamiliar with
+ * them, you probably want to read Herlihy and Shavit's book "The
+ * Art of Multiprocessor programming", chapter 16 describing these
+ * in more detail before proceeding.) The main work-stealing
+ * queue design is roughly similar to those in the papers "Dynamic
+ * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
+ * (http://research.sun.com/scalable/pubs/index.html) and
+ * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
+ * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
+ * The main differences ultimately stem from gc requirements that
+ * we null out taken slots as soon as we can, to maintain as small
+ * a footprint as possible even in programs generating huge
+ * numbers of tasks. To accomplish this, we shift the CAS
+ * arbitrating pop vs deq (steal) from being on the indices
+ * ("base" and "sp") to the slots themselves (mainly via method
+ * "casSlotNull()"). So, both a successful pop and deq mainly
+ * entail a CAS of a slot from non-null to null. Because we rely
+ * on CASes of references, we do not need tag bits on base or sp.
+ * They are simple ints as used in any circular array-based queue
+ * (see for example ArrayDeque). Updates to the indices must
+ * still be ordered in a way that guarantees that sp == base means
+ * the queue is empty, but otherwise may err on the side of
+ * possibly making the queue appear nonempty when a push, pop, or
+ * deq have not fully committed. Note that this means that the deq
+ * operation, considered individually, is not wait-free. One thief
+ * cannot successfully continue until another in-progress one (or,
+ * if previously empty, a push) completes. However, in the
+ * aggregate, we ensure at least probabilistic non-blockingness.
+ * If an attempted steal fails, a thief always chooses a different
+ * random victim target to try next. So, in order for one thief to
+ * progress, it suffices for any in-progress deq or new push on
+ * any empty queue to complete. One reason this works well here is
+ * that apparently-nonempty often means soon-to-be-stealable,
+ * which gives threads a chance to set activation status if
+ * necessary before stealing.
*
* This approach also enables support for "async mode" where local
* task processing is in FIFO, not LIFO order; simply by using a
@@ -99,24 +110,54 @@
* by the ForkJoinPool). This allows use in message-passing
* frameworks in which tasks are never joined.
*
- * Efficient implementation of this approach currently relies on
- * an uncomfortable amount of "Unsafe" mechanics. To maintain
+ * When a worker would otherwise be blocked waiting to join a
+ * task, it first tries a form of linear helping: Each worker
+ * records (in field currentSteal) the most recent task it stole
+ * from some other worker. Plus, it records (in field currentJoin)
+ * the task it is currently actively joining. Method joinTask uses
+ * these markers to try to find a worker to help (i.e., steal back
+ * a task from and execute it) that could hasten completion of the
+ * actively joined task. In essence, the joiner executes a task
+ * that would be on its own local deque had the to-be-joined task
+ * not been stolen. This may be seen as a conservative variant of
+ * the approach in Wagner & Calder "Leapfrogging: a portable
+ * technique for implementing efficient futures" SIGPLAN Notices,
+ * 1993 (http://portal.acm.org/citation.cfm?id=155354). It differs
+ * in that: (1) We only maintain dependency links across workers
+ * upon steals, rather than use per-task bookkeeping. This may
+ * require a linear scan of workers array to locate stealers, but
+ * usually doesn't because stealers leave hints (that may become
+ * stale/wrong) of where to locate them. This isolates cost to
+ * when it is needed, rather than adding to per-task overhead.
+ * (2) It is "shallow", ignoring nesting and potentially cyclic
+ * mutual steals. (3) It is intentionally racy: field currentJoin
+ * is updated only while actively joining, which means that we
+ * miss links in the chain during long-lived tasks, GC stalls etc
+ * (which is OK since blocking in such cases is usually a good
+ * idea). (4) We bound the number of attempts to find work (see
+ * MAX_HELP_DEPTH) and fall back to suspending the worker and if
+ * necessary replacing it with a spare (see
+ * ForkJoinPool.awaitJoin).
+ *
+ * Efficient implementation of these algorithms currently relies
+ * on an uncomfortable amount of "Unsafe" mechanics. To maintain
* correct orderings, reads and writes of variable base require
- * volatile ordering. Variable sp does not require volatile write
- * but needs cheaper store-ordering on writes. Because they are
- * protected by volatile base reads, reads of the queue array and
- * its slots do not need volatile load semantics, but writes (in
- * push) require store order and CASes (in pop and deq) require
- * (volatile) CAS semantics. (See "Idempotent work stealing" by
- * Michael, Saraswat, and Vechev, PPoPP 2009
- * http://portal.acm.org/citation.cfm?id=1504186 for an algorithm
- * with similar properties, but without support for nulling
- * slots.) Since these combinations aren't supported using
- * ordinary volatiles, the only way to accomplish these
- * efficiently is to use direct Unsafe calls. (Using external
- * AtomicIntegers and AtomicReferenceArrays for the indices and
- * array is significantly slower because of memory locality and
- * indirection effects.)
+ * volatile ordering. Variable sp does not require volatile
+ * writes but still needs store-ordering, which we accomplish by
+ * pre-incrementing sp before filling the slot with an ordered
+ * store. (Pre-incrementing also enables backouts used in
+ * joinTask.) Because they are protected by volatile base reads,
+ * reads of the queue array and its slots by other threads do not
+ * need volatile load semantics, but writes (in push) require
+ * store order and CASes (in pop and deq) require (volatile) CAS
+ * semantics. (Michael, Saraswat, and Vechev's algorithm has
+ * similar properties, but without support for nulling slots.)
+ * Since these combinations aren't supported using ordinary
+ * volatiles, the only way to accomplish these efficiently is to
+ * use direct Unsafe calls. (Using external AtomicIntegers and
+ * AtomicReferenceArrays for the indices and array is
+ * significantly slower because of memory locality and indirection
+ * effects.)
*
* Further, performance on most platforms is very sensitive to
* placement and sizing of the (resizable) queue array. Even
@@ -124,56 +165,45 @@
* initial size must be large enough to counteract cache
* contention effects across multiple queues (especially in the
* presence of GC cardmarking). Also, to improve thread-locality,
- * queues are currently initialized immediately after the thread
- * gets the initial signal to start processing tasks. However,
- * all queue-related methods except pushTask are written in a way
- * that allows them to instead be lazily allocated and/or disposed
- * of when empty. All together, these low-level implementation
- * choices produce as much as a factor of 4 performance
- * improvement compared to naive implementations, and enable the
- * processing of billions of tasks per second, sometimes at the
- * expense of ugliness.
- *
- * 2. Run control: The primary run control is based on a global
- * counter (activeCount) held by the pool. It uses an algorithm
- * similar to that in Herlihy and Shavit section 17.6 to cause
- * threads to eventually block when all threads declare they are
- * inactive. For this to work, threads must be declared active
- * when executing tasks, and before stealing a task. They must be
- * inactive before blocking on the Pool Barrier (awaiting a new
- * submission or other Pool event). In between, there is some free
- * play which we take advantage of to avoid contention and rapid
- * flickering of the global activeCount: If inactive, we activate
- * only if a victim queue appears to be nonempty (see above).
- * Similarly, a thread tries to inactivate only after a full scan
- * of other threads. The net effect is that contention on
- * activeCount is rarely a measurable performance issue. (There
- * are also a few other cases where we scan for work rather than
- * retry/block upon contention.)
- *
- * 3. Selection control. We maintain policy of always choosing to
- * run local tasks rather than stealing, and always trying to
- * steal tasks before trying to run a new submission. All steals
- * are currently performed in randomly-chosen deq-order. It may be
- * worthwhile to bias these with locality / anti-locality
- * information, but doing this well probably requires more
- * lower-level information from JVMs than currently provided.
+ * queues are initialized after starting. All together, these
+ * low-level implementation choices produce as much as a factor of
+ * 4 performance improvement compared to naive implementations,
+ * and enable the processing of billions of tasks per second,
+ * sometimes at the expense of ugliness.
*/
/**
+ * Generator for initial random seeds for random victim
+ * selection. This is used only to create initial seeds. Random
+ * steals use a cheaper xorshift generator per steal attempt. We
+ * expect only rare contention on seedGenerator, so just use a
+ * plain Random.
+ */
+ private static final Random seedGenerator = new Random();
+
+ /**
+ * The maximum stolen->joining link depth allowed in helpJoinTask.
+ * Depths for legitimate chains are unbounded, but we use a fixed
+ * constant to avoid (otherwise unchecked) cycles and bound
+ * staleness of traversal parameters at the expense of sometimes
+ * blocking when we could be helping.
+ */
+ private static final int MAX_HELP_DEPTH = 8;
+
+ /**
* Capacity of work-stealing queue array upon initialization.
- * Must be a power of two. Initial size must be at least 2, but is
+ * Must be a power of two. Initial size must be at least 4, but is
* padded to minimize cache effects.
*/
private static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
/**
* Maximum work-stealing queue array size. Must be less than or
- * equal to 1 << 28 to ensure lack of index wraparound. (This
- * is less than usual bounds, because we need leftshift by 3
- * to be in int range).
+ * equal to 1 << (31 - width of array entry) to ensure lack of
+ * index wraparound. The value is set in the static block
+ * at the end of this file after obtaining width.
*/
- private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 28;
+ private static final int MAXIMUM_QUEUE_CAPACITY;
/**
* The pool this thread works in. Accessed directly by ForkJoinTask.
@@ -182,65 +212,118 @@
/**
* The work-stealing queue array. Size must be a power of two.
- * Initialized when thread starts, to improve memory locality.
+ * Initialized in onStart, to improve memory locality.
*/
private ForkJoinTask<?>[] queue;
/**
- * Index (mod queue.length) of next queue slot to push to or pop
- * from. It is written only by owner thread, via ordered store.
- * Both sp and base are allowed to wrap around on overflow, but
- * (sp - base) still estimates size.
- */
- private volatile int sp;
-
- /**
* Index (mod queue.length) of least valid queue slot, which is
* always the next position to steal from if nonempty.
*/
private volatile int base;
/**
- * Activity status. When true, this worker is considered active.
- * Must be false upon construction. It must be true when executing
- * tasks, and BEFORE stealing a task. It must be false before
- * calling pool.sync.
+ * Index (mod queue.length) of next queue slot to push to or pop
+ * from. It is written only by owner thread, and accessed by other
+ * threads only after reading (volatile) base. Both sp and base
+ * are allowed to wrap around on overflow, but (sp - base) still
+ * estimates size.
*/
- private boolean active;
+ private int sp;
+
+ /**
+ * The index of most recent stealer, used as a hint to avoid
+ * traversal in method helpJoinTask. This is only a hint because a
+ * worker might have had multiple steals and this only holds one
+ * of them (usually the most current). Declared non-volatile,
+ * relying on other prevailing sync to keep reasonably current.
+ */
+ private int stealHint;
/**
- * Run state of this worker. Supports simple versions of the usual
- * shutdown/shutdownNow control.
+ * Run state of this worker. In addition to the usual run levels,
+ * tracks if this worker is suspended as a spare, and if it was
+ * killed (trimmed) while suspended. However, "active" status is
+ * maintained separately and modified only in conjunction with
+ * CASes of the pool's runState (which are currently sadly
+ * manually inlined for performance.) Accessed directly by pool
+ * to simplify checks for normal (zero) status.
*/
- private volatile int runState;
+ volatile int runState;
+
+ private static final int TERMINATING = 0x01;
+ private static final int TERMINATED = 0x02;
+ private static final int SUSPENDED = 0x04; // inactive spare
+ private static final int TRIMMED = 0x08; // killed while suspended
+
+ /**
+ * Number of steals. Directly accessed (and reset) by
+ * pool.tryAccumulateStealCount when idle.
+ */
+ int stealCount;
/**
* Seed for random number generator for choosing steal victims.
- * Uses Marsaglia xorshift. Must be nonzero upon initialization.
+ * Uses Marsaglia xorshift. Must be initialized as nonzero.
*/
private int seed;
/**
- * Number of steals, transferred to pool when idle
+ * Activity status. When true, this worker is considered active.
+ * Accessed directly by pool. Must be false upon construction.
*/
- private int stealCount;
+ boolean active;
+
+ /**
+ * True if use local fifo, not default lifo, for local polling.
+ * Shadows value from ForkJoinPool.
+ */
+ private final boolean locallyFifo;
/**
* Index of this worker in pool array. Set once by pool before
- * running, and accessed directly by pool during cleanup etc.
+ * running, and accessed directly by pool to locate this worker in
+ * its workers array.
*/
int poolIndex;
/**
- * The last barrier event waited for. Accessed in pool callback
- * methods, but only by current thread.
+ * The last pool event waited for. Accessed only by pool in
+ * callback methods invoked within this thread.
*/
- long lastEventCount;
+ int lastEventCount;
+
+ /**
+ * Encoded index and event count of next event waiter. Accessed
+ * only by ForkJoinPool for managing event waiters.
+ */
+ volatile long nextWaiter;
+
+ /**
+ * Number of times this thread suspended as spare. Accessed only
+ * by pool.
+ */
+ int spareCount;
/**
- * True if use local fifo, not default lifo, for local polling
+ * Encoded index and count of next spare waiter. Accessed only
+ * by ForkJoinPool for managing spares.
*/
- private boolean locallyFifo;
+ volatile int nextSpare;
+
+ /**
+ * The task currently being joined, set only when actively trying
+ * to help other stealers in helpJoinTask. Written only by this
+ * thread, but read by others.
+ */
+ private volatile ForkJoinTask<?> currentJoin;
+
+ /**
+ * The task most recently stolen from another worker (or
+ * submission queue). Written only by this thread, but read by
+ * others.
+ */
+ private volatile ForkJoinTask<?> currentSteal;
/**
* Creates a ForkJoinWorkerThread operating in the given pool.
@@ -249,13 +332,24 @@
* @throws NullPointerException if pool is null
*/
protected ForkJoinWorkerThread(ForkJoinPool pool) {
- if (pool == null) throw new NullPointerException();
this.pool = pool;
- // Note: poolIndex is set by pool during construction
- // Remaining initialization is deferred to onStart
+ this.locallyFifo = pool.locallyFifo;
+ setDaemon(true);
+ // To avoid exposing construction details to subclasses,
+ // remaining initialization is in start() and onStart()
}
- // Public access methods
+ /**
+ * Performs additional initialization and starts this thread.
+ */
+ final void start(int poolIndex, UncaughtExceptionHandler ueh) {
+ this.poolIndex = poolIndex;
+ if (ueh != null)
+ setUncaughtExceptionHandler(ueh);
+ start();
+ }
+
+ // Public/protected methods
/**
* Returns the pool hosting this thread.
@@ -280,129 +374,24 @@
}
/**
- * Establishes local first-in-first-out scheduling mode for forked
- * tasks that are never joined.
- *
- * @param async if true, use locally FIFO scheduling
- */
- void setAsyncMode(boolean async) {
- locallyFifo = async;
- }
-
- // Runstate management
-
- // Runstate values. Order matters
- private static final int RUNNING = 0;
- private static final int SHUTDOWN = 1;
- private static final int TERMINATING = 2;
- private static final int TERMINATED = 3;
-
- final boolean isShutdown() { return runState >= SHUTDOWN; }
- final boolean isTerminating() { return runState >= TERMINATING; }
- final boolean isTerminated() { return runState == TERMINATED; }
- final boolean shutdown() { return transitionRunStateTo(SHUTDOWN); }
- final boolean shutdownNow() { return transitionRunStateTo(TERMINATING); }
-
- /**
- * Transitions to at least the given state.
- *
- * @return {@code true} if not already at least at given state
- */
- private boolean transitionRunStateTo(int state) {
- for (;;) {
- int s = runState;
- if (s >= state)
- return false;
- if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, state))
- return true;
- }
- }
-
- /**
- * Tries to set status to active; fails on contention.
- */
- private boolean tryActivate() {
- if (!active) {
- if (!pool.tryIncrementActiveCount())
- return false;
- active = true;
- }
- return true;
- }
-
- /**
- * Tries to set status to inactive; fails on contention.
- */
- private boolean tryInactivate() {
- if (active) {
- if (!pool.tryDecrementActiveCount())
- return false;
- active = false;
- }
- return true;
- }
-
- /**
- * Computes next value for random victim probe. Scans don't
- * require a very high quality generator, but also not a crummy
- * one. Marsaglia xor-shift is cheap and works well.
- */
- private static int xorShift(int r) {
- r ^= (r << 13);
- r ^= (r >>> 17);
- return r ^ (r << 5);
- }
-
- // Lifecycle methods
-
- /**
- * This method is required to be public, but should never be
- * called explicitly. It performs the main run loop to execute
- * ForkJoinTasks.
- */
- public void run() {
- Throwable exception = null;
- try {
- onStart();
- pool.sync(this); // await first pool event
- mainLoop();
- } catch (Throwable ex) {
- exception = ex;
- } finally {
- onTermination(exception);
- }
- }
-
- /**
- * Executes tasks until shut down.
- */
- private void mainLoop() {
- while (!isShutdown()) {
- ForkJoinTask<?> t = pollTask();
- if (t != null || (t = pollSubmission()) != null)
- t.quietlyExec();
- else if (tryInactivate())
- pool.sync(this);
- }
- }
-
- /**
* Initializes internal state after construction but before
* processing any tasks. If you override this method, you must
- * invoke super.onStart() at the beginning of the method.
+ * invoke @code{super.onStart()} at the beginning of the method.
* Initialization requires care: Most fields must have legal
* default values, to ensure that attempted accesses from other
* threads work correctly even before this thread starts
* processing tasks.
*/
protected void onStart() {
- // Allocate while starting to improve chances of thread-local
- // isolation
+ int rs = seedGenerator.nextInt();
+ seed = rs == 0? 1 : rs; // seed must be nonzero
+
+ // Allocate name string and arrays in this thread
+ String pid = Integer.toString(pool.getPoolNumber());
+ String wid = Integer.toString(poolIndex);
+ setName("ForkJoinPool-" + pid + "-worker-" + wid);
+
queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
- // Initial value of seed need not be especially random but
- // should differ across workers and must be nonzero
- int p = poolIndex + 1;
- seed = p + (p << 8) + (p << 16) + (p << 24); // spread bits
}
/**
@@ -414,97 +403,187 @@
* to an unrecoverable error, or {@code null} if completed normally
*/
protected void onTermination(Throwable exception) {
- // Execute remaining local tasks unless aborting or terminating
- while (exception == null && pool.isProcessingTasks() && base != sp) {
- try {
- ForkJoinTask<?> t = popTask();
- if (t != null)
- t.quietlyExec();
- } catch (Throwable ex) {
- exception = ex;
+ try {
+ ForkJoinPool p = pool;
+ if (active) {
+ int a; // inline p.tryDecrementActiveCount
+ active = false;
+ do {} while (!UNSAFE.compareAndSwapInt
+ (p, poolRunStateOffset, a = p.runState, a - 1));
}
- }
- // Cancel other tasks, transition status, notify pool, and
- // propagate exception to uncaught exception handler
- try {
- do {} while (!tryInactivate()); // ensure inactive
cancelTasks();
- runState = TERMINATED;
- pool.workerTerminated(this);
+ setTerminated();
+ p.workerTerminated(this);
} catch (Throwable ex) { // Shouldn't ever happen
if (exception == null) // but if so, at least rethrown
exception = ex;
} finally {
if (exception != null)
- ForkJoinTask.rethrowException(exception);
+ UNSAFE.throwException(exception);
+ }
+ }
+
+ /**
+ * This method is required to be public, but should never be
+ * called explicitly. It performs the main run loop to execute
+ * ForkJoinTasks.
+ */
+ public void run() {
+ Throwable exception = null;
+ try {
+ onStart();
+ mainLoop();
+ } catch (Throwable ex) {
+ exception = ex;
+ } finally {
+ onTermination(exception);
}
}
- // Intrinsics-based support for queue operations.
+ // helpers for run()
- private static long slotOffset(int i) {
- return ((long) i << qShift) + qBase;
+ /**
+ * Finds and executes tasks, and checks status while running.
+ */
+ private void mainLoop() {
+ boolean ran = false; // true if ran a task on last step
+ ForkJoinPool p = pool;
+ for (;;) {
+ p.preStep(this, ran);
+ if (runState != 0)
+ break;
+ ran = tryExecSteal() || tryExecSubmission();
+ }
}
/**
- * Adds in store-order the given task at given slot of q to null.
- * Caller must ensure q is non-null and index is in range.
+ * Tries to steal a task and execute it.
+ *
+ * @return true if ran a task
*/
- private static void setSlot(ForkJoinTask<?>[] q, int i,
- ForkJoinTask<?> t) {
- UNSAFE.putOrderedObject(q, slotOffset(i), t);
+ private boolean tryExecSteal() {
+ ForkJoinTask<?> t;
+ if ((t = scan()) != null) {
+ t.quietlyExec();
+ UNSAFE.putOrderedObject(this, currentStealOffset, null);
+ if (sp != base)
+ execLocalTasks();
+ return true;
+ }
+ return false;
}
/**
- * CAS given slot of q to null. Caller must ensure q is non-null
- * and index is in range.
+ * If a submission exists, try to activate and run it.
+ *
+ * @return true if ran a task
*/
- private static boolean casSlotNull(ForkJoinTask<?>[] q, int i,
- ForkJoinTask<?> t) {
- return UNSAFE.compareAndSwapObject(q, slotOffset(i), t, null);
+ private boolean tryExecSubmission() {
+ ForkJoinPool p = pool;
+ // This loop is needed in case attempt to activate fails, in
+ // which case we only retry if there still appears to be a
+ // submission.
+ while (p.hasQueuedSubmissions()) {
+ ForkJoinTask<?> t; int a;
+ if (active || // inline p.tryIncrementActiveCount
+ (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
+ a = p.runState, a + 1))) {
+ if ((t = p.pollSubmission()) != null) {
+ UNSAFE.putOrderedObject(this, currentStealOffset, t);
+ t.quietlyExec();
+ UNSAFE.putOrderedObject(this, currentStealOffset, null);
+ if (sp != base)
+ execLocalTasks();
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
- * Sets sp in store-order.
+ * Runs local tasks until queue is empty or shut down. Call only
+ * while active.
*/
- private void storeSp(int s) {
- UNSAFE.putOrderedInt(this, spOffset, s);
+ private void execLocalTasks() {
+ while (runState == 0) {
+ ForkJoinTask<?> t = locallyFifo ? locallyDeqTask() : popTask();
+ if (t != null)
+ t.quietlyExec();
+ else if (sp == base)
+ break;
+ }
}
- // Main queue methods
+ /*
+ * Intrinsics-based atomic writes for queue slots. These are
+ * basically the same as methods in AtomicReferenceArray, but
+ * specialized for (1) ForkJoinTask elements (2) requirement that
+ * nullness and bounds checks have already been performed by
+ * callers and (3) effective offsets are known not to overflow
+ * from int to long (because of MAXIMUM_QUEUE_CAPACITY). We don't
+ * need corresponding version for reads: plain array reads are OK
+ * because they are protected by other volatile reads and are
+ * confirmed by CASes.
+ *
+ * Most uses don't actually call these methods, but instead contain
+ * inlined forms that enable more predictable optimization. We
+ * don't define the version of write used in pushTask at all, but
+ * instead inline there a store-fenced array slot write.
+ */
/**
- * Pushes a task. Called only by current thread.
+ * CASes slot i of array q from t to null. Caller must ensure q is
+ * non-null and index is in range.
+ */
+ private static final boolean casSlotNull(ForkJoinTask<?>[] q, int i,
+ ForkJoinTask<?> t) {
+ return UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null);
+ }
+
+ /**
+ * Performs a volatile write of the given task at given slot of
+ * array q. Caller must ensure q is non-null and index is in
+ * range. This method is used only during resets and backouts.
+ */
+ private static final void writeSlot(ForkJoinTask<?>[] q, int i,
+ ForkJoinTask<?> t) {
+ UNSAFE.putObjectVolatile(q, (i << qShift) + qBase, t);
+ }
+
+ // queue methods
+
+ /**
+ * Pushes a task. Call only from this thread.
*
* @param t the task. Caller must ensure non-null.
*/
final void pushTask(ForkJoinTask<?> t) {
ForkJoinTask<?>[] q = queue;
- int mask = q.length - 1;
- int s = sp;
- setSlot(q, s & mask, t);
- storeSp(++s);
- if ((s -= base) == 1)
- pool.signalWork();
- else if (s >= mask)
- growQueue();
+ int mask = q.length - 1; // implicit assert q != null
+ int s = sp++; // ok to increment sp before slot write
+ UNSAFE.putOrderedObject(q, ((s & mask) << qShift) + qBase, t);
+ if ((s -= base) == 0)
+ pool.signalWork(); // was empty
+ else if (s == mask)
+ growQueue(); // is full
}
/**
* Tries to take a task from the base of the queue, failing if
- * either empty or contended.
+ * empty or contended. Note: Specializations of this code appear
+ * in locallyDeqTask and elsewhere.
*
* @return a task, or null if none or contended
*/
final ForkJoinTask<?> deqTask() {
ForkJoinTask<?> t;
ForkJoinTask<?>[] q;
- int i;
- int b;
+ int b, i;
if (sp != (b = base) &&
(q = queue) != null && // must read q after b
- (t = q[i = (q.length - 1) & b]) != null &&
- casSlotNull(q, i, t)) {
+ (t = q[i = (q.length - 1) & b]) != null && base == b &&
+ UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null)) {
base = b + 1;
return t;
}
@@ -512,19 +591,20 @@
}
/**
- * Tries to take a task from the base of own queue, activating if
- * necessary, failing only if empty. Called only by current thread.
+ * Tries to take a task from the base of own queue. Assumes active
+ * status. Called only by this thread.
*
* @return a task, or null if none
*/
final ForkJoinTask<?> locallyDeqTask() {
- int b;
- while (sp != (b = base)) {
- if (tryActivate()) {
- ForkJoinTask<?>[] q = queue;
- int i = (q.length - 1) & b;
- ForkJoinTask<?> t = q[i];
- if (t != null && casSlotNull(q, i, t)) {
+ ForkJoinTask<?>[] q = queue;
+ if (q != null) {
+ ForkJoinTask<?> t;
+ int b, i;
+ while (sp != (b = base)) {
+ if ((t = q[i = (q.length - 1) & b]) != null && base == b &&
+ UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase,
+ t, null)) {
base = b + 1;
return t;
}
@@ -534,46 +614,50 @@
}
/**
- * Returns a popped task, or null if empty. Ensures active status
- * if non-null. Called only by current thread.
+ * Returns a popped task, or null if empty. Assumes active status.
+ * Called only by this thread.
*/
- final ForkJoinTask<?> popTask() {
- int s = sp;
- while (s != base) {
- if (tryActivate()) {
- ForkJoinTask<?>[] q = queue;
- int mask = q.length - 1;
- int i = (s - 1) & mask;
+ private ForkJoinTask<?> popTask() {
+ ForkJoinTask<?>[] q = queue;
+ if (q != null) {
+ int s;
+ while ((s = sp) != base) {
+ int i = (q.length - 1) & --s;
+ long u = (i << qShift) + qBase; // raw offset
ForkJoinTask<?> t = q[i];
- if (t == null || !casSlotNull(q, i, t))
+ if (t == null) // lost to stealer
break;
- storeSp(s - 1);
- return t;
+ if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ sp = s; // putOrderedInt may encourage more timely write
+ // UNSAFE.putOrderedInt(this, spOffset, s);
+ return t;
+ }
}
}
return null;
}
/**
- * Specialized version of popTask to pop only if
- * topmost element is the given task. Called only
- * by current thread while active.
+ * Specialized version of popTask to pop only if topmost element
+ * is the given task. Called only by this thread while active.
*
* @param t the task. Caller must ensure non-null.
*/
final boolean unpushTask(ForkJoinTask<?> t) {
+ int s;
ForkJoinTask<?>[] q = queue;
- int mask = q.length - 1;
- int s = sp - 1;
- if (casSlotNull(q, s & mask, t)) {
- storeSp(s);
+ if ((s = sp) != base && q != null &&
+ UNSAFE.compareAndSwapObject
+ (q, (((q.length - 1) & --s) << qShift) + qBase, t, null)) {
+ sp = s; // putOrderedInt may encourage more timely write
+ // UNSAFE.putOrderedInt(this, spOffset, s);
return true;
}
return false;
}
/**
- * Returns next task or null if empty or contended
+ * Returns next task, or null if empty or contended.
*/
final ForkJoinTask<?> peekTask() {
ForkJoinTask<?>[] q = queue;
@@ -606,104 +690,209 @@
ForkJoinTask<?> t = oldQ[oldIndex];
if (t != null && !casSlotNull(oldQ, oldIndex, t))
t = null;
- setSlot(newQ, b & newMask, t);
+ writeSlot(newQ, b & newMask, t);
} while (++b != bf);
pool.signalWork();
}
/**
+ * Computes next value for random victim probe in scan(). Scans
+ * don't require a very high quality generator, but also not a
+ * crummy one. Marsaglia xor-shift is cheap and works well enough.
+ * Note: This is manually inlined in scan().
+ */
+ private static final int xorShift(int r) {
+ r ^= r << 13;
+ r ^= r >>> 17;
+ return r ^ (r << 5);
+ }
+
+ /**
* Tries to steal a task from another worker. Starts at a random
* index of workers array, and probes workers until finding one
* with non-empty queue or finding that all are empty. It
* randomly selects the first n probes. If these are empty, it
- * resorts to a full circular traversal, which is necessary to
- * accurately set active status by caller. Also restarts if pool
- * events occurred since last scan, which forces refresh of
- * workers array, in case barrier was associated with resize.
+ * resorts to a circular sweep, which is necessary to accurately
+ * set active status. (The circular sweep uses steps of
+ * approximately half the array size plus 1, to avoid bias
+ * stemming from leftmost packing of the array in ForkJoinPool.)
*
* This method must be both fast and quiet -- usually avoiding
* memory accesses that could disrupt cache sharing etc other than
- * those needed to check for and take tasks. This accounts for,
- * among other things, updating random seed in place without
- * storing it until exit.
+ * those needed to check for and take tasks (or to activate if not
+ * already active). This accounts for, among other things,
+ * updating random seed in place without storing it until exit.
*
* @return a task, or null if none found
*/
private ForkJoinTask<?> scan() {
- ForkJoinTask<?> t = null;
- int r = seed; // extract once to keep scan quiet
- ForkJoinWorkerThread[] ws; // refreshed on outer loop
- int mask; // must be power 2 minus 1 and > 0
- outer:do {
- if ((ws = pool.workers) != null && (mask = ws.length - 1) > 0) {
- int idx = r;
- int probes = ~mask; // use random index while negative
- for (;;) {
- r = xorShift(r); // update random seed
- ForkJoinWorkerThread v = ws[mask & idx];
- if (v == null || v.sp == v.base) {
- if (probes <= mask)
- idx = (probes++ < 0) ? r : (idx + 1);
- else
- break;
+ ForkJoinPool p = pool;
+ ForkJoinWorkerThread[] ws; // worker array
+ int n; // upper bound of #workers
+ if ((ws = p.workers) != null && (n = ws.length) > 1) {
+ boolean canSteal = active; // shadow active status
+ int r = seed; // extract seed once
+ int mask = n - 1;
+ int j = -n; // loop counter
+ int k = r; // worker index, random if j < 0
+ for (;;) {
+ ForkJoinWorkerThread v = ws[k & mask];
+ r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // inline xorshift
+ ForkJoinTask<?>[] q; ForkJoinTask<?> t; int b, a;
+ if (v != null && (b = v.base) != v.sp &&
+ (q = v.queue) != null) {
+ int i = (q.length - 1) & b;
+ long u = (i << qShift) + qBase; // raw offset
+ int pid = poolIndex;
+ if ((t = q[i]) != null) {
+ if (!canSteal && // inline p.tryIncrementActiveCount
+ UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
+ a = p.runState, a + 1))
+ canSteal = active = true;
+ if (canSteal && v.base == b++ &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ v.base = b;
+ v.stealHint = pid;
+ UNSAFE.putOrderedObject(this,
+ currentStealOffset, t);
+ seed = r;
+ ++stealCount;
+ return t;
+ }
}
- else if (!tryActivate() || (t = v.deqTask()) == null)
- continue outer; // restart on contention
- else
- break outer;
+ j = -n;
+ k = r; // restart on contention
}
+ else if (++j <= 0)
+ k = r;
+ else if (j <= n)
+ k += (n >>> 1) | 1;
+ else
+ break;
}
- } while (pool.hasNewSyncEvent(this)); // retry on pool events
- seed = r;
- return t;
- }
-
- /**
- * Gets and removes a local or stolen task.
- *
- * @return a task, if available
- */
- final ForkJoinTask<?> pollTask() {
- ForkJoinTask<?> t = locallyFifo ? locallyDeqTask() : popTask();
- if (t == null && (t = scan()) != null)
- ++stealCount;
- return t;
- }
-
- /**
- * Gets a local task.
- *
- * @return a task, if available
- */
- final ForkJoinTask<?> pollLocalTask() {
- return locallyFifo ? locallyDeqTask() : popTask();
- }
-
- /**
- * Returns a pool submission, if one exists, activating first.
- *
- * @return a submission, if available
- */
- private ForkJoinTask<?> pollSubmission() {
- ForkJoinPool p = pool;
- while (p.hasQueuedSubmissions()) {
- ForkJoinTask<?> t;
- if (tryActivate() && (t = p.pollSubmission()) != null)
- return t;
}
return null;
}
- // Methods accessed only by Pool
+ // Run State management
+
+ // status check methods used mainly by ForkJoinPool
+ final boolean isRunning() { return runState == 0; }
+ final boolean isTerminating() { return (runState & TERMINATING) != 0; }
+ final boolean isTerminated() { return (runState & TERMINATED) != 0; }
+ final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
+ final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
+
+ /**
+ * Sets state to TERMINATING. Does NOT unpark or interrupt
+ * to wake up if currently blocked. Callers must do so if desired.
+ */
+ final void shutdown() {
+ for (;;) {
+ int s = runState;
+ if ((s & (TERMINATING|TERMINATED)) != 0)
+ break;
+ if ((s & SUSPENDED) != 0) { // kill and wakeup if suspended
+ if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
+ (s & ~SUSPENDED) |
+ (TRIMMED|TERMINATING)))
+ break;
+ }
+ else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
+ s | TERMINATING))
+ break;
+ }
+ }
+
+ /**
+ * Sets state to TERMINATED. Called only by onTermination().
+ */
+ private void setTerminated() {
+ int s;
+ do {} while (!UNSAFE.compareAndSwapInt(this, runStateOffset,
+ s = runState,
+ s | (TERMINATING|TERMINATED)));
+ }
+
+ /**
+ * If suspended, tries to set status to unsuspended.
+ * Does NOT wake up if blocked.
+ *
+ * @return true if successful
+ */
+ final boolean tryUnsuspend() {
+ int s;
+ while (((s = runState) & SUSPENDED) != 0) {
+ if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
+ s & ~SUSPENDED))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sets suspended status and blocks as spare until resumed
+ * or shutdown.
+ */
+ final void suspendAsSpare() {
+ for (;;) { // set suspended unless terminating
+ int s = runState;
+ if ((s & TERMINATING) != 0) { // must kill
+ if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
+ s | (TRIMMED | TERMINATING)))
+ return;
+ }
+ else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
+ s | SUSPENDED))
+ break;
+ }
+ ForkJoinPool p = pool;
+ p.pushSpare(this);
+ while ((runState & SUSPENDED) != 0) {
+ if (p.tryAccumulateStealCount(this)) {
+ interrupted(); // clear/ignore interrupts
+ if ((runState & SUSPENDED) == 0)
+ break;
+ LockSupport.park(this);
+ }
+ }
+ }
+
+ // Misc support methods for ForkJoinPool
+
+ /**
+ * Returns an estimate of the number of tasks in the queue. Also
+ * used by ForkJoinTask.
+ */
+ final int getQueueSize() {
+ int n; // external calls must read base first
+ return (n = -base + sp) <= 0 ? 0 : n;
+ }
/**
* Removes and cancels all tasks in queue. Can be called from any
* thread.
*/
final void cancelTasks() {
- ForkJoinTask<?> t;
- while (base != sp && (t = deqTask()) != null)
- t.cancelIgnoringExceptions();
+ ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
+ if (cj != null) {
+ currentJoin = null;
+ cj.cancelIgnoringExceptions();
+ try {
+ this.interrupt(); // awaken wait
+ } catch (SecurityException ignore) {
+ }
+ }
+ ForkJoinTask<?> cs = currentSteal;
+ if (cs != null) {
+ currentSteal = null;
+ cs.cancelIgnoringExceptions();
+ }
+ while (base != sp) {
+ ForkJoinTask<?> t = deqTask();
+ if (t != null)
+ t.cancelIgnoringExceptions();
+ }
}
/**
@@ -713,87 +902,266 @@
*/
final int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
int n = 0;
- ForkJoinTask<?> t;
- while (base != sp && (t = deqTask()) != null) {
- c.add(t);
- ++n;
+ while (base != sp) {
+ ForkJoinTask<?> t = deqTask();
+ if (t != null) {
+ c.add(t);
+ ++n;
+ }
}
return n;
}
- /**
- * Gets and clears steal count for accumulation by pool. Called
- * only when known to be idle (in pool.sync and termination).
- */
- final int getAndClearStealCount() {
- int sc = stealCount;
- stealCount = 0;
- return sc;
- }
-
- /**
- * Returns {@code true} if at least one worker in the given array
- * appears to have at least one queued task.
- *
- * @param ws array of workers
- */
- static boolean hasQueuedTasks(ForkJoinWorkerThread[] ws) {
- if (ws != null) {
- int len = ws.length;
- for (int j = 0; j < 2; ++j) { // need two passes for clean sweep
- for (int i = 0; i < len; ++i) {
- ForkJoinWorkerThread w = ws[i];
- if (w != null && w.sp != w.base)
- return true;
- }
- }
- }
- return false;
- }
-
// Support methods for ForkJoinTask
/**
- * Returns an estimate of the number of tasks in the queue.
+ * Gets and removes a local task.
+ *
+ * @return a task, if available
+ */
+ final ForkJoinTask<?> pollLocalTask() {
+ ForkJoinPool p = pool;
+ while (sp != base) {
+ int a; // inline p.tryIncrementActiveCount
+ if (active ||
+ (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
+ a = p.runState, a + 1)))
+ return locallyFifo ? locallyDeqTask() : popTask();
+ }
+ return null;
+ }
+
+ /**
+ * Gets and removes a local or stolen task.
+ *
+ * @return a task, if available
+ */
+ final ForkJoinTask<?> pollTask() {
+ ForkJoinTask<?> t = pollLocalTask();
+ if (t == null) {
+ t = scan();
+ // cannot retain/track/help steal
+ UNSAFE.putOrderedObject(this, currentStealOffset, null);
+ }
+ return t;
+ }
+
+ /**
+ * Possibly runs some tasks and/or blocks, until task is done.
+ *
+ * @param joinMe the task to join
*/
- final int getQueueSize() {
- // suppress momentarily negative values
- return Math.max(0, sp - base);
+ final void joinTask(ForkJoinTask<?> joinMe) {
+ // currentJoin only written by this thread; only need ordered store
+ ForkJoinTask<?> prevJoin = currentJoin;
+ UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe);
+ if (sp != base)
+ localHelpJoinTask(joinMe);
+ if (joinMe.status >= 0)
+ pool.awaitJoin(joinMe, this);
+ UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin);
+ }
+
+ /**
+ * Run tasks in local queue until given task is done.
+ *
+ * @param joinMe the task to join
+ */
+ private void localHelpJoinTask(ForkJoinTask<?> joinMe) {
+ int s;
+ ForkJoinTask<?>[] q;
+ while (joinMe.status >= 0 && (s = sp) != base && (q = queue) != null) {
+ int i = (q.length - 1) & --s;
+ long u = (i << qShift) + qBase; // raw offset
+ ForkJoinTask<?> t = q[i];
+ if (t == null) // lost to a stealer
+ break;
+ if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ /*
+ * This recheck (and similarly in helpJoinTask)
+ * handles cases where joinMe is independently
+ * cancelled or forced even though there is other work
+ * available. Back out of the pop by putting t back
+ * into slot before we commit by writing sp.
+ */
+ if (joinMe.status < 0) {
+ UNSAFE.putObjectVolatile(q, u, t);
+ break;
+ }
+ sp = s;
+ // UNSAFE.putOrderedInt(this, spOffset, s);
+ t.quietlyExec();
+ }
+ }
}
/**
- * Returns an estimate of the number of tasks, offset by a
- * function of number of idle workers.
+ * Unless terminating, tries to locate and help perform tasks for
+ * a stealer of the given task, or in turn one of its stealers.
+ * Traces currentSteal->currentJoin links looking for a thread
+ * working on a descendant of the given task and with a non-empty
+ * queue to steal back and execute tasks from.
+ *
+ * The implementation is very branchy to cope with potential
+ * inconsistencies or loops encountering chains that are stale,
+ * unknown, or of length greater than MAX_HELP_DEPTH links. All
+ * of these cases are dealt with by just returning back to the
+ * caller, who is expected to retry if other join mechanisms also
+ * don't work out.
+ *
+ * @param joinMe the task to join
*/
- final int getEstimatedSurplusTaskCount() {
- // The halving approximates weighting idle vs non-idle workers
- return (sp - base) - (pool.getIdleThreadCount() >>> 1);
+ final void helpJoinTask(ForkJoinTask<?> joinMe) {
+ ForkJoinWorkerThread[] ws;
+ int n;
+ if (joinMe.status < 0) // already done
+ return;
+ if ((runState & TERMINATING) != 0) { // cancel if shutting down
+ joinMe.cancelIgnoringExceptions();
+ return;
+ }
+ if ((ws = pool.workers) == null || (n = ws.length) <= 1)
+ return; // need at least 2 workers
+
+ ForkJoinTask<?> task = joinMe; // base of chain
+ ForkJoinWorkerThread thread = this; // thread with stolen task
+ for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
+ // Try to find v, the stealer of task, by first using hint
+ ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
+ if (v == null || v.currentSteal != task) {
+ for (int j = 0; ; ++j) { // search array
+ if (j < n) {
+ ForkJoinTask<?> vs;
+ if ((v = ws[j]) != null &&
+ (vs = v.currentSteal) != null) {
+ if (joinMe.status < 0 || task.status < 0)
+ return; // stale or done
+ if (vs == task) {
+ thread.stealHint = j;
+ break; // save hint for next time
+ }
+ }
+ }
+ else
+ return; // no stealer
+ }
+ }
+ for (;;) { // Try to help v, using specialized form of deqTask
+ if (joinMe.status < 0)
+ return;
+ int b = v.base;
+ ForkJoinTask<?>[] q = v.queue;
+ if (b == v.sp || q == null)
+ break;
+ int i = (q.length - 1) & b;
+ long u = (i << qShift) + qBase;
+ ForkJoinTask<?> t = q[i];
+ int pid = poolIndex;
+ ForkJoinTask<?> ps = currentSteal;
+ if (task.status < 0)
+ return; // stale or done
+ if (t != null && v.base == b++ &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ if (joinMe.status < 0) {
+ UNSAFE.putObjectVolatile(q, u, t);
+ return; // back out on cancel
+ }
+ v.base = b;
+ v.stealHint = pid;
+ UNSAFE.putOrderedObject(this, currentStealOffset, t);
+ t.quietlyExec();
+ UNSAFE.putOrderedObject(this, currentStealOffset, ps);
+ }
+ }
+ // Try to descend to find v's stealer
+ ForkJoinTask<?> next = v.currentJoin;
+ if (task.status < 0 || next == null || next == task ||
+ joinMe.status < 0)
+ return;
+ task = next;
+ thread = v;
+ }
}
/**
- * Scans, returning early if joinMe done.
+ * Implements ForkJoinTask.getSurplusQueuedTaskCount().
+ * Returns an estimate of the number of tasks, offset by a
+ * function of number of idle workers.
+ *
+ * This method provides a cheap heuristic guide for task
+ * partitioning when programmers, frameworks, tools, or languages
+ * have little or no idea about task granularity. In essence by
+ * offering this method, we ask users only about tradeoffs in
+ * overhead vs expected throughput and its variance, rather than
+ * how finely to partition tasks.
+ *
+ * In a steady state strict (tree-structured) computation, each
+ * thread makes available for stealing enough tasks for other
+ * threads to remain active. Inductively, if all threads play by
+ * the same rules, each thread should make available only a
+ * constant number of tasks.
+ *
+ * The minimum useful constant is just 1. But using a value of 1
+ * would require immediate replenishment upon each steal to
+ * maintain enough tasks, which is infeasible. Further,
+ * partitionings/granularities of offered tasks should minimize
+ * steal rates, which in general means that threads nearer the top
+ * of computation tree should generate more than those nearer the
+ * bottom. In perfect steady state, each thread is at
+ * approximately the same level of computation tree. However,
+ * producing extra tasks amortizes the uncertainty of progress and
+ * diffusion assumptions.
+ *
+ * So, users will want to use values larger, but not much larger
+ * than 1 to both smooth over transient shortages and hedge
+ * against uneven progress; as traded off against the cost of
+ * extra task overhead. We leave the user to pick a threshold
+ * value to compare with the results of this call to guide
+ * decisions, but recommend values such as 3.
+ *
+ * When all threads are active, it is on average OK to estimate
+ * surplus strictly locally. In steady-state, if one thread is
+ * maintaining say 2 surplus tasks, then so are others. So we can
+ * just use estimated queue length (although note that (sp - base)
+ * can be an overestimate because of stealers lagging increments
+ * of base). However, this strategy alone leads to serious
+ * mis-estimates in some non-steady-state conditions (ramp-up,
+ * ramp-down, other stalls). We can detect many of these by
+ * further considering the number of "idle" threads, that are
+ * known to have zero queued tasks, so compensate by a factor of
+ * (#idle/#active) threads.
*/
- final ForkJoinTask<?> scanWhileJoining(ForkJoinTask<?> joinMe) {
- ForkJoinTask<?> t = pollTask();
- if (t != null && joinMe.status < 0 && sp == base) {
- pushTask(t); // unsteal if done and this task would be stealable
- t = null;
- }
- return t;
+ final int getEstimatedSurplusTaskCount() {
+ return sp - base - pool.idlePerActive();
}
/**
* Runs tasks until {@code pool.isQuiescent()}.
*/
final void helpQuiescePool() {
+ ForkJoinTask<?> ps = currentSteal; // to restore below
for (;;) {
- ForkJoinTask<?> t = pollTask();
- if (t != null)
+ ForkJoinTask<?> t = pollLocalTask();
+ if (t != null || (t = scan()) != null)
t.quietlyExec();
- else if (tryInactivate() && pool.isQuiescent())
- break;
+ else {
+ ForkJoinPool p = pool;
+ int a; // to inline CASes
+ if (active) {
+ if (!UNSAFE.compareAndSwapInt
+ (p, poolRunStateOffset, a = p.runState, a - 1))
+ continue; // retry later
+ active = false; // inactivate
+ UNSAFE.putOrderedObject(this, currentStealOffset, ps);
+ }
+ if (p.isQuiescent()) {
+ active = true; // re-activate
+ do {} while (!UNSAFE.compareAndSwapInt
+ (p, poolRunStateOffset, a = p.runState, a+1));
+ return;
+ }
+ }
}
- do {} while (!tryActivate()); // re-activate on exit
}
// Unsafe mechanics
@@ -803,15 +1171,23 @@
objectFieldOffset("sp", ForkJoinWorkerThread.class);
private static final long runStateOffset =
objectFieldOffset("runState", ForkJoinWorkerThread.class);
- private static final long qBase;
+ private static final long currentJoinOffset =
+ objectFieldOffset("currentJoin", ForkJoinWorkerThread.class);
+ private static final long currentStealOffset =
+ objectFieldOffset("currentSteal", ForkJoinWorkerThread.class);
+ private static final long qBase =
+ UNSAFE.arrayBaseOffset(ForkJoinTask[].class);
+ private static final long poolRunStateOffset = // to inline CAS
+ objectFieldOffset("runState", ForkJoinPool.class);
+
private static final int qShift;
static {
- qBase = UNSAFE.arrayBaseOffset(ForkJoinTask[].class);
int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class);
if ((s & (s-1)) != 0)
throw new Error("data type scale not a power of two");
qShift = 31 - Integer.numberOfLeadingZeros(s);
+ MAXIMUM_QUEUE_CAPACITY = 1 << (31 - qShift);
}
private static long objectFieldOffset(String field, Class<?> klazz) {
--- a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java Thu Sep 16 11:19:43 2010 -0700
@@ -42,6 +42,7 @@
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.concurrent.locks.LockSupport;
+
/**
* An unbounded {@link TransferQueue} based on linked nodes.
* This queue orders elements FIFO (first-in-first-out) with respect
@@ -233,24 +234,6 @@
* additional GC bookkeeping ("write barriers") that are sometimes
* more costly than the writes themselves because of contention).
*
- * Removal of interior nodes (due to timed out or interrupted
- * waits, or calls to remove(x) or Iterator.remove) can use a
- * scheme roughly similar to that described in Scherer, Lea, and
- * Scott's SynchronousQueue. Given a predecessor, we can unsplice
- * any node except the (actual) tail of the queue. To avoid
- * build-up of cancelled trailing nodes, upon a request to remove
- * a trailing node, it is placed in field "cleanMe" to be
- * unspliced upon the next call to unsplice any other node.
- * Situations needing such mechanics are not common but do occur
- * in practice; for example when an unbounded series of short
- * timed calls to poll repeatedly time out but never otherwise
- * fall off the list because of an untimed call to take at the
- * front of the queue. Note that maintaining field cleanMe does
- * not otherwise much impact garbage retention even if never
- * cleared by some other call because the held node will
- * eventually either directly or indirectly lead to a self-link
- * once off the list.
- *
* *** Overview of implementation ***
*
* We use a threshold-based approach to updates, with a slack
@@ -266,15 +249,10 @@
* per-thread one available, but even ThreadLocalRandom is too
* heavy for these purposes.
*
- * With such a small slack threshold value, it is rarely
- * worthwhile to augment this with path short-circuiting; i.e.,
- * unsplicing nodes between head and the first unmatched node, or
- * similarly for tail, rather than advancing head or tail
- * proper. However, it is used (in awaitMatch) immediately before
- * a waiting thread starts to block, as a final bit of helping at
- * a point when contention with others is extremely unlikely
- * (since if other threads that could release it are operating,
- * then the current thread wouldn't be blocking).
+ * With such a small slack threshold value, it is not worthwhile
+ * to augment this with path short-circuiting (i.e., unsplicing
+ * interior nodes) except in the case of cancellation/removal (see
+ * below).
*
* We allow both the head and tail fields to be null before any
* nodes are enqueued; initializing upon first append. This
@@ -356,6 +334,70 @@
* versa) compared to their predecessors receive additional
* chained spins, reflecting longer paths typically required to
* unblock threads during phase changes.
+ *
+ *
+ * ** Unlinking removed interior nodes **
+ *
+ * In addition to minimizing garbage retention via self-linking
+ * described above, we also unlink removed interior nodes. These
+ * may arise due to timed out or interrupted waits, or calls to
+ * remove(x) or Iterator.remove. Normally, given a node that was
+ * at one time known to be the predecessor of some node s that is
+ * to be removed, we can unsplice s by CASing the next field of
+ * its predecessor if it still points to s (otherwise s must
+ * already have been removed or is now offlist). But there are two
+ * situations in which we cannot guarantee to make node s
+ * unreachable in this way: (1) If s is the trailing node of list
+ * (i.e., with null next), then it is pinned as the target node
+ * for appends, so can only be removed later after other nodes are
+ * appended. (2) We cannot necessarily unlink s given a
+ * predecessor node that is matched (including the case of being
+ * cancelled): the predecessor may already be unspliced, in which
+ * case some previous reachable node may still point to s.
+ * (For further explanation see Herlihy & Shavit "The Art of
+ * Multiprocessor Programming" chapter 9). Although, in both
+ * cases, we can rule out the need for further action if either s
+ * or its predecessor are (or can be made to be) at, or fall off
+ * from, the head of list.
+ *
+ * Without taking these into account, it would be possible for an
+ * unbounded number of supposedly removed nodes to remain
+ * reachable. Situations leading to such buildup are uncommon but
+ * can occur in practice; for example when a series of short timed
+ * calls to poll repeatedly time out but never otherwise fall off
+ * the list because of an untimed call to take at the front of the
+ * queue.
+ *
+ * When these cases arise, rather than always retraversing the
+ * entire list to find an actual predecessor to unlink (which
+ * won't help for case (1) anyway), we record a conservative
+ * estimate of possible unsplice failures (in "sweepVotes").
+ * We trigger a full sweep when the estimate exceeds a threshold
+ * ("SWEEP_THRESHOLD") indicating the maximum number of estimated
+ * removal failures to tolerate before sweeping through, unlinking
+ * cancelled nodes that were not unlinked upon initial removal.
+ * We perform sweeps by the thread hitting threshold (rather than
+ * background threads or by spreading work to other threads)
+ * because in the main contexts in which removal occurs, the
+ * caller is already timed-out, cancelled, or performing a
+ * potentially O(n) operation (e.g. remove(x)), none of which are
+ * time-critical enough to warrant the overhead that alternatives
+ * would impose on other threads.
+ *
+ * Because the sweepVotes estimate is conservative, and because
+ * nodes become unlinked "naturally" as they fall off the head of
+ * the queue, and because we allow votes to accumulate even while
+ * sweeps are in progress, there are typically significantly fewer
+ * such nodes than estimated. Choice of a threshold value
+ * balances the likelihood of wasted effort and contention, versus
+ * providing a worst-case bound on retention of interior nodes in
+ * quiescent queues. The value defined below was chosen
+ * empirically to balance these under various timeout scenarios.
+ *
+ * Note that we cannot self-link unlinked interior nodes during
+ * sweeps. However, the associated garbage chains terminate when
+ * some successor ultimately falls off the head of the list and is
+ * self-linked.
*/
/** True if on multiprocessor */
@@ -382,11 +424,19 @@
private static final int CHAINED_SPINS = FRONT_SPINS >>> 1;
/**
+ * The maximum number of estimated removal failures (sweepVotes)
+ * to tolerate before sweeping through the queue unlinking
+ * cancelled nodes that were not unlinked upon initial
+ * removal. See above for explanation. The value must be at least
+ * two to avoid useless sweeps when removing trailing nodes.
+ */
+ static final int SWEEP_THRESHOLD = 32;
+
+ /**
* Queue nodes. Uses Object, not E, for items to allow forgetting
* them after use. Relies heavily on Unsafe mechanics to minimize
- * unnecessary ordering constraints: Writes that intrinsically
- * precede or follow CASes use simple relaxed forms. Other
- * cleanups use releasing/lazy writes.
+ * unnecessary ordering constraints: Writes that are intrinsically
+ * ordered wrt other accesses or CASes use simple relaxed forms.
*/
static final class Node {
final boolean isData; // false if this is a request node
@@ -400,13 +450,13 @@
}
final boolean casItem(Object cmp, Object val) {
- // assert cmp == null || cmp.getClass() != Node.class;
+ // assert cmp == null || cmp.getClass() != Node.class;
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
/**
- * Creates a new node. Uses relaxed write because item can only
- * be seen if followed by CAS.
+ * Constructs a new node. Uses relaxed write because item can
+ * only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
UNSAFE.putObject(this, itemOffset, item); // relaxed write
@@ -422,13 +472,17 @@
}
/**
- * Sets item to self (using a releasing/lazy write) and waiter
- * to null, to avoid garbage retention after extracting or
- * cancelling.
+ * Sets item to self and waiter to null, to avoid garbage
+ * retention after matching or cancelling. Uses relaxed writes
+ * because order is already constrained in the only calling
+ * contexts: item is forgotten only after volatile/atomic
+ * mechanics that extract items. Similarly, clearing waiter
+ * follows either CAS or return from park (if ever parked;
+ * else we don't care).
*/
final void forgetContents() {
- UNSAFE.putOrderedObject(this, itemOffset, this);
- UNSAFE.putOrderedObject(this, waiterOffset, null);
+ UNSAFE.putObject(this, itemOffset, this);
+ UNSAFE.putObject(this, waiterOffset, null);
}
/**
@@ -462,7 +516,7 @@
* Tries to artificially match a data node -- used by remove.
*/
final boolean tryMatchData() {
- // assert isData;
+ // assert isData;
Object x = item;
if (x != null && x != this && casItem(x, null)) {
LockSupport.unpark(waiter);
@@ -486,12 +540,12 @@
/** head of the queue; null until first enqueue */
transient volatile Node head;
- /** predecessor of dangling unspliceable node */
- private transient volatile Node cleanMe; // decl here reduces contention
-
/** tail of the queue; null until first append */
private transient volatile Node tail;
+ /** The number of apparent failures to unsplice removed nodes */
+ private transient volatile int sweepVotes;
+
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
@@ -501,8 +555,8 @@
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
}
- private boolean casCleanMe(Node cmp, Node val) {
- return UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
+ private boolean casSweepVotes(int cmp, int val) {
+ return UNSAFE.compareAndSwapInt(this, sweepVotesOffset, cmp, val);
}
/*
@@ -515,7 +569,7 @@
@SuppressWarnings("unchecked")
static <E> E cast(Object item) {
- // assert item == null || item.getClass() != Node.class;
+ // assert item == null || item.getClass() != Node.class;
return (E) item;
}
@@ -544,10 +598,8 @@
break;
if (p.casItem(item, e)) { // match
for (Node q = p; q != h;) {
- Node n = q.next; // update head by 2
- if (n != null) // unless singleton
- q = n;
- if (head == h && casHead(h, q)) {
+ Node n = q.next; // update by 2 unless singleton
+ if (head == h && casHead(h, n == null? q : n)) {
h.forgetNext();
break;
} // advance and retry
@@ -632,12 +684,12 @@
for (;;) {
Object item = s.item;
if (item != e) { // matched
- // assert item != s;
+ // assert item != s;
s.forgetContents(); // avoid garbage
return this.<E>cast(item);
}
if ((w.isInterrupted() || (timed && nanos <= 0)) &&
- s.casItem(e, s)) { // cancel
+ s.casItem(e, s)) { // cancel
unsplice(pred, s);
return e;
}
@@ -647,9 +699,8 @@
randomYields = ThreadLocalRandom.current();
}
else if (spins > 0) { // spin
- if (--spins == 0)
- shortenHeadPath(); // reduce slack before blocking
- else if (randomYields.nextInt(CHAINED_SPINS) == 0)
+ --spins;
+ if (randomYields.nextInt(CHAINED_SPINS) == 0)
Thread.yield(); // occasionally yield
}
else if (s.waiter == null) {
@@ -663,8 +714,6 @@
}
else {
LockSupport.park(this);
- s.waiter = null;
- spins = -1; // spin if front upon wakeup
}
}
}
@@ -685,27 +734,6 @@
return 0;
}
- /**
- * Tries (once) to unsplice nodes between head and first unmatched
- * or trailing node; failing on contention.
- */
- private void shortenHeadPath() {
- Node h, hn, p, q;
- if ((p = h = head) != null && h.isMatched() &&
- (q = hn = h.next) != null) {
- Node n;
- while ((n = q.next) != q) {
- if (n == null || !q.isMatched()) {
- if (hn != q && h.next == hn)
- h.casNext(hn, q);
- break;
- }
- p = q;
- q = n;
- }
- }
- }
-
/* -------------- Traversal methods -------------- */
/**
@@ -818,7 +846,8 @@
public final void remove() {
Node p = lastRet;
if (p == null) throw new IllegalStateException();
- findAndRemoveDataNode(lastPred, p);
+ if (p.tryMatchData())
+ unsplice(lastPred, p);
}
}
@@ -828,99 +857,68 @@
* Unsplices (now or later) the given deleted/cancelled node with
* the given predecessor.
*
- * @param pred predecessor of node to be unspliced
+ * @param pred a node that was at one time known to be the
+ * predecessor of s, or null or s itself if s is/was at head
* @param s the node to be unspliced
*/
- private void unsplice(Node pred, Node s) {
- s.forgetContents(); // clear unneeded fields
+ final void unsplice(Node pred, Node s) {
+ s.forgetContents(); // forget unneeded fields
/*
- * At any given time, exactly one node on list cannot be
- * unlinked -- the last inserted node. To accommodate this, if
- * we cannot unlink s, we save its predecessor as "cleanMe",
- * processing the previously saved version first. Because only
- * one node in the list can have a null next, at least one of
- * node s or the node previously saved can always be
- * processed, so this always terminates.
+ * See above for rationale. Briefly: if pred still points to
+ * s, try to unlink s. If s cannot be unlinked, because it is
+ * trailing node or pred might be unlinked, and neither pred
+ * nor s are head or offlist, add to sweepVotes, and if enough
+ * votes have accumulated, sweep.
*/
- if (pred != null && pred != s) {
- while (pred.next == s) {
- Node oldpred = (cleanMe == null) ? null : reclean();
- Node n = s.next;
- if (n != null) {
- if (n != s)
- pred.casNext(s, n);
- break;
+ if (pred != null && pred != s && pred.next == s) {
+ Node n = s.next;
+ if (n == null ||
+ (n != s && pred.casNext(s, n) && pred.isMatched())) {
+ for (;;) { // check if at, or could be, head
+ Node h = head;
+ if (h == pred || h == s || h == null)
+ return; // at head or list empty
+ if (!h.isMatched())
+ break;
+ Node hn = h.next;
+ if (hn == null)
+ return; // now empty
+ if (hn != h && casHead(h, hn))
+ h.forgetNext(); // advance head
}
- if (oldpred == pred || // Already saved
- ((oldpred == null || oldpred.next == s) &&
- casCleanMe(oldpred, pred))) {
- break;
+ if (pred.next != pred && s.next != s) { // recheck if offlist
+ for (;;) { // sweep now if enough votes
+ int v = sweepVotes;
+ if (v < SWEEP_THRESHOLD) {
+ if (casSweepVotes(v, v + 1))
+ break;
+ }
+ else if (casSweepVotes(v, 0)) {
+ sweep();
+ break;
+ }
+ }
}
}
}
}
/**
- * Tries to unsplice the deleted/cancelled node held in cleanMe
- * that was previously uncleanable because it was at tail.
- *
- * @return current cleanMe node (or null)
+ * Unlinks matched (typically cancelled) nodes encountered in a
+ * traversal from head.
*/
- private Node reclean() {
- /*
- * cleanMe is, or at one time was, predecessor of a cancelled
- * node s that was the tail so could not be unspliced. If it
- * is no longer the tail, try to unsplice if necessary and
- * make cleanMe slot available. This differs from similar
- * code in unsplice() because we must check that pred still
- * points to a matched node that can be unspliced -- if not,
- * we can (must) clear cleanMe without unsplicing. This can
- * loop only due to contention.
- */
- Node pred;
- while ((pred = cleanMe) != null) {
- Node s = pred.next;
- Node n;
- if (s == null || s == pred || !s.isMatched())
- casCleanMe(pred, null); // already gone
- else if ((n = s.next) != null) {
- if (n != s)
- pred.casNext(s, n);
- casCleanMe(pred, null);
- }
- else
+ private void sweep() {
+ for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
+ if (!s.isMatched())
+ // Unmatched nodes are never self-linked
+ p = s;
+ else if ((n = s.next) == null) // trailing node is pinned
break;
- }
- return pred;
- }
-
- /**
- * Main implementation of Iterator.remove(). Finds
- * and unsplices the given data node.
- *
- * @param possiblePred possible predecessor of s
- * @param s the node to remove
- */
- final void findAndRemoveDataNode(Node possiblePred, Node s) {
- // assert s.isData;
- if (s.tryMatchData()) {
- if (possiblePred != null && possiblePred.next == s)
- unsplice(possiblePred, s); // was actual predecessor
- else {
- for (Node pred = null, p = head; p != null; ) {
- if (p == s) {
- unsplice(pred, p);
- break;
- }
- if (p.isUnmatchedRequest())
- break;
- pred = p;
- if ((p = p.next) == pred) { // stale
- pred = null;
- p = head;
- }
- }
- }
+ else if (s == n) // stale
+ // No need to also check for p == s, since that implies s == n
+ p = head;
+ else
+ p.casNext(s, n);
}
}
@@ -1158,7 +1156,11 @@
* @return {@code true} if this queue contains no elements
*/
public boolean isEmpty() {
- return firstOfMode(true) == null;
+ for (Node p = head; p != null; p = succ(p)) {
+ if (!p.isMatched())
+ return !p.isData;
+ }
+ return true;
}
public boolean hasWaitingConsumer() {
@@ -1252,8 +1254,8 @@
objectFieldOffset(UNSAFE, "head", LinkedTransferQueue.class);
private static final long tailOffset =
objectFieldOffset(UNSAFE, "tail", LinkedTransferQueue.class);
- private static final long cleanMeOffset =
- objectFieldOffset(UNSAFE, "cleanMe", LinkedTransferQueue.class);
+ private static final long sweepVotesOffset =
+ objectFieldOffset(UNSAFE, "sweepVotes", LinkedTransferQueue.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
@@ -1266,5 +1268,4 @@
throw error;
}
}
-
}
--- a/jdk/src/share/classes/java/util/concurrent/Phaser.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/Phaser.java Thu Sep 16 11:19:43 2010 -0700
@@ -898,7 +898,7 @@
boolean doWait() {
if (thread != null) {
try {
- ForkJoinPool.managedBlock(this, false);
+ ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
}
}
--- a/jdk/src/share/classes/javax/sql/CommonDataSource.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/javax/sql/CommonDataSource.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
import java.sql.SQLException;
import java.io.PrintWriter;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
/**
* Interface that defines the methods which are common between <code>DataSource</code>,
@@ -35,79 +37,93 @@
*/
public interface CommonDataSource {
- /**
- * <p>Retrieves the log writer for this <code>DataSource</code>
- * object.
- *
- * <p>The log writer is a character output stream to which all logging
- * and tracing messages for this data source will be
- * printed. This includes messages printed by the methods of this
- * object, messages printed by methods of other objects manufactured
- * by this object, and so on. Messages printed to a data source
- * specific log writer are not printed to the log writer associated
- * with the <code>java.sql.DriverManager</code> class. When a
- * <code>DataSource</code> object is
- * created, the log writer is initially null; in other words, the
- * default is for logging to be disabled.
- *
- * @return the log writer for this data source or null if
- * logging is disabled
- * @exception java.sql.SQLException if a database access error occurs
- * @see #setLogWriter
- * @since 1.4
- */
- java.io.PrintWriter getLogWriter() throws SQLException;
+ /**
+ * <p>Retrieves the log writer for this <code>DataSource</code>
+ * object.
+ *
+ * <p>The log writer is a character output stream to which all logging
+ * and tracing messages for this data source will be
+ * printed. This includes messages printed by the methods of this
+ * object, messages printed by methods of other objects manufactured
+ * by this object, and so on. Messages printed to a data source
+ * specific log writer are not printed to the log writer associated
+ * with the <code>java.sql.DriverManager</code> class. When a
+ * <code>DataSource</code> object is
+ * created, the log writer is initially null; in other words, the
+ * default is for logging to be disabled.
+ *
+ * @return the log writer for this data source or null if
+ * logging is disabled
+ * @exception java.sql.SQLException if a database access error occurs
+ * @see #setLogWriter
+ * @since 1.4
+ */
+ java.io.PrintWriter getLogWriter() throws SQLException;
+
+ /**
+ * <p>Sets the log writer for this <code>DataSource</code>
+ * object to the given <code>java.io.PrintWriter</code> object.
+ *
+ * <p>The log writer is a character output stream to which all logging
+ * and tracing messages for this data source will be
+ * printed. This includes messages printed by the methods of this
+ * object, messages printed by methods of other objects manufactured
+ * by this object, and so on. Messages printed to a data source-
+ * specific log writer are not printed to the log writer associated
+ * with the <code>java.sql.DriverManager</code> class. When a
+ * <code>DataSource</code> object is created the log writer is
+ * initially null; in other words, the default is for logging to be
+ * disabled.
+ *
+ * @param out the new log writer; to disable logging, set to null
+ * @exception SQLException if a database access error occurs
+ * @see #getLogWriter
+ * @since 1.4
+ */
+ void setLogWriter(java.io.PrintWriter out) throws SQLException;
- /**
- * <p>Sets the log writer for this <code>DataSource</code>
- * object to the given <code>java.io.PrintWriter</code> object.
- *
- * <p>The log writer is a character output stream to which all logging
- * and tracing messages for this data source will be
- * printed. This includes messages printed by the methods of this
- * object, messages printed by methods of other objects manufactured
- * by this object, and so on. Messages printed to a data source-
- * specific log writer are not printed to the log writer associated
- * with the <code>java.sql.DriverManager</code> class. When a
- * <code>DataSource</code> object is created the log writer is
- * initially null; in other words, the default is for logging to be
- * disabled.
- *
- * @param out the new log writer; to disable logging, set to null
- * @exception SQLException if a database access error occurs
- * @see #getLogWriter
- * @since 1.4
- */
- void setLogWriter(java.io.PrintWriter out) throws SQLException;
+ /**
+ * <p>Sets the maximum time in seconds that this data source will wait
+ * while attempting to connect to a database. A value of zero
+ * specifies that the timeout is the default system timeout
+ * if there is one; otherwise, it specifies that there is no timeout.
+ * When a <code>DataSource</code> object is created, the login timeout is
+ * initially zero.
+ *
+ * @param seconds the data source login time limit
+ * @exception SQLException if a database access error occurs.
+ * @see #getLoginTimeout
+ * @since 1.4
+ */
+ void setLoginTimeout(int seconds) throws SQLException;
- /**
- * <p>Sets the maximum time in seconds that this data source will wait
- * while attempting to connect to a database. A value of zero
- * specifies that the timeout is the default system timeout
- * if there is one; otherwise, it specifies that there is no timeout.
- * When a <code>DataSource</code> object is created, the login timeout is
- * initially zero.
- *
- * @param seconds the data source login time limit
- * @exception SQLException if a database access error occurs.
- * @see #getLoginTimeout
- * @since 1.4
- */
- void setLoginTimeout(int seconds) throws SQLException;
+ /**
+ * Gets the maximum time in seconds that this data source can wait
+ * while attempting to connect to a database. A value of zero
+ * means that the timeout is the default system timeout
+ * if there is one; otherwise, it means that there is no timeout.
+ * When a <code>DataSource</code> object is created, the login timeout is
+ * initially zero.
+ *
+ * @return the data source login time limit
+ * @exception SQLException if a database access error occurs.
+ * @see #setLoginTimeout
+ * @since 1.4
+ */
+ int getLoginTimeout() throws SQLException;
- /**
- * Gets the maximum time in seconds that this data source can wait
- * while attempting to connect to a database. A value of zero
- * means that the timeout is the default system timeout
- * if there is one; otherwise, it means that there is no timeout.
- * When a <code>DataSource</code> object is created, the login timeout is
- * initially zero.
- *
- * @return the data source login time limit
- * @exception SQLException if a database access error occurs.
- * @see #setLoginTimeout
- * @since 1.4
- */
- int getLoginTimeout() throws SQLException;
+ //------------------------- JDBC 4.1 -----------------------------------
+ /**
+ * Return the parent Logger of all the Loggers used by this data source. This
+ * should be the Logger farthest from the root Logger that is
+ * still an ancestor of all of the Loggers used by this data source. Configuring
+ * this Logger will affect all of the log messages generated by the data source.
+ * In the worst case, this may be the root Logger.
+ *
+ * @return the parent Logger for this data source
+ * @throws SQLFeatureNotSupportedException if the data source does not use <code>java.util.logging<code>.
+ * @since 1.7
+ */
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException;
}
--- a/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/javax/sql/rowset/CachedRowSet.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -644,10 +644,10 @@
* of <code>execute</code> that takes a <code>ResultSet</code> object.
*
* @param data the <code>ResultSet</code> object containing the data
- * to be read into this <code>CachedRowSet</code> object
+ * to be read into this <code>CachedRowSet</code> object
* @throws SQLException if a null <code>ResultSet</code> object is supplied
- * or this <code>CachedRowSet</code> object cannot
- * retrieve the associated <code>ResultSetMetaData</code> object
+ * or this <code>CachedRowSet</code> object cannot
+ * retrieve the associated <code>ResultSetMetaData</code> object
* @see #execute
* @see java.sql.ResultSet
* @see java.sql.ResultSetMetaData
@@ -674,10 +674,10 @@
* to commit outstanding updates, those updates are lost.
*
* @param conn a standard JDBC <code>Connection</code> object with valid
- * properties
+ * properties
* @throws SQLException if an invalid <code>Connection</code> object is supplied
- * or an error occurs in establishing the connection to the
- * data source
+ * or an error occurs in establishing the connection to the
+ * data source
* @see #populate
* @see java.sql.Connection
*/
@@ -736,8 +736,8 @@
*
* @throws SQLException if the cursor is on the insert row
* @throws SyncProviderException if the underlying
- * synchronization provider's writer fails to write the updates
- * back to the data source
+ * synchronization provider's writer fails to write the updates
+ * back to the data source
* @see #acceptChanges(java.sql.Connection)
* @see javax.sql.RowSetWriter
* @see javax.sql.rowset.spi.SyncFactory
@@ -807,8 +807,8 @@
* @param con a standard JDBC <code>Connection</code> object
* @throws SQLException if the cursor is on the insert row
* @throws SyncProviderException if the underlying
- * synchronization provider's writer fails to write the updates
- * back to the data source
+ * synchronization provider's writer fails to write the updates
+ * back to the data source
* @see #acceptChanges()
* @see javax.sql.RowSetWriter
* @see javax.sql.rowset.spi.SyncFactory
@@ -867,7 +867,7 @@
* the rowset's Java VM resources.
*
* @throws SQLException if an error occurs flushing the contents of this
- * <code>CachedRowSet</code> object
+ * <code>CachedRowSet</code> object
* @see javax.sql.RowSetListener#rowSetChanged
* @see java.sql.ResultSet#close
*/
@@ -948,9 +948,9 @@
*
* @param idx an <code>int</code> identifying the column to be checked for updates
* @return <code>true</code> if the designated column has been visibly updated;
- * <code>false</code> otherwise
+ * <code>false</code> otherwise
* @throws SQLException if the cursor is on the insert row, before the first row,
- * or after the last row
+ * or after the last row
* @see java.sql.DatabaseMetaData#updatesAreDetected
*/
public boolean columnUpdated(int idx) throws SQLException;
@@ -963,9 +963,9 @@
* @param columnName a <code>String</code> object giving the name of the
* column to be checked for updates
* @return <code>true</code> if the column has been visibly updated;
- * <code>false</code> otherwise
+ * <code>false</code> otherwise
* @throws SQLException if the cursor is on the insert row, before the first row,
- * or after the last row
+ * or after the last row
* @see java.sql.DatabaseMetaData#updatesAreDetected
*/
public boolean columnUpdated(String columnName) throws SQLException;
@@ -1003,7 +1003,7 @@
* <P>
*
* @return a <code>Collection</code> object that contains the values in
- * each row in this <code>CachedRowSet</code> object
+ * each row in this <code>CachedRowSet</code> object
* @throws SQLException if an error occurs generating the collection
* @see #toCollection(int)
* @see #toCollection(String)
@@ -1030,10 +1030,10 @@
* @param column an <code>int</code> indicating the column whose values
* are to be represented in a <code>Collection</code> object
* @return a <code>Collection</code> object that contains the values
- * stored in the specified column of this <code>CachedRowSet</code>
- * object
+ * stored in the specified column of this <code>CachedRowSet</code>
+ * object
* @throws SQLException if an error occurs generating the collection or
- * an invalid column id is provided
+ * an invalid column id is provided
* @see #toCollection
* @see #toCollection(String)
*/
@@ -1059,10 +1059,10 @@
* @param column a <code>String</code> object giving the name of the
* column whose values are to be represented in a collection
* @return a <code>Collection</code> object that contains the values
- * stored in the specified column of this <code>CachedRowSet</code>
- * object
+ * stored in the specified column of this <code>CachedRowSet</code>
+ * object
* @throws SQLException if an error occurs generating the collection or
- * an invalid column id is provided
+ * an invalid column id is provided
* @see #toCollection
* @see #toCollection(int)
*/
@@ -1100,7 +1100,7 @@
* @return the <code>SyncProvider</code> object that was set when the rowset
* was instantiated, or if none was was set, the default provider
* @throws SQLException if an error occurs while returning the
- * <code>SyncProvider</code> object
+ * <code>SyncProvider</code> object
* @see #setSyncProvider
*/
public SyncProvider getSyncProvider() throws SQLException;
@@ -1127,7 +1127,7 @@
* @param provider a <code>String</code> object giving the fully qualified class
* name of a <code>SyncProvider</code> implementation
* @throws SQLException if an error occurs while attempting to reset the
- * <code>SyncProvider</code> implementation
+ * <code>SyncProvider</code> implementation
* @see #getSyncProvider
*/
public void setSyncProvider(String provider) throws SQLException;
@@ -1152,9 +1152,9 @@
* object to the rowset.
*
* @param md a <code>RowSetMetaData</code> object containing
- * metadata about the columns in this <code>CachedRowSet</code> object
+ * metadata about the columns in this <code>CachedRowSet</code> object
* @throws SQLException if invalid metadata is supplied to the
- * rowset
+ * rowset
*/
public void setMetaData(RowSetMetaData md) throws SQLException;
@@ -1183,7 +1183,7 @@
* @return a <code>ResultSet</code> object that contains the original value for
* this <code>CachedRowSet</code> object
* @throws SQLException if an error occurs producing the
- * <code>ResultSet</code> object
+ * <code>ResultSet</code> object
*/
public ResultSet getOriginal() throws SQLException;
@@ -1217,7 +1217,7 @@
* A call to <code>setOriginalRow</code> is irreversible.
*
* @throws SQLException if there is no current row or an error is
- * encountered resetting the contents of the original row
+ * encountered resetting the contents of the original row
* @see #getOriginalRow
*/
public void setOriginalRow() throws SQLException;
@@ -1326,7 +1326,7 @@
* as this <code>CachedRowSet</code> object and that has a cursor over
* the same data
* @throws SQLException if an error occurs or cloning is not
- * supported in the underlying platform
+ * supported in the underlying platform
* @see javax.sql.RowSetEvent
* @see javax.sql.RowSetListener
*/
@@ -1344,10 +1344,10 @@
* established must be maintained.
*
* @return a new <code>RowSet</code> object that is a deep copy
- * of this <code>CachedRowSet</code> object and is
- * completely independent of this <code>CachedRowSet</code> object
+ * of this <code>CachedRowSet</code> object and is
+ * completely independent of this <code>CachedRowSet</code> object
* @throws SQLException if an error occurs in generating the copy of
- * the of this <code>CachedRowSet</code> object
+ * the of this <code>CachedRowSet</code> object
* @see #createShared
* @see #createCopySchema
* @see #createCopyNoConstraints
@@ -1396,10 +1396,10 @@
* in the copy.
*
* @return a new <code>CachedRowSet</code> object that is a deep copy
- * of this <code>CachedRowSet</code> object and is
- * completely independent of this <code>CachedRowSet</code> object
+ * of this <code>CachedRowSet</code> object and is
+ * completely independent of this <code>CachedRowSet</code> object
* @throws SQLException if an error occurs in generating the copy of
- * the of this <code>CachedRowSet</code> object
+ * the of this <code>CachedRowSet</code> object
* @see #createCopy
* @see #createShared
* @see #createCopySchema
@@ -1445,7 +1445,7 @@
* @return <code>true</code> if deleted rows are visible;
* <code>false</code> otherwise
* @throws SQLException if a rowset implementation is unable to
- * to determine whether rows marked for deletion are visible
+ * to determine whether rows marked for deletion are visible
* @see #setShowDeleted
*/
public boolean getShowDeleted() throws SQLException;
@@ -1467,7 +1467,7 @@
* @param b <code>true</code> if deleted rows should be shown;
* <code>false</code> otherwise
* @exception SQLException if a rowset implementation is unable to
- * to reset whether deleted rows should be visible
+ * to reset whether deleted rows should be visible
* @see #getShowDeleted
*/
public void setShowDeleted(boolean b) throws SQLException;
@@ -1523,9 +1523,12 @@
* set to false, the changes will <b>not</b> be committed until one of the
* <code>CachedRowSet</code> interface transaction methods is called.
*
+ * @deprecated Because this field is final (it is part of an interface),
+ * its value cannot be changed.
* @see #commit
* @see #rollback
*/
+ @Deprecated
public static final boolean COMMIT_ON_ACCEPT_CHANGES = true;
/**
@@ -1562,10 +1565,10 @@
* @param startRow the position in the <code>ResultSet</code> from where to start
* populating the records in this <code>CachedRowSet</code>
* @param rs the <code>ResultSet</code> object containing the data
- * to be read into this <code>CachedRowSet</code> object
+ * to be read into this <code>CachedRowSet</code> object
* @throws SQLException if a null <code>ResultSet</code> object is supplied
- * or this <code>CachedRowSet</code> object cannot
- * retrieve the associated <code>ResultSetMetaData</code> object
+ * or this <code>CachedRowSet</code> object cannot
+ * retrieve the associated <code>ResultSetMetaData</code> object
* @see #execute
* @see #populate(ResultSet)
* @see java.sql.ResultSet
@@ -1620,3 +1623,4 @@
public boolean previousPage() throws SQLException;
}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/sql/rowset/RowSetFactory.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.sql.rowset;
+
+import java.sql.SQLException;
+
+/**
+ * An interface that defines the implementation of a factory that is used
+ * to obtain different types of {@code RowSet} implementations.
+ *
+ * @author Lance Andersen
+ * @since 1.7
+ */
+public interface RowSetFactory{
+
+ /**
+ * <p>Creates a new instance of a CachedRowSet.</p>
+ *
+ * @return A new instance of a CachedRowSet.
+ *
+ * @throws SQLException if a CachedRowSet cannot
+ * be created.
+ *
+ * @since 1.7
+ */
+ public CachedRowSet createCachedRowSet() throws SQLException;
+
+ /**
+ * <p>Creates a new instance of a FilteredRowSet.</p>
+ *
+ * @return A new instance of a FilteredRowSet.
+ *
+ * @throws SQLException if a FilteredRowSet cannot
+ * be created.
+ *
+ * @since 1.7
+ */
+ public FilteredRowSet createFilteredRowSet() throws SQLException;
+
+ /**
+ * <p>Creates a new instance of a JdbcRowSet.</p>
+ *
+ * @return A new instance of a JdbcRowSet.
+ *
+ * @throws SQLException if a JdbcRowSet cannot
+ * be created.
+ *
+ * @since 1.7
+ */
+ public JdbcRowSet createJdbcRowSet() throws SQLException;
+
+ /**
+ * <p>Creates a new instance of a JoinRowSet.</p>
+ *
+ * @return A new instance of a JoinRowSet.
+ *
+ * @throws SQLException if a JoinRowSet cannot
+ * be created.
+ *
+ * @since 1.7
+ */
+ public JoinRowSet createJoinRowSet() throws SQLException;
+
+ /**
+ * <p>Creates a new instance of a WebRowSet.</p>
+ *
+ * @return A new instance of a WebRowSet.
+ *
+ * @throws SQLException if a WebRowSet cannot
+ * be created.
+ *
+ * @since 1.7
+ */
+ public WebRowSet createWebRowSet() throws SQLException;
+
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.sql.rowset;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.sql.SQLException;
+import java.util.ServiceLoader;
+import javax.sql.rowset.RowSetFactory;
+
+/**
+ * A factory API that enables applications to obtain a
+ * {@code RowSetFactory} implementation that can be used to create different
+ * types of {@code RowSet} implementations.
+ * <p>
+ * Example:
+ * </p>
+ * <pre>
+ * RowSetFactory aFactory = RowSetProvider.newFactory();
+ * CachedRowSet crs = aFactory.createCachedRowSet();
+ * ...
+ * RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);
+ * WebRowSet wrs = rsf.createWebRowSet();
+ * </pre>
+ *<p>
+ * Tracing of this class may be enabled by setting the System property
+ * {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}.
+ * </p>
+ *
+ * @author Lance Andersen
+ * @since 1.7
+ */
+public class RowSetProvider {
+
+ private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug";
+ private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl";
+ private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory";
+ /**
+ * Internal debug flag.
+ */
+ private static boolean debug = true;
+
+
+ static {
+ // Check to see if the debug property is set
+ String val = getSystemProperty(ROWSET_DEBUG_PROPERTY);
+ // Allow simply setting the prop to turn on debug
+ debug = val != null && !"false".equals(val);
+ }
+
+
+ protected RowSetProvider () {
+ }
+
+ /**
+ * <p>Creates a new instance of a <code>RowSetFactory</code>
+ * implementation. This method uses the following
+ * look up order to determine
+ * the <code>RowSetFactory</code> implementation class to load:</p>
+ * <ul>
+ * <li>
+ * The System property {@code javax.sql.rowset.RowsetFactory}. For example:
+ * <ul>
+ * <li>
+ * -Djavax.sql.rowset.RowsetFactory=com.sun.rowset.RowSetFactoryImpl
+ * </li>
+ * </ul>
+ * <li>
+ * The ServiceLocator API. The ServiceLocator API will look
+ * for a classname in the file
+ * {@code META-INF/services/javax.sql.rowset.RowSetFactory}
+ * in jars available to the runtime. For example, to have the the RowSetFactory
+ * implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the
+ * entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be:
+ * <ul>
+ * <li>
+ * {@code com.sun.rowset.RowSetFactoryImpl }
+ * </li>
+ * </ul>
+ * </li>
+ * <li>
+ * Platform default <code>RowSetFactory</code> instance.
+ * </li>
+ * </ul>
+ *
+ * <p>Once an application has obtained a reference to a {@code RowSetFactory},
+ * it can use the factory to obtain RowSet instances.</p>
+ *
+ * @return New instance of a <code>RowSetFactory</code>
+ *
+ * @throws SQLException if the default factory class cannot be loaded,
+ * instantiated. The cause will be set to actual Exception
+ *
+ * @see ServiceLoader
+ * @since 1.7
+ */
+ public static RowSetFactory newFactory()
+ throws SQLException {
+ // Use the system property first
+ RowSetFactory factory = null;
+ String factoryClassName = null;
+ try {
+ trace("Checking for Rowset System Property...");
+ factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME);
+ if (factoryClassName != null) {
+ trace("Found system property, value=" + factoryClassName);
+ factory = (RowSetFactory) getFactoryClass(factoryClassName, null, true).newInstance();
+ }
+ } catch (ClassNotFoundException e) {
+ throw new SQLException(
+ "RowSetFactory: " + factoryClassName + " not found", e);
+ } catch (Exception e) {
+ throw new SQLException(
+ "RowSetFactory: " + factoryClassName + " could not be instantiated: " + e,
+ e);
+ }
+
+ // Check to see if we found the RowSetFactory via a System property
+ if (factory == null) {
+ // If the RowSetFactory is not found via a System Property, now
+ // look it up via the ServiceLoader API and if not found, use the
+ // Java SE default.
+ factory = loadViaServiceLoader();
+ factory =
+ factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory;
+ }
+ return (factory);
+ }
+
+ /**
+ * <p>Creates a new instance of a <code>RowSetFactory</code> from the
+ * specified factory class name.
+ * This function is useful when there are multiple providers in the classpath.
+ * It gives more control to the application as it can specify which provider
+ * should be loaded.</p>
+ *
+ * <p>Once an application has obtained a reference to a <code>RowSetFactory</code>
+ * it can use the factory to obtain RowSet instances.</p>
+ *
+ * @param factoryClassName fully qualified factory class name that
+ * provides an implementation of <code>javax.sql.rowset.RowSetFactory</code>.
+ *
+ * @param cl <code>ClassLoader</code> used to load the factory
+ * class. If <code>null</code> current <code>Thread</code>'s context
+ * classLoader is used to load the factory class.
+ *
+ * @return New instance of a <code>RowSetFactory</code>
+ *
+ * @throws SQLException if <code>factoryClassName</code> is
+ * <code>null</code>, or the factory class cannot be loaded, instantiated.
+ *
+ * @see #newFactory()
+ *
+ * @since 1.7
+ */
+ public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl)
+ throws SQLException {
+
+ trace("***In newInstance()");
+ try {
+ Class providerClass = getFactoryClass(factoryClassName, cl, false);
+ RowSetFactory instance = (RowSetFactory) providerClass.newInstance();
+ if (debug) {
+ trace("Created new instance of " + providerClass +
+ " using ClassLoader: " + cl);
+ }
+ return instance;
+ } catch (ClassNotFoundException x) {
+ throw new SQLException(
+ "Provider " + factoryClassName + " not found", x);
+ } catch (Exception x) {
+ throw new SQLException(
+ "Provider " + factoryClassName + " could not be instantiated: " + x,
+ x);
+ }
+ }
+
+ /*
+ * Returns the class loader to be used.
+ * @return The ClassLoader to use.
+ *
+ */
+ static private ClassLoader getContextClassLoader() throws SecurityException {
+ return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run() {
+ ClassLoader cl = null;
+
+ cl = Thread.currentThread().getContextClassLoader();
+
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+
+ return cl;
+ }
+ });
+ }
+
+ /**
+ * Attempt to load a class using the class loader supplied. If that fails
+ * and fall back is enabled, the current (i.e. bootstrap) class loader is
+ * tried.
+ *
+ * If the class loader supplied is <code>null</code>, first try using the
+ * context class loader followed by the current class loader.
+ * @return The class which was loaded
+ */
+ static private Class getFactoryClass(String factoryClassName, ClassLoader cl,
+ boolean doFallback) throws ClassNotFoundException {
+ try {
+ if (cl == null) {
+ cl = getContextClassLoader();
+ if (cl == null) {
+ throw new ClassNotFoundException();
+ } else {
+ return cl.loadClass(factoryClassName);
+ }
+ } else {
+ return cl.loadClass(factoryClassName);
+ }
+ } catch (ClassNotFoundException e) {
+ if (doFallback) {
+ // Use current class loader
+ return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Use the ServiceLoader mechanism to load the default RowSetFactory
+ * @return default RowSetFactory Implementation
+ */
+ static private RowSetFactory loadViaServiceLoader() {
+ RowSetFactory theFactory = null;
+ trace("***in loadViaServiceLoader()");
+ for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) {
+ trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName());
+ theFactory = factory;
+ break;
+ }
+ return theFactory;
+
+ }
+
+ /**
+ * Returns the requested System Property. If a {@code SecurityException}
+ * occurs, just return NULL
+ * @param propName - System property to retreive
+ * @return The System property value or NULL if the property does not exist
+ * or a {@code SecurityException} occurs.
+ */
+ static private String getSystemProperty(final String propName) {
+ String property = null;
+ try {
+ property = (String) AccessController.doPrivileged(new PrivilegedAction() {
+
+ public Object run() {
+ return System.getProperty(propName);
+ }
+ });
+ } catch (SecurityException se) {
+ if (debug) {
+ se.printStackTrace();
+ }
+ }
+ return property;
+ }
+
+ /**
+ * Debug routine which will output tracing if the System Property
+ * -Djavax.sql.rowset.RowSetFactory.debug is set
+ * @param msg - The debug message to display
+ */
+ private static void trace(String msg) {
+ if (debug) {
+ System.err.println("###RowSets: " + msg);
+ }
+ }
+}
--- a/jdk/src/share/classes/javax/sql/rowset/package.html Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/javax/sql/rowset/package.html Thu Sep 16 11:19:43 2010 -0700
@@ -5,7 +5,7 @@
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<!--
-Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,7 @@
data structure as defined in the JDBC 3.0 specification.
<p>
<li><a href="CachedRowSet.html">
-<b><code>CachedRowSet</code><sup><font size=-2>TM></font></sup</b></a>
+<b><code>CachedRowSet</code>™</b></a>
- A <tt>CachedRowSet</tt> object is a JavaBeans<sup><font size=-2>TM</font></sup>
component that is scrollable, updatable, serializable, and generally disconnected from
the source of its data. A <tt>CachedRowSet</tt> object
@@ -148,7 +148,12 @@
on <a href="spi/SyncProvider.html"><code>SyncProvider</code></a> implementations.
<p>
<ul>
-<li><b>3.1 Role of the <code>BaseRowSet</code> Class</b>
+<li><b>3.1 Constructor</b>
+<p>
+ All <code>RowSet</code> implementations <strong>must</strong> provide a
+no-argument constructor.
+</li>
+<li><b>3.2 Role of the <code>BaseRowSet</code> Class</b>
<p>
A compliant JDBC <code>RowSet</code> implementation <b>must</b> implement one or more
standard interfaces specified in this package and and <b>may</b> extend the
@@ -215,7 +220,7 @@
</table>
</blockquote>
<p>
-<li><b>3.2 Connected RowSet Requirements</b>
+<li><b>3.3 Connected RowSet Requirements</b>
<p>
The <code>JdbcRowSet</code> describes a <code>RowSet</code> object that <b>must</b> always
be connected to the originating data source. Implementations of the <code>JdbcRowSet</code>
@@ -229,7 +234,7 @@
<p>
<li>
-<b>3.3 Disconnected RowSet Requirements</b>
+<b>3.4 Disconnected RowSet Requirements</b>
<p>
A disconnected <code>RowSet</code> object, such as a <code>CachedRowSet</code> object,
<b>should</b> delegate
@@ -244,7 +249,7 @@
therefore ensure that no
extraneous references remain on the <code>Connection</code> object.
<p>
-<li><b>3.4 Role of RowSetMetaDataImpl</b>
+<li><b>3.5 Role of RowSetMetaDataImpl</b>
<p>
The <code>RowsetMetaDataImpl</code> class is a utility class that provides an implementation of the
<a href="../RowSetMetaData.html">RowSetMetaData</a> interface, supplying standard setter
@@ -252,7 +257,7 @@
<code>RowSet</code> objects. All implementations are free to use this standard
implementation but are not required to do so.
<p>
-<li><b>3.5 RowSetWarning Class</b>
+<li><b>3.6 RowSetWarning Class</b>
<p>
The <code>RowSetWarning</code> class provides warnings that can be set
on <code>RowSet</code> implementations.
@@ -270,7 +275,7 @@
<P>
-<li><b>3.6 The Joinable Interface</b>
+<li><b>3.7 The Joinable Interface</b>
<P>
The <code>Joinable</code> interface provides both connected and disconnected
<code>RowSet</code> objects with the capability to be added to a
@@ -278,7 +283,14 @@
A <code>RowSet</code> object that has implemented the <code>Joinable</code>
interface can set a match column, retrieve a match column, or unset a match column.
A <code>JoinRowSet</code> object can then use the <code>RowSet</code> object's
-match column as a basis for adding the <code>RowSet</code> object.
+match column as a basis for adding the <code>RowSet</code> object.
+</li>
+
+<li><b>3.8 The RowSetFactory Interface</b>
+ <p>
+ A <code>RowSetFactory</code> implementation <strong>must</strong>
+ be provided.
+</li>
</ul>
<h3><a name="relspec">4.0 Related Specifications</a></h3>
--- a/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,6 @@
package javax.sql.rowset.spi;
-import java.util.Map;
-import java.util.Hashtable;
-import java.util.Enumeration;
-import java.util.Vector;
-import java.util.Properties;
-import java.util.Collection;
-import java.util.StringTokenizer;
import java.util.logging.*;
import java.util.*;
@@ -216,68 +209,64 @@
* Having a private constructor guarantees that no more than
* one <code>SyncProvider</code> object can exist at a time.
*/
- private SyncFactory() {};
+ private SyncFactory() {
+ }
/**
* The standard property-id for a synchronization provider implementation
* name.
*/
- public static String ROWSET_SYNC_PROVIDER =
- "rowset.provider.classname";
-
+ public static final String ROWSET_SYNC_PROVIDER =
+ "rowset.provider.classname";
/**
* The standard property-id for a synchronization provider implementation
* vendor name.
*/
- public static String ROWSET_SYNC_VENDOR =
- "rowset.provider.vendor";
-
+ public static final String ROWSET_SYNC_VENDOR =
+ "rowset.provider.vendor";
/**
* The standard property-id for a synchronization provider implementation
* version tag.
*/
- public static String ROWSET_SYNC_PROVIDER_VERSION =
- "rowset.provider.version";
-
+ public static final String ROWSET_SYNC_PROVIDER_VERSION =
+ "rowset.provider.version";
/**
* The standard resource file name.
*/
private static String ROWSET_PROPERTIES = "rowset.properties";
-
/**
* The RI Optimistic Provider.
*/
private static String default_provider =
- "com.sun.rowset.providers.RIOptimisticProvider";
-
+ "com.sun.rowset.providers.RIOptimisticProvider";
+ /**
+ * Permission required to invoke setJNDIContext and setLogger
+ */
+ private static final SQLPermission SET_SYNCFACTORY_PERMISSION =
+ new SQLPermission("setSyncFactory");
/**
* The initial JNDI context where <code>SyncProvider</code> implementations can
* be stored and from which they can be invoked.
*/
private static Context ic;
-
/**
* The <code>Logger</code> object to be used by the <code>SyncFactory</code>.
*/
private static Logger rsLogger;
-
/**
*
*/
private static Level rsLevel;
-
/**
* The registry of available <code>SyncProvider</code> implementations.
* See section 2.0 of the class comment for <code>SyncFactory</code> for an
* explanation of how a provider can be added to this registry.
*/
private static Hashtable implementations;
-
/**
* Internal sync object used to maintain the SPI as a singleton
*/
private static Object logSync = new Object();
-
/**
* Internal PrintWriter field for logging facility
*/
@@ -311,7 +300,7 @@
* @see #setJNDIContext
*/
public static synchronized void registerProvider(String providerID)
- throws SyncFactoryException {
+ throws SyncFactoryException {
ProviderImpl impl = new ProviderImpl();
impl.setClassname(providerID);
@@ -325,29 +314,29 @@
*
* @return the <code>SyncFactory</code> instance
*/
- public static SyncFactory getSyncFactory(){
+ public static SyncFactory getSyncFactory() {
- // This method uses the Singleton Design Pattern
- // with Double-Checked Locking Pattern for
- // 1. Creating single instance of the SyncFactory
- // 2. Make the class thread safe, so that at one time
- // only one thread enters the synchronized block
- // to instantiate.
+ // This method uses the Singleton Design Pattern
+ // with Double-Checked Locking Pattern for
+ // 1. Creating single instance of the SyncFactory
+ // 2. Make the class thread safe, so that at one time
+ // only one thread enters the synchronized block
+ // to instantiate.
- // if syncFactory object is already there
- // don't go into synchronized block and return
- // that object.
- // else go into synchronized block
+ // if syncFactory object is already there
+ // don't go into synchronized block and return
+ // that object.
+ // else go into synchronized block
- if(syncFactory == null){
- synchronized(SyncFactory.class) {
- if(syncFactory == null){
+ if (syncFactory == null) {
+ synchronized (SyncFactory.class) {
+ if (syncFactory == null) {
syncFactory = new SyncFactory();
} //end if
- } //end synchronized block
- } //end if
- return syncFactory;
- }
+ } //end synchronized block
+ } //end if
+ return syncFactory;
+ }
/**
* Removes the designated currently registered synchronization provider from the
@@ -358,13 +347,12 @@
* unregister a SyncProvider implementation that was not registered.
*/
public static synchronized void unregisterProvider(String providerID)
- throws SyncFactoryException {
+ throws SyncFactoryException {
initMapIfNecessary();
if (implementations.containsKey(providerID)) {
implementations.remove(providerID);
}
}
-
private static String colon = ":";
private static String strFileSep = "/";
@@ -395,7 +383,7 @@
* Dependent on application
*/
String strRowsetProperties = System.getProperty("rowset.properties");
- if ( strRowsetProperties != null) {
+ if (strRowsetProperties != null) {
// Load user's implementation of SyncProvider
// here. -Drowset.properties=/abc/def/pqr.txt
ROWSET_PROPERTIES = strRowsetProperties;
@@ -407,8 +395,8 @@
* Always available
*/
ROWSET_PROPERTIES = "javax" + strFileSep + "sql" +
- strFileSep + "rowset" + strFileSep +
- "rowset.properties";
+ strFileSep + "rowset" + strFileSep +
+ "rowset.properties";
// properties.load(
// ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES));
@@ -417,7 +405,7 @@
properties.load(cl.getResourceAsStream(ROWSET_PROPERTIES));
parseProperties(properties);
- // removed else, has properties should sum together
+ // removed else, has properties should sum together
} catch (FileNotFoundException e) {
throw new SyncFactoryException("Cannot locate properties file: " + e);
@@ -447,18 +435,15 @@
}
}
}
-
/**
* The internal boolean switch that indicates whether a JNDI
* context has been established or not.
*/
private static boolean jndiCtxEstablished = false;
-
/**
* The internal debug switch.
*/
private static boolean debug = false;
-
/**
* Internal registry count for the number of providers contained in the
* registry.
@@ -475,9 +460,9 @@
String key = null;
String[] propertyNames = null;
- for (Enumeration e = p.propertyNames(); e.hasMoreElements() ;) {
+ for (Enumeration e = p.propertyNames(); e.hasMoreElements();) {
- String str = (String)e.nextElement();
+ String str = (String) e.nextElement();
int w = str.length();
@@ -491,7 +476,7 @@
propertyNames = getPropertyNames(false);
} else {
// property index has been set.
- propertyNames = getPropertyNames(true, str.substring(w-1));
+ propertyNames = getPropertyNames(true, str.substring(w - 1));
}
key = p.getProperty(propertyNames[0]);
@@ -515,17 +500,17 @@
* overloaded property names that contain indexes.
*/
private static String[] getPropertyNames(boolean append,
- String propertyIndex) {
+ String propertyIndex) {
String dot = ".";
String[] propertyNames =
- new String[] {SyncFactory.ROWSET_SYNC_PROVIDER,
- SyncFactory.ROWSET_SYNC_VENDOR,
- SyncFactory.ROWSET_SYNC_PROVIDER_VERSION};
+ new String[]{SyncFactory.ROWSET_SYNC_PROVIDER,
+ SyncFactory.ROWSET_SYNC_VENDOR,
+ SyncFactory.ROWSET_SYNC_PROVIDER_VERSION};
if (append) {
for (int i = 0; i < propertyNames.length; i++) {
propertyNames[i] = propertyNames[i] +
- dot +
- propertyIndex;
+ dot +
+ propertyIndex;
}
return propertyNames;
} else {
@@ -549,15 +534,21 @@
*
* @param providerID the unique identifier of the provider
* @return a <code>SyncProvider</code> implementation
- * @throws SyncFactoryException If the SyncProvider cannot be found or
+ * @throws SyncFactoryException If the SyncProvider cannot be found,
+ * the providerID is {@code null}, or
* some error was encountered when trying to invoke this provider.
*/
public static SyncProvider getInstance(String providerID)
- throws SyncFactoryException {
+ throws SyncFactoryException {
+
+ if(providerID == null) {
+ throw new SyncFactoryException("The providerID cannot be null");
+ }
+
initMapIfNecessary(); // populate HashTable
initJNDIContext(); // check JNDI context for any additional bindings
- ProviderImpl impl = (ProviderImpl)implementations.get(providerID);
+ ProviderImpl impl = (ProviderImpl) implementations.get(providerID);
if (impl == null) {
// Requested SyncProvider is unavailable. Return default provider.
@@ -575,11 +566,10 @@
* this SyncFactory and try to laod the SyncProvider class from
* there.
**/
-
c = Class.forName(providerID, true, cl);
if (c != null) {
- return (SyncProvider)c.newInstance();
+ return (SyncProvider) c.newInstance();
} else {
return new com.sun.rowset.providers.RIOptimisticProvider();
}
@@ -592,6 +582,7 @@
throw new SyncFactoryException("ClassNotFoundException: " + e.getMessage());
}
}
+
/**
* Returns an Enumeration of currently registered synchronization
* providers. A <code>RowSet</code> implementation may use any provider in
@@ -605,7 +596,7 @@
* providers that are registered with this Factory
*/
public static Enumeration<SyncProvider> getRegisteredProviders()
- throws SyncFactoryException {
+ throws SyncFactoryException {
initMapIfNecessary();
// return a collection of classnames
// of type SyncProvider
@@ -618,10 +609,26 @@
* <code>SyncProvider</code> implementations can log their events to
* this object and the application can retrieve a handle to this
* object using the <code>getLogger</code> method.
+ * <p>
+ * This method checks to see that there is an {@code SQLPermission}
+ * object which grants the permission {@code setSyncFactory}
+ * before allowing the method to succeed. If a
+ * {@code SecurityManager} exists and its
+ * {@code checkPermission} method denies calling {@code setLogger},
+ * this method throws a
+ * {@code java.lang.SecurityException}.
*
* @param logger A Logger object instance
+ * @throws java.lang.SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies calling {@code setLogger}
+ * @see SecurityManager#checkPermission
*/
public static void setLogger(Logger logger) {
+
+ SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
+ }
rsLogger = logger;
}
@@ -631,14 +638,28 @@
* <code>SyncProvider</code> implementations can log their events
* to this object and the application can retrieve a handle to this
* object using the <code>getLogger</code> method.
+ * <p>
+ * This method checks to see that there is an {@code SQLPermission}
+ * object which grants the permission {@code setSyncFactory}
+ * before allowing the method to succeed. If a
+ * {@code SecurityManager} exists and its
+ * {@code checkPermission} method denies calling {@code setLogger},
+ * this method throws a
+ * {@code java.lang.SecurityException}.
*
* @param logger a Logger object instance
* @param level a Level object instance indicating the degree of logging
* required
+ * @throws java.lang.SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies calling {@code setLogger}
+ * @see SecurityManager#checkPermission
*/
public static void setLogger(Logger logger, Level level) {
// singleton
-
+ SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
+ }
rsLogger = logger;
rsLogger.setLevel(level);
}
@@ -651,27 +672,42 @@
*/
public static Logger getLogger() throws SyncFactoryException {
// only one logger per session
- if(rsLogger == null){
- throw new SyncFactoryException("(SyncFactory) : No logger has been set");
+ if (rsLogger == null) {
+ throw new SyncFactoryException("(SyncFactory) : No logger has been set");
}
return rsLogger;
}
- /**
- * Sets the initial JNDI context from which SyncProvider implementations
- * can be retrieved from a JNDI namespace
- *
- * @param ctx a valid JNDI context
- * @throws SyncFactoryException if the supplied JNDI context is null
- */
+ /**
+ * Sets the initial JNDI context from which SyncProvider implementations
+ * can be retrieved from a JNDI namespace
+ * <p>
+ * This method checks to see that there is an {@code SQLPermission}
+ * object which grants the permission {@code setSyncFactory}
+ * before allowing the method to succeed. If a
+ * {@code SecurityManager} exists and its
+ * {@code checkPermission} method denies calling {@code setJNDIContext},
+ * this method throws a
+ * {@code java.lang.SecurityException}.
+ *
+ * @param ctx a valid JNDI context
+ * @throws SyncFactoryException if the supplied JNDI context is null
+ * @throws java.lang.SecurityException if a security manager exists and its
+ * {@code checkPermission} method denies calling {@code setJNDIContext}
+ * @see SecurityManager#checkPermission
+ */
public static void setJNDIContext(javax.naming.Context ctx)
- throws SyncFactoryException {
+ throws SyncFactoryException {
+ SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ sec.checkPermission(SET_SYNCFACTORY_PERMISSION);
+ }
if (ctx == null) {
throw new SyncFactoryException("Invalid JNDI context supplied");
}
ic = ctx;
jndiCtxEstablished = true;
- }
+ }
/**
* Controls JNDI context intialization.
@@ -689,7 +725,7 @@
throw new SyncFactoryException("SPI: NamingException: " + e.getExplanation());
} catch (Exception e) {
e.printStackTrace();
- throw new SyncFactoryException("SPI: Exception: " + e.getMessage());
+ throw new SyncFactoryException("SPI: Exception: " + e.getMessage());
}
}
}
@@ -720,7 +756,7 @@
* bindings have been enumerated.
*/
private static void enumerateBindings(NamingEnumeration bindings,
- Properties properties) throws NamingException {
+ Properties properties) throws NamingException {
boolean syncProviderObj = false; // move to parameters ?
@@ -729,21 +765,21 @@
Object elementObj = null;
String element = null;
while (bindings.hasMore()) {
- bd = (Binding)bindings.next();
+ bd = (Binding) bindings.next();
element = bd.getName();
elementObj = bd.getObject();
if (!(ic.lookup(element) instanceof Context)) {
- // skip directories/sub-contexts
- if (ic.lookup(element) instanceof SyncProvider) {
+ // skip directories/sub-contexts
+ if (ic.lookup(element) instanceof SyncProvider) {
syncProviderObj = true;
- }
+ }
}
if (syncProviderObj) {
- SyncProvider sync = (SyncProvider)elementObj;
+ SyncProvider sync = (SyncProvider) elementObj;
properties.put(SyncFactory.ROWSET_SYNC_PROVIDER,
- sync.getProviderID());
+ sync.getProviderID());
syncProviderObj = false; // reset
}
@@ -756,142 +792,136 @@
}
}
- /**
- * Internal class that defines the lazy reference construct for each registered
- * SyncProvider implementation.
- */
- class ProviderImpl extends SyncProvider {
- private String className = null;
- private String vendorName = null;
- private String ver = null;
- private int index;
+/**
+ * Internal class that defines the lazy reference construct for each registered
+ * SyncProvider implementation.
+ */
+class ProviderImpl extends SyncProvider {
+
+ private String className = null;
+ private String vendorName = null;
+ private String ver = null;
+ private int index;
- public void setClassname(String classname) {
- className = classname;
- }
-
- public String getClassname() {
- return className;
- }
+ public void setClassname(String classname) {
+ className = classname;
+ }
- public void setVendor(String vendor) {
- vendorName = vendor;
- }
+ public String getClassname() {
+ return className;
+ }
- public String getVendor() {
- return vendorName;
- }
+ public void setVendor(String vendor) {
+ vendorName = vendor;
+ }
- public void setVersion(String providerVer) {
- ver = providerVer;
- }
+ public String getVendor() {
+ return vendorName;
+ }
- public String getVersion() {
- return ver;
- }
+ public void setVersion(String providerVer) {
+ ver = providerVer;
+ }
- public void setIndex(int i) {
- index = i;
- }
+ public String getVersion() {
+ return ver;
+ }
- public int getIndex() {
- return index;
- }
+ public void setIndex(int i) {
+ index = i;
+ }
- public int getDataSourceLock() throws SyncProviderException {
+ public int getIndex() {
+ return index;
+ }
- int dsLock = 0;
- try
- {
- dsLock = SyncFactory.getInstance(className).getDataSourceLock();
- } catch(SyncFactoryException sfEx) {
+ public int getDataSourceLock() throws SyncProviderException {
- throw new SyncProviderException(sfEx.getMessage());
- }
+ int dsLock = 0;
+ try {
+ dsLock = SyncFactory.getInstance(className).getDataSourceLock();
+ } catch (SyncFactoryException sfEx) {
- return dsLock;
+ throw new SyncProviderException(sfEx.getMessage());
}
- public int getProviderGrade() {
+ return dsLock;
+ }
- int grade = 0;
+ public int getProviderGrade() {
- try
- {
- grade = SyncFactory.getInstance(className).getProviderGrade();
- } catch(SyncFactoryException sfEx) {
- //
- }
+ int grade = 0;
- return grade;
- }
-
- public String getProviderID() {
- return className;
+ try {
+ grade = SyncFactory.getInstance(className).getProviderGrade();
+ } catch (SyncFactoryException sfEx) {
+ //
}
- /*
- public javax.sql.RowSetInternal getRowSetInternal() {
- try
- {
- return SyncFactory.getInstance(className).getRowSetInternal();
- } catch(SyncFactoryException sfEx) {
- //
- }
- }
- */
+ return grade;
+ }
+
+ public String getProviderID() {
+ return className;
+ }
- public javax.sql.RowSetReader getRowSetReader() {
-
- RowSetReader rsReader = null;;
+ /*
+ public javax.sql.RowSetInternal getRowSetInternal() {
+ try
+ {
+ return SyncFactory.getInstance(className).getRowSetInternal();
+ } catch(SyncFactoryException sfEx) {
+ //
+ }
+ }
+ */
+ public javax.sql.RowSetReader getRowSetReader() {
- try
- {
- rsReader = SyncFactory.getInstance(className).getRowSetReader();
- } catch(SyncFactoryException sfEx) {
- //
- }
+ RowSetReader rsReader = null;
- return rsReader;
-
+ try {
+ rsReader = SyncFactory.getInstance(className).getRowSetReader();
+ } catch (SyncFactoryException sfEx) {
+ //
}
- public javax.sql.RowSetWriter getRowSetWriter() {
+ return rsReader;
+
+ }
+
+ public javax.sql.RowSetWriter getRowSetWriter() {
RowSetWriter rsWriter = null;
- try
- {
- rsWriter = SyncFactory.getInstance(className).getRowSetWriter();
- } catch(SyncFactoryException sfEx) {
- //
- }
-
- return rsWriter;
- }
- public void setDataSourceLock(int param)
- throws SyncProviderException {
-
- try
- {
- SyncFactory.getInstance(className).setDataSourceLock(param);
- } catch(SyncFactoryException sfEx) {
-
- throw new SyncProviderException(sfEx.getMessage());
- }
+ try {
+ rsWriter = SyncFactory.getInstance(className).getRowSetWriter();
+ } catch (SyncFactoryException sfEx) {
+ //
}
- public int supportsUpdatableView() {
+ return rsWriter;
+ }
+
+ public void setDataSourceLock(int param)
+ throws SyncProviderException {
+
+ try {
+ SyncFactory.getInstance(className).setDataSourceLock(param);
+ } catch (SyncFactoryException sfEx) {
+
+ throw new SyncProviderException(sfEx.getMessage());
+ }
+ }
+
+ public int supportsUpdatableView() {
int view = 0;
- try
- {
- view = SyncFactory.getInstance(className).supportsUpdatableView();
- } catch(SyncFactoryException sfEx) {
- //
- }
+ try {
+ view = SyncFactory.getInstance(className).supportsUpdatableView();
+ } catch (SyncFactoryException sfEx) {
+ //
+ }
- return view;
- }
-
+ return view;
}
+}
--- a/jdk/src/share/classes/javax/sql/rowset/spi/SyncProvider.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/javax/sql/rowset/spi/SyncProvider.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -344,7 +344,7 @@
* source without checking the validity of any data.
*
*/
- public static int GRADE_NONE = 1;
+ public static final int GRADE_NONE = 1;
/**
* Indicates a low level optimistic synchronization grade with
@@ -354,7 +354,7 @@
* returning this grade will check only rows that have changed.
*
*/
- public static int GRADE_CHECK_MODIFIED_AT_COMMIT = 2;
+ public static final int GRADE_CHECK_MODIFIED_AT_COMMIT = 2;
/**
* Indicates a high level optimistic synchronization grade with
@@ -364,7 +364,7 @@
* returning this grade will check all rows, including rows that have not
* changed.
*/
- public static int GRADE_CHECK_ALL_AT_COMMIT = 3;
+ public static final int GRADE_CHECK_ALL_AT_COMMIT = 3;
/**
* Indicates a pessimistic synchronization grade with
@@ -374,7 +374,7 @@
* implementation returning this grade will lock the row in the originating
* data source.
*/
- public static int GRADE_LOCK_WHEN_MODIFIED = 4;
+ public static final int GRADE_LOCK_WHEN_MODIFIED = 4;
/**
* Indicates the most pessimistic synchronization grade with
@@ -384,47 +384,47 @@
* table affected by the original statement used to populate a
* <code>RowSet</code> object.
*/
- public static int GRADE_LOCK_WHEN_LOADED = 5;
+ public static final int GRADE_LOCK_WHEN_LOADED = 5;
/**
* Indicates that no locks remain on the originating data source. This is the default
* lock setting for all <code>SyncProvider</code> implementations unless
* otherwise directed by a <code>RowSet</code> object.
*/
- public static int DATASOURCE_NO_LOCK = 1;
+ public static final int DATASOURCE_NO_LOCK = 1;
/**
* Indicates that a lock is placed on the rows that are touched by the original
* SQL statement used to populate the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
- public static int DATASOURCE_ROW_LOCK = 2;
+ public static final int DATASOURCE_ROW_LOCK = 2;
/**
* Indicates that a lock is placed on all tables that are touched by the original
* SQL statement used to populate the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
- public static int DATASOURCE_TABLE_LOCK = 3;
+ public static final int DATASOURCE_TABLE_LOCK = 3;
/**
* Indicates that a lock is placed on the entire data source that is the source of
* data for the <code>RowSet</code> object
* that is using this <code>SyncProvider</code> object.
*/
- public static int DATASOURCE_DB_LOCK = 4;
+ public static final int DATASOURCE_DB_LOCK = 4;
/**
* Indicates that a <code>SyncProvider</code> implementation
* supports synchronization between a <code>RowSet</code> object and
* the SQL <code>VIEW</code> used to populate it.
*/
- public static int UPDATABLE_VIEW_SYNC = 5;
+ public static final int UPDATABLE_VIEW_SYNC = 5;
/**
* Indicates that a <code>SyncProvider</code> implementation
* does <B>not</B> support synchronization between a <code>RowSet</code>
* object and the SQL <code>VIEW</code> used to populate it.
*/
- public static int NONUPDATABLE_VIEW_SYNC = 6;
+ public static final int NONUPDATABLE_VIEW_SYNC = 6;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/sdp/SdpSupport.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.net.sdp;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.AccessController;
+
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+
+/**
+ * This class defines methods for creating SDP sockets or "converting" existing
+ * file descriptors, referencing (unbound) TCP sockets, to SDP.
+ */
+
+public final class SdpSupport {
+ private static final String os = AccessController
+ .doPrivileged(new sun.security.action.GetPropertyAction("os.name"));
+ private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux")));
+ private static final JavaIOFileDescriptorAccess fdAccess =
+ SharedSecrets.getJavaIOFileDescriptorAccess();
+
+ private SdpSupport() { }
+
+ /**
+ * Creates a SDP socket, returning file descriptor referencing the socket.
+ */
+ public static FileDescriptor createSocket() throws IOException {
+ if (!isSupported)
+ throw new UnsupportedOperationException("SDP not supported on this platform");
+ int fdVal = create0();
+ FileDescriptor fd = new FileDescriptor();
+ fdAccess.set(fd, fdVal);
+ return fd;
+ }
+
+ /**
+ * Converts an existing file descriptor, that references an unbound TCP socket,
+ * to SDP.
+ */
+ public static void convertSocket(FileDescriptor fd) throws IOException {
+ if (!isSupported)
+ throw new UnsupportedOperationException("SDP not supported on this platform");
+ int fdVal = fdAccess.get(fd);
+ convert0(fdVal);
+ }
+
+ private static native int create0() throws IOException;
+
+ private static native void convert0(int fd) throws IOException;
+
+ static {
+ AccessController.doPrivileged(
+ new sun.security.action.LoadLibraryAction("net"));
+ }
+}
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -545,6 +545,8 @@
long position, long count)
throws IOException
{
+ if (!src.readable)
+ throw new NonReadableChannelException();
synchronized (src.positionLock) {
long pos = src.position();
long max = Math.min(count, src.size() - pos);
--- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java Thu Sep 16 11:19:43 2010 -0700
@@ -319,7 +319,12 @@
static native boolean randomBytes(byte[] someBytes);
- static native void initPipe(int[] fda, boolean blocking);
+ /**
+ * Returns two file descriptors for a pipe encoded in a long.
+ * The read end of the pipe is returned in the high 32 bits,
+ * while the write end is returned in the low 32 bits.
+ */
+ static native long makePipe(boolean blocking);
static native boolean drain(int fd) throws IOException;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Secrets.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.SocketChannel;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * Provides access to implementation private constructors and methods.
+ */
+
+public final class Secrets {
+ private Secrets() { }
+
+ private static SelectorProvider provider() {
+ SelectorProvider p = SelectorProvider.provider();
+ if (!(p instanceof SelectorProviderImpl))
+ throw new UnsupportedOperationException();
+ return p;
+ }
+
+ public static SocketChannel newSocketChannel(FileDescriptor fd) {
+ try {
+ return new SocketChannelImpl(provider(), fd, false);
+ } catch (IOException ioe) {
+ throw new AssertionError(ioe);
+ }
+ }
+
+ public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) {
+ try {
+ return new ServerSocketChannelImpl(provider(), fd, false);
+ } catch (IOException ioe) {
+ throw new AssertionError(ioe);
+ }
+ }
+}
--- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -80,21 +80,24 @@
// -- End of fields protected by stateLock
- public ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
+ ServerSocketChannelImpl(SelectorProvider sp) throws IOException {
super(sp);
this.fd = Net.serverSocket(true);
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
}
- public ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd)
+ ServerSocketChannelImpl(SelectorProvider sp,
+ FileDescriptor fd,
+ boolean bound)
throws IOException
{
super(sp);
this.fd = fd;
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_INUSE;
- localAddress = Net.localAddress(fd);
+ if (bound)
+ localAddress = Net.localAddress(fd);
}
public ServerSocket socket() {
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -103,6 +103,19 @@
this.state = ST_UNCONNECTED;
}
+ SocketChannelImpl(SelectorProvider sp,
+ FileDescriptor fd,
+ boolean bound)
+ throws IOException
+ {
+ super(sp);
+ this.fd = fd;
+ this.fdVal = IOUtil.fdVal(fd);
+ this.state = ST_UNCONNECTED;
+ if (bound)
+ this.localAddress = Net.localAddress(fd);
+ }
+
// Constructor for sockets obtained from server sockets
//
SocketChannelImpl(SelectorProvider sp,
--- a/jdk/src/share/classes/sun/security/tools/policytool/PolicyTool.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/share/classes/sun/security/tools/policytool/PolicyTool.java Thu Sep 16 11:19:43 2010 -0700
@@ -4231,7 +4231,10 @@
super("SQLPermission",
"java.sql.SQLPermission",
new String[] {
- "setLog"
+ "setLog",
+ "callAbort",
+ "setSyncFactory",
+ "setNetworkTimeout",
},
null);
}
--- a/jdk/src/solaris/bin/java_md.c Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/bin/java_md.c Thu Sep 16 11:19:43 2010 -0700
@@ -535,7 +535,7 @@
GetApplicationHome(char *buf, jint bufsize)
{
if (execname != NULL) {
- JLI_StrNCpy(buf, execname, bufsize-1);
+ JLI_Snprintf(buf, bufsize, "%s", execname);
buf[bufsize-1] = '\0';
} else {
return JNI_FALSE;
--- a/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/java/lang/UNIXProcess.java.linux Thu Sep 16 11:19:43 2010 -0700
@@ -39,6 +39,7 @@
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.security.AccessController;
+import static java.security.AccessController.doPrivileged;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
@@ -94,14 +95,13 @@
private final static ThreadGroup group = getRootThreadGroup();
private static ThreadGroup getRootThreadGroup() {
- return AccessController.doPrivileged
- (new PrivilegedAction<ThreadGroup> () {
- public ThreadGroup run() {
- ThreadGroup root = Thread.currentThread().getThreadGroup();
- while (root.getParent() != null)
- root = root.getParent();
- return root;
- }});
+ return doPrivileged(new PrivilegedAction<ThreadGroup> () {
+ public ThreadGroup run() {
+ ThreadGroup root = Thread.currentThread().getThreadGroup();
+ while (root.getParent() != null)
+ root = root.getParent();
+ return root;
+ }});
}
public Thread newThread(Runnable grimReaper) {
@@ -117,8 +117,12 @@
/**
* The thread pool of "process reaper" daemon threads.
*/
- private static final Executor processReaperExecutor
- = Executors.newCachedThreadPool(new ProcessReaperThreadFactory());
+ private static final Executor processReaperExecutor =
+ doPrivileged(new PrivilegedAction<Executor>() {
+ public Executor run() {
+ return Executors.newCachedThreadPool
+ (new ProcessReaperThreadFactory());
+ }});
UNIXProcess(final byte[] prog,
final byte[] argBlock, final int argc,
@@ -136,8 +140,7 @@
redirectErrorStream);
try {
- AccessController.doPrivileged
- (new PrivilegedExceptionAction<Void>() {
+ doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws IOException {
initStreams(fds);
return null;
--- a/jdk/src/solaris/classes/sun/net/NetHooks.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/net/NetHooks.java Thu Sep 16 11:19:43 2010 -0700
@@ -73,28 +73,7 @@
* be changed to use the ServiceLoader facility to allow the deployment of
* other providers.
*/
- private static Provider loadProvider(final String cn) {
- return AccessController
- .doPrivileged(new PrivilegedAction<Provider>() {
- @Override public Provider run() {
- Class<Provider> c;
- try {
- c = (Class<Provider>)Class.forName(cn, true, null);
- } catch (ClassNotFoundException x) {
- return null;
- }
- try {
- return c.newInstance();
- } catch (IllegalAccessException x) {
- throw new AssertionError(x);
- } catch (InstantiationException x) {
- throw new AssertionError(x);
- }
- }});
- }
- private static final Provider provider = AccessController
- .doPrivileged(new GetPropertyAction("os.name")).equals("SunOS") ?
- loadProvider("sun.net.spi.SdpProvider") : null;
+ private static final Provider provider = new sun.net.sdp.SdpProvider();
/**
* Invoke prior to binding a TCP socket.
@@ -104,8 +83,7 @@
int port)
throws IOException
{
- if (provider != null)
- provider.implBeforeTcpBind(fdObj, address, port);
+ provider.implBeforeTcpBind(fdObj, address, port);
}
/**
@@ -116,7 +94,6 @@
int port)
throws IOException
{
- if (provider != null)
- provider.implBeforeTcpConnect(fdObj, address, port);
+ provider.implBeforeTcpConnect(fdObj, address, port);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/net/sdp/SdpProvider.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.net.sdp;
+
+import sun.net.NetHooks;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+import java.util.*;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.AccessController;
+
+import sun.net.sdp.SdpSupport;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * A NetHooks provider that converts sockets from the TCP to SDP protocol prior
+ * to binding or connecting.
+ */
+
+public class SdpProvider extends NetHooks.Provider {
+ // maximum port
+ private static final int MAX_PORT = 65535;
+
+ // indicates if SDP is enabled and the rules for when the protocol is used
+ private final boolean enabled;
+ private final List<Rule> rules;
+
+ // logging for debug purposes
+ private PrintStream log;
+
+ public SdpProvider() {
+ // if this property is not defined then there is nothing to do.
+ String file = AccessController.doPrivileged(
+ new GetPropertyAction("com.sun.sdp.conf"));
+ if (file == null) {
+ this.enabled = false;
+ this.rules = null;
+ return;
+ }
+
+ // load configuration file
+ List<Rule> list = null;
+ if (file != null) {
+ try {
+ list = loadRulesFromFile(file);
+ } catch (IOException e) {
+ fail("Error reading %s: %s", file, e.getMessage());
+ }
+ }
+
+ // check if debugging is enabled
+ PrintStream out = null;
+ String logfile = AccessController.doPrivileged(
+ new GetPropertyAction("com.sun.sdp.debug"));
+ if (logfile != null) {
+ out = System.out;
+ if (logfile.length() > 0) {
+ try {
+ out = new PrintStream(logfile);
+ } catch (IOException ignore) { }
+ }
+ }
+
+ this.enabled = !list.isEmpty();
+ this.rules = list;
+ this.log = out;
+ }
+
+ // supported actions
+ private static enum Action {
+ BIND,
+ CONNECT;
+ }
+
+ // a rule for matching a bind or connect request
+ private static interface Rule {
+ boolean match(Action action, InetAddress address, int port);
+ }
+
+ // rule to match port[-end]
+ private static class PortRangeRule implements Rule {
+ private final Action action;
+ private final int portStart;
+ private final int portEnd;
+ PortRangeRule(Action action, int portStart, int portEnd) {
+ this.action = action;
+ this.portStart = portStart;
+ this.portEnd = portEnd;
+ }
+ Action action() {
+ return action;
+ }
+ @Override
+ public boolean match(Action action, InetAddress address, int port) {
+ return (action == this.action &&
+ port >= this.portStart &&
+ port <= this.portEnd);
+ }
+ }
+
+ // rule to match address[/prefix] port[-end]
+ private static class AddressPortRangeRule extends PortRangeRule {
+ private final byte[] addressAsBytes;
+ private final int prefixByteCount;
+ private final byte mask;
+ AddressPortRangeRule(Action action, InetAddress address,
+ int prefix, int port, int end)
+ {
+ super(action, port, end);
+ this.addressAsBytes = address.getAddress();
+ this.prefixByteCount = prefix >> 3;
+ this.mask = (byte)(0xff << (8 - (prefix % 8)));
+ }
+ @Override
+ public boolean match(Action action, InetAddress address, int port) {
+ if (action != action())
+ return false;
+ byte[] candidate = address.getAddress();
+ // same address type?
+ if (candidate.length != addressAsBytes.length)
+ return false;
+ // check bytes
+ for (int i=0; i<prefixByteCount; i++) {
+ if (candidate[i] != addressAsBytes[i])
+ return false;
+ }
+ // check remaining bits
+ if ((prefixByteCount < addressAsBytes.length) &&
+ ((candidate[prefixByteCount] & mask) !=
+ (addressAsBytes[prefixByteCount] & mask)))
+ return false;
+ return super.match(action, address, port);
+ }
+ }
+
+ // parses port:[-end]
+ private static int[] parsePortRange(String s) {
+ int pos = s.indexOf('-');
+ try {
+ int[] result = new int[2];
+ if (pos < 0) {
+ boolean all = s.equals("*");
+ result[0] = all ? 0 : Integer.parseInt(s);
+ result[1] = all ? MAX_PORT : result[0];
+ } else {
+ String low = s.substring(0, pos);
+ if (low.length() == 0) low = "*";
+ String high = s.substring(pos+1);
+ if (high.length() == 0) high = "*";
+ result[0] = low.equals("*") ? 0 : Integer.parseInt(low);
+ result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high);
+ }
+ return result;
+ } catch (NumberFormatException e) {
+ return new int[0];
+ }
+ }
+
+ private static void fail(String msg, Object... args) {
+ Formatter f = new Formatter();
+ f.format(msg, args);
+ throw new RuntimeException(f.out().toString());
+ }
+
+ // loads rules from the given file
+ // Each non-blank/non-comment line must have the format:
+ // ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix])
+ // 1*LWSP-char ("*" | port) [ "-" ("*" | port) ]
+ private static List<Rule> loadRulesFromFile(String file)
+ throws IOException
+ {
+ Scanner scanner = new Scanner(new File(file));
+ try {
+ List<Rule> result = new ArrayList<Rule>();
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine().trim();
+
+ // skip blank lines and comments
+ if (line.length() == 0 || line.charAt(0) == '#')
+ continue;
+
+ // must have 3 fields
+ String[] s = line.split("\\s+");
+ if (s.length != 3) {
+ fail("Malformed line '%s'", line);
+ continue;
+ }
+
+ // first field is the action ("bind" or "connect")
+ Action action = null;
+ for (Action a: Action.values()) {
+ if (s[0].equalsIgnoreCase(a.name())) {
+ action = a;
+ break;
+ }
+ }
+ if (action == null) {
+ fail("Action '%s' not recognized", s[0]);
+ continue;
+ }
+
+ // * port[-end]
+ int[] ports = parsePortRange(s[2]);
+ if (ports.length == 0) {
+ fail("Malformed port range '%s'", s[2]);
+ continue;
+ }
+
+ // match all addresses
+ if (s[1].equals("*")) {
+ result.add(new PortRangeRule(action, ports[0], ports[1]));
+ continue;
+ }
+
+ // hostname | ipaddress[/prefix]
+ int pos = s[1].indexOf('/');
+ try {
+ if (pos < 0) {
+ // hostname or ipaddress (no prefix)
+ InetAddress[] addresses = InetAddress.getAllByName(s[1]);
+ for (InetAddress address: addresses) {
+ int prefix =
+ (address instanceof Inet4Address) ? 32 : 128;
+ result.add(new AddressPortRangeRule(action, address,
+ prefix, ports[0], ports[1]));
+ }
+ } else {
+ // ipaddress/prefix
+ InetAddress address = InetAddress
+ .getByName(s[1].substring(0, pos));
+ int prefix = -1;
+ try {
+ prefix = Integer.parseInt(s[1].substring(pos+1));
+ if (address instanceof Inet4Address) {
+ // must be 1-31
+ if (prefix < 0 || prefix > 32) prefix = -1;
+ } else {
+ // must be 1-128
+ if (prefix < 0 || prefix > 128) prefix = -1;
+ }
+ } catch (NumberFormatException e) {
+ }
+
+ if (prefix > 0) {
+ result.add(new AddressPortRangeRule(action,
+ address, prefix, ports[0], ports[1]));
+ } else {
+ fail("Malformed prefix '%s'", s[1]);
+ continue;
+ }
+ }
+ } catch (UnknownHostException uhe) {
+ fail("Unknown host or malformed IP address '%s'", s[1]);
+ continue;
+ }
+ }
+ return result;
+ } finally {
+ scanner.close();
+ }
+ }
+
+ // converts unbound TCP socket to a SDP socket if it matches the rules
+ private void convertTcpToSdpIfMatch(FileDescriptor fdObj,
+ Action action,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ boolean matched = false;
+ for (Rule rule: rules) {
+ if (rule.match(action, address, port)) {
+ SdpSupport.convertSocket(fdObj);
+ matched = true;
+ break;
+ }
+ }
+ if (log != null) {
+ String addr = (address instanceof Inet4Address) ?
+ address.getHostAddress() : "[" + address.getHostAddress() + "]";
+ if (matched) {
+ log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);
+ } else {
+ log.format("%s to %s:%d (no match)\n", action, addr, port);
+ }
+ }
+ }
+
+ @Override
+ public void implBeforeTcpBind(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (enabled)
+ convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);
+ }
+
+ @Override
+ public void implBeforeTcpConnect(FileDescriptor fdObj,
+ InetAddress address,
+ int port)
+ throws IOException
+ {
+ if (enabled)
+ convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);
+ }
+}
--- a/jdk/src/solaris/classes/sun/net/spi/SdpProvider.java Thu Sep 16 11:17:32 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,339 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.spi;
-
-import sun.net.NetHooks;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-import java.util.*;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.PrintStream;
-
-import sun.misc.SharedSecrets;
-import sun.misc.JavaIOFileDescriptorAccess;
-
-/**
- * A NetHooks provider that converts sockets from the TCP to SDP protocol prior
- * to binding or connecting.
- */
-
-public class SdpProvider extends NetHooks.Provider {
- private static final JavaIOFileDescriptorAccess fdAccess =
- SharedSecrets.getJavaIOFileDescriptorAccess();
-
- // maximum port
- private static final int MAX_PORT = 65535;
-
- // indicates if SDP is enabled and the rules for when the protocol is used
- private final boolean enabled;
- private final List<Rule> rules;
-
- // logging for debug purposes
- private PrintStream log;
-
- public SdpProvider() {
- // if this property is not defined then there is nothing to do.
- String file = System.getProperty("com.sun.sdp.conf");
- if (file == null) {
- this.enabled = false;
- this.rules = null;
- return;
- }
-
- // load configuration file
- List<Rule> list = null;
- if (file != null) {
- try {
- list = loadRulesFromFile(file);
- } catch (IOException e) {
- fail("Error reading %s: %s", file, e.getMessage());
- }
- }
-
- // check if debugging is enabled
- PrintStream out = null;
- String logfile = System.getProperty("com.sun.sdp.debug");
- if (logfile != null) {
- out = System.out;
- if (logfile.length() > 0) {
- try {
- out = new PrintStream(logfile);
- } catch (IOException ignore) { }
- }
- }
-
- this.enabled = !list.isEmpty();
- this.rules = list;
- this.log = out;
- }
-
- // supported actions
- private static enum Action {
- BIND,
- CONNECT;
- }
-
- // a rule for matching a bind or connect request
- private static interface Rule {
- boolean match(Action action, InetAddress address, int port);
- }
-
- // rule to match port[-end]
- private static class PortRangeRule implements Rule {
- private final Action action;
- private final int portStart;
- private final int portEnd;
- PortRangeRule(Action action, int portStart, int portEnd) {
- this.action = action;
- this.portStart = portStart;
- this.portEnd = portEnd;
- }
- Action action() {
- return action;
- }
- @Override
- public boolean match(Action action, InetAddress address, int port) {
- return (action == this.action &&
- port >= this.portStart &&
- port <= this.portEnd);
- }
- }
-
- // rule to match address[/prefix] port[-end]
- private static class AddressPortRangeRule extends PortRangeRule {
- private final byte[] addressAsBytes;
- private final int prefixByteCount;
- private final byte mask;
- AddressPortRangeRule(Action action, InetAddress address,
- int prefix, int port, int end)
- {
- super(action, port, end);
- this.addressAsBytes = address.getAddress();
- this.prefixByteCount = prefix >> 3;
- this.mask = (byte)(0xff << (8 - (prefix % 8)));
- }
- @Override
- public boolean match(Action action, InetAddress address, int port) {
- if (action != action())
- return false;
- byte[] candidate = address.getAddress();
- // same address type?
- if (candidate.length != addressAsBytes.length)
- return false;
- // check bytes
- for (int i=0; i<prefixByteCount; i++) {
- if (candidate[i] != addressAsBytes[i])
- return false;
- }
- // check remaining bits
- if ((prefixByteCount < addressAsBytes.length) &&
- ((candidate[prefixByteCount] & mask) !=
- (addressAsBytes[prefixByteCount] & mask)))
- return false;
- return super.match(action, address, port);
- }
- }
-
- // parses port:[-end]
- private static int[] parsePortRange(String s) {
- int pos = s.indexOf('-');
- try {
- int[] result = new int[2];
- if (pos < 0) {
- boolean all = s.equals("*");
- result[0] = all ? 0 : Integer.parseInt(s);
- result[1] = all ? MAX_PORT : result[0];
- } else {
- String low = s.substring(0, pos);
- if (low.length() == 0) low = "*";
- String high = s.substring(pos+1);
- if (high.length() == 0) high = "*";
- result[0] = low.equals("*") ? 0 : Integer.parseInt(low);
- result[1] = high.equals("*") ? MAX_PORT : Integer.parseInt(high);
- }
- return result;
- } catch (NumberFormatException e) {
- return new int[0];
- }
- }
-
- private static void fail(String msg, Object... args) {
- Formatter f = new Formatter();
- f.format(msg, args);
- throw new RuntimeException(f.out().toString());
- }
-
- // loads rules from the given file
- // Each non-blank/non-comment line must have the format:
- // ("bind" | "connect") 1*LWSP-char (hostname | ipaddress["/" prefix])
- // 1*LWSP-char ("*" | port) [ "-" ("*" | port) ]
- private static List<Rule> loadRulesFromFile(String file)
- throws IOException
- {
- Scanner scanner = new Scanner(new File(file));
- try {
- List<Rule> result = new ArrayList<Rule>();
- while (scanner.hasNextLine()) {
- String line = scanner.nextLine().trim();
-
- // skip blank lines and comments
- if (line.length() == 0 || line.charAt(0) == '#')
- continue;
-
- // must have 3 fields
- String[] s = line.split("\\s+");
- if (s.length != 3) {
- fail("Malformed line '%s'", line);
- continue;
- }
-
- // first field is the action ("bind" or "connect")
- Action action = null;
- for (Action a: Action.values()) {
- if (s[0].equalsIgnoreCase(a.name())) {
- action = a;
- break;
- }
- }
- if (action == null) {
- fail("Action '%s' not recognized", s[0]);
- continue;
- }
-
- // * port[-end]
- int[] ports = parsePortRange(s[2]);
- if (ports.length == 0) {
- fail("Malformed port range '%s'", s[2]);
- continue;
- }
-
- // match all addresses
- if (s[1].equals("*")) {
- result.add(new PortRangeRule(action, ports[0], ports[1]));
- continue;
- }
-
- // hostname | ipaddress[/prefix]
- int pos = s[1].indexOf('/');
- try {
- if (pos < 0) {
- // hostname or ipaddress (no prefix)
- InetAddress[] addresses = InetAddress.getAllByName(s[1]);
- for (InetAddress address: addresses) {
- int prefix =
- (address instanceof Inet4Address) ? 32 : 128;
- result.add(new AddressPortRangeRule(action, address,
- prefix, ports[0], ports[1]));
- }
- } else {
- // ipaddress/prefix
- InetAddress address = InetAddress
- .getByName(s[1].substring(0, pos));
- int prefix = -1;
- try {
- prefix = Integer.parseInt(s[1].substring(pos+1));
- if (address instanceof Inet4Address) {
- // must be 1-31
- if (prefix < 0 || prefix > 32) prefix = -1;
- } else {
- // must be 1-128
- if (prefix < 0 || prefix > 128) prefix = -1;
- }
- } catch (NumberFormatException e) {
- }
-
- if (prefix > 0) {
- result.add(new AddressPortRangeRule(action,
- address, prefix, ports[0], ports[1]));
- } else {
- fail("Malformed prefix '%s'", s[1]);
- continue;
- }
- }
- } catch (UnknownHostException uhe) {
- fail("Unknown host or malformed IP address '%s'", s[1]);
- continue;
- }
- }
- return result;
- } finally {
- scanner.close();
- }
- }
-
- // converts unbound TCP socket to a SDP socket if it matches the rules
- private void convertTcpToSdpIfMatch(FileDescriptor fdObj,
- Action action,
- InetAddress address,
- int port)
- throws IOException
- {
- boolean matched = false;
- for (Rule rule: rules) {
- if (rule.match(action, address, port)) {
- int fd = fdAccess.get(fdObj);
- convert(fd);
- matched = true;
- break;
- }
- }
- if (log != null) {
- String addr = (address instanceof Inet4Address) ?
- address.getHostAddress() : "[" + address.getHostAddress() + "]";
- if (matched) {
- log.format("%s to %s:%d (socket converted to SDP protocol)\n", action, addr, port);
- } else {
- log.format("%s to %s:%d (no match)\n", action, addr, port);
- }
- }
- }
-
- @Override
- public void implBeforeTcpBind(FileDescriptor fdObj,
- InetAddress address,
- int port)
- throws IOException
- {
- if (enabled)
- convertTcpToSdpIfMatch(fdObj, Action.BIND, address, port);
- }
-
- @Override
- public void implBeforeTcpConnect(FileDescriptor fdObj,
- InetAddress address,
- int port)
- throws IOException
- {
- if (enabled)
- convertTcpToSdpIfMatch(fdObj, Action.CONNECT, address, port);
- }
-
- // -- native methods --
- private static native void convert(int fd) throws IOException;
-}
--- a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,20 +25,14 @@
package sun.net.www.protocol.http.ntlm;
+import com.sun.security.ntlm.Client;
+import com.sun.security.ntlm.NTLMException;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.UnknownHostException;
import java.net.URL;
import java.security.GeneralSecurityException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import javax.crypto.Cipher;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.DESKeySpec;
import sun.net.www.HeaderParser;
import sun.net.www.protocol.http.AuthenticationInfo;
@@ -72,14 +66,8 @@
*/
public class NTLMAuthentication extends AuthenticationInfo {
- private static final long serialVersionUID = -2403849171106437142L;
+ private static final long serialVersionUID = 170L;
- private byte[] type1;
- private byte[] type3;
-
- private SecretKeyFactory fac;
- private Cipher cipher;
- private MessageDigest md4;
private String hostname;
private static String defaultDomain; /* Domain to use if not specified by user */
@@ -94,53 +82,28 @@
}
private void init0() {
- type1 = new byte[256];
- type3 = new byte[256];
- System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,1}, 0, type1, 0, 9);
- type1[12] = (byte) 3;
- type1[13] = (byte) 0xb2;
- type1[28] = (byte) 0x20;
- System.arraycopy (new byte[] {'N','T','L','M','S','S','P',0,3}, 0, type3, 0, 9);
- type3[12] = (byte) 0x18;
- type3[14] = (byte) 0x18;
- type3[20] = (byte) 0x18;
- type3[22] = (byte) 0x18;
- type3[32] = (byte) 0x40;
- type3[60] = (byte) 1;
- type3[61] = (byte) 0x82;
- try {
- hostname = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<String>() {
- public String run() {
- String localhost;
- try {
- localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
- } catch (UnknownHostException e) {
- localhost = "localhost";
- }
- return localhost;
+ hostname = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<String>() {
+ public String run() {
+ String localhost;
+ try {
+ localhost = InetAddress.getLocalHost().getHostName().toUpperCase();
+ } catch (UnknownHostException e) {
+ localhost = "localhost";
}
- });
- int x = hostname.indexOf ('.');
- if (x != -1) {
- hostname = hostname.substring (0, x);
+ return localhost;
}
- fac = SecretKeyFactory.getInstance ("DES");
- cipher = Cipher.getInstance ("DES/ECB/NoPadding");
- md4 = sun.security.provider.MD4.getInstance();
- } catch (NoSuchPaddingException e) {
- assert false;
- } catch (NoSuchAlgorithmException e) {
- assert false;
+ });
+ int x = hostname.indexOf ('.');
+ if (x != -1) {
+ hostname = hostname.substring (0, x);
}
};
PasswordAuthentication pw;
- String username;
- String ntdomain;
- String password;
+ Client client;
/**
* Create a NTLMAuthentication:
* Username may be specified as domain<BACKSLASH>username in the application Authenticator.
@@ -156,6 +119,9 @@
}
private void init (PasswordAuthentication pw) {
+ String username;
+ String ntdomain;
+ char[] password;
this.pw = pw;
String s = pw.getUserName();
int i = s.indexOf ('\\');
@@ -166,8 +132,19 @@
ntdomain = s.substring (0, i).toUpperCase();
username = s.substring (i+1);
}
- password = new String (pw.getPassword());
+ password = pw.getPassword();
init0();
+ try {
+ client = new Client(System.getProperty("ntlm.version"), hostname,
+ username, ntdomain, password);
+ } catch (NTLMException ne) {
+ try {
+ client = new Client(null, hostname, username, ntdomain, password);
+ } catch (NTLMException ne2) {
+ // Will never happen
+ throw new AssertionError("Really?");
+ }
+ }
}
/**
@@ -240,181 +217,26 @@
}
}
- private void copybytes (byte[] dest, int destpos, String src, String enc) {
- try {
- byte[] x = src.getBytes(enc);
- System.arraycopy (x, 0, dest, destpos, x.length);
- } catch (UnsupportedEncodingException e) {
- assert false;
- }
- }
-
private String buildType1Msg () {
- int dlen = ntdomain.length();
- type1[16]= (byte) (dlen % 256);
- type1[17]= (byte) (dlen / 256);
- type1[18] = type1[16];
- type1[19] = type1[17];
-
- int hlen = hostname.length();
- type1[24]= (byte) (hlen % 256);
- type1[25]= (byte) (hlen / 256);
- type1[26] = type1[24];
- type1[27] = type1[25];
-
- copybytes (type1, 32, hostname, "ISO8859_1");
- copybytes (type1, hlen+32, ntdomain, "ISO8859_1");
- type1[20] = (byte) ((hlen+32) % 256);
- type1[21] = (byte) ((hlen+32) / 256);
-
- byte[] msg = new byte [32 + hlen + dlen];
- System.arraycopy (type1, 0, msg, 0, 32 + hlen + dlen);
+ byte[] msg = client.type1();
String result = "NTLM " + (new B64Encoder()).encode (msg);
return result;
}
-
- /* Convert a 7 byte array to an 8 byte array (for a des key with parity)
- * input starts at offset off
- */
- private byte[] makeDesKey (byte[] input, int off) {
- int[] in = new int [input.length];
- for (int i=0; i<in.length; i++ ) {
- in[i] = input[i]<0 ? input[i]+256: input[i];
- }
- byte[] out = new byte[8];
- out[0] = (byte)in[off+0];
- out[1] = (byte)(((in[off+0] << 7) & 0xFF) | (in[off+1] >> 1));
- out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2));
- out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3));
- out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4));
- out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5));
- out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6));
- out[7] = (byte)((in[off+6] << 1) & 0xFF);
- return out;
- }
-
- private byte[] calcLMHash () throws GeneralSecurityException {
- byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
- byte[] pwb = password.toUpperCase ().getBytes();
- byte[] pwb1 = new byte [14];
- int len = password.length();
- if (len > 14)
- len = 14;
- System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */
-
- DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0));
- DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7));
-
- SecretKey key1 = fac.generateSecret (dks1);
- SecretKey key2 = fac.generateSecret (dks2);
- cipher.init (Cipher.ENCRYPT_MODE, key1);
- byte[] out1 = cipher.doFinal (magic, 0, 8);
- cipher.init (Cipher.ENCRYPT_MODE, key2);
- byte[] out2 = cipher.doFinal (magic, 0, 8);
-
- byte[] result = new byte [21];
- System.arraycopy (out1, 0, result, 0, 8);
- System.arraycopy (out2, 0, result, 8, 8);
- return result;
- }
-
- private byte[] calcNTHash () throws GeneralSecurityException {
- byte[] pw = null;
- try {
- pw = password.getBytes ("UnicodeLittleUnmarked");
- } catch (UnsupportedEncodingException e) {
- assert false;
- }
- byte[] out = md4.digest (pw);
- byte[] result = new byte [21];
- System.arraycopy (out, 0, result, 0, 16);
- return result;
- }
-
- /* key is a 21 byte array. Split it into 3 7 byte chunks,
- * Convert each to 8 byte DES keys, encrypt the text arg with
- * each key and return the three results in a sequential []
- */
- private byte[] calcResponse (byte[] key, byte[] text)
- throws GeneralSecurityException {
- assert key.length == 21;
- DESKeySpec dks1 = new DESKeySpec (makeDesKey (key, 0));
- DESKeySpec dks2 = new DESKeySpec (makeDesKey (key, 7));
- DESKeySpec dks3 = new DESKeySpec (makeDesKey (key, 14));
- SecretKey key1 = fac.generateSecret (dks1);
- SecretKey key2 = fac.generateSecret (dks2);
- SecretKey key3 = fac.generateSecret (dks3);
- cipher.init (Cipher.ENCRYPT_MODE, key1);
- byte[] out1 = cipher.doFinal (text, 0, 8);
- cipher.init (Cipher.ENCRYPT_MODE, key2);
- byte[] out2 = cipher.doFinal (text, 0, 8);
- cipher.init (Cipher.ENCRYPT_MODE, key3);
- byte[] out3 = cipher.doFinal (text, 0, 8);
- byte[] result = new byte [24];
- System.arraycopy (out1, 0, result, 0, 8);
- System.arraycopy (out2, 0, result, 8, 8);
- System.arraycopy (out3, 0, result, 16, 8);
- return result;
- }
-
private String buildType3Msg (String challenge) throws GeneralSecurityException,
IOException {
/* First decode the type2 message to get the server nonce */
/* nonce is located at type2[24] for 8 bytes */
byte[] type2 = (new sun.misc.BASE64Decoder()).decodeBuffer (challenge);
- byte[] nonce = new byte [8];
- System.arraycopy (type2, 24, nonce, 0, 8);
-
- int ulen = username.length()*2;
- type3[36] = type3[38] = (byte) (ulen % 256);
- type3[37] = type3[39] = (byte) (ulen / 256);
- int dlen = ntdomain.length()*2;
- type3[28] = type3[30] = (byte) (dlen % 256);
- type3[29] = type3[31] = (byte) (dlen / 256);
- int hlen = hostname.length()*2;
- type3[44] = type3[46] = (byte) (hlen % 256);
- type3[45] = type3[47] = (byte) (hlen / 256);
-
- int l = 64;
- copybytes (type3, l, ntdomain, "UnicodeLittleUnmarked");
- type3[32] = (byte) (l % 256);
- type3[33] = (byte) (l / 256);
- l += dlen;
- copybytes (type3, l, username, "UnicodeLittleUnmarked");
- type3[40] = (byte) (l % 256);
- type3[41] = (byte) (l / 256);
- l += ulen;
- copybytes (type3, l, hostname, "UnicodeLittleUnmarked");
- type3[48] = (byte) (l % 256);
- type3[49] = (byte) (l / 256);
- l += hlen;
-
- byte[] lmhash = calcLMHash();
- byte[] lmresponse = calcResponse (lmhash, nonce);
- byte[] nthash = calcNTHash();
- byte[] ntresponse = calcResponse (nthash, nonce);
- System.arraycopy (lmresponse, 0, type3, l, 24);
- type3[16] = (byte) (l % 256);
- type3[17] = (byte) (l / 256);
- l += 24;
- System.arraycopy (ntresponse, 0, type3, l, 24);
- type3[24] = (byte) (l % 256);
- type3[25] = (byte) (l / 256);
- l += 24;
- type3[56] = (byte) (l % 256);
- type3[57] = (byte) (l / 256);
-
- byte[] msg = new byte [l];
- System.arraycopy (type3, 0, msg, 0, l);
+ byte[] nonce = new byte[8];
+ new java.util.Random().nextBytes(nonce);
+ byte[] msg = client.type3(type2, nonce);
String result = "NTLM " + (new B64Encoder()).encode (msg);
return result;
}
-
}
-
class B64Encoder extends sun.misc.BASE64Encoder {
/* to force it to to the entire encoding in one line */
protected int bytesPerLine () {
--- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -65,10 +65,9 @@
*/
DevPollSelectorImpl(SelectorProvider sp) {
super(sp);
- int[] fdes = new int[2];
- IOUtil.initPipe(fdes, false);
- fd0 = fdes[0];
- fd1 = fdes[1];
+ long pipeFds = IOUtil.makePipe(false);
+ fd0 = (int) (pipeFds >>> 32);
+ fd1 = (int) pipeFds;
pollWrapper = new DevPollArrayWrapper();
pollWrapper.initInterrupt(fd0, fd1);
fdToKey = new HashMap<Integer,SelectionKeyImpl>();
@@ -147,7 +146,7 @@
selectedKeys = null;
// Deregister channels
- Iterator i = keys.iterator();
+ Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
--- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -62,10 +62,9 @@
*/
EPollSelectorImpl(SelectorProvider sp) {
super(sp);
- int[] fdes = new int[2];
- IOUtil.initPipe(fdes, false);
- fd0 = fdes[0];
- fd1 = fdes[1];
+ long pipeFds = IOUtil.makePipe(false);
+ fd0 = (int) (pipeFds >>> 32);
+ fd1 = (int) pipeFds;
pollWrapper = new EPollArrayWrapper();
pollWrapper.initInterrupt(fd0, fd1);
fdToKey = new HashMap<Integer,SelectionKeyImpl>();
@@ -144,7 +143,7 @@
selectedKeys = null;
// Deregister channels
- Iterator i = keys.iterator();
+ Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
--- a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java Thu Sep 16 11:19:43 2010 -0700
@@ -96,7 +96,7 @@
FileDescriptor fd)
throws IOException
{
- super(sp, fd);
+ super(sp, fd, true);
}
protected void implCloseSelectableChannel() throws IOException {
--- a/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/PipeImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -39,13 +39,14 @@
private final SinkChannel sink;
PipeImpl(SelectorProvider sp) {
- int[] fdes = new int[2];
- IOUtil.initPipe(fdes, true);
+ long pipeFds = IOUtil.makePipe(true);
+ int readFd = (int) (pipeFds >>> 32);
+ int writeFd = (int) pipeFds;
FileDescriptor sourcefd = new FileDescriptor();
- IOUtil.setfdVal(sourcefd, fdes[0]);
+ IOUtil.setfdVal(sourcefd, readFd);
source = new SourceChannelImpl(sp, sourcefd);
FileDescriptor sinkfd = new FileDescriptor();
- IOUtil.setfdVal(sinkfd, fdes[1]);
+ IOUtil.setfdVal(sinkfd, writeFd);
sink = new SinkChannelImpl(sp, sinkfd);
}
--- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java Thu Sep 16 11:19:43 2010 -0700
@@ -54,10 +54,9 @@
*/
PollSelectorImpl(SelectorProvider sp) {
super(sp, 1, 1);
- int[] fdes = new int[2];
- IOUtil.initPipe(fdes, false);
- fd0 = fdes[0];
- fd1 = fdes[1];
+ long pipeFds = IOUtil.makePipe(false);
+ fd0 = (int) (pipeFds >>> 32);
+ fd1 = (int) pipeFds;
pollWrapper = new PollArrayWrapper(INIT_CAP);
pollWrapper.initInterrupt(fd0, fd1);
channelArray = new SelectionKeyImpl[INIT_CAP];
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Thu Sep 16 11:19:43 2010 -0700
@@ -27,7 +27,6 @@
import java.nio.file.*;
import java.util.Iterator;
-import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.concurrent.locks.*;
import java.io.IOException;
@@ -139,9 +138,6 @@
// next entry to return
private Path nextEntry;
- // previous entry returned by next method (needed by remove method)
- private Path prevEntry;
-
UnixDirectoryIterator(DirectoryStream<Path> stream) {
atEof = false;
this.stream = stream;
@@ -168,24 +164,19 @@
// prevent close while reading
readLock().lock();
try {
- if (isClosed)
- throwAsConcurrentModificationException(new
- ClosedDirectoryStreamException());
- try {
+ if (isOpen()) {
nameAsBytes = readdir(dp);
- } catch (UnixException x) {
- try {
- x.rethrowAsIOException(dir);
- } catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
- }
}
+ } catch (UnixException x) {
+ IOException ioe = x.asIOException(dir);
+ throw new DirectoryIteratorException(ioe);
} finally {
readLock().unlock();
}
// EOF
if (nameAsBytes == null) {
+ atEof = true;
return null;
}
@@ -198,7 +189,7 @@
if (filter == null || filter.accept(entry))
return entry;
} catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
+ throw new DirectoryIteratorException(ioe);
}
}
}
@@ -206,66 +197,28 @@
@Override
public synchronized boolean hasNext() {
- if (nextEntry == null && !atEof) {
+ if (nextEntry == null && !atEof)
nextEntry = readNextEntry();
-
- // at EOF?
- if (nextEntry == null)
- atEof = true;
- }
return nextEntry != null;
}
@Override
public synchronized Path next() {
- if (nextEntry == null) {
- if (!atEof) {
- nextEntry = readNextEntry();
- }
- if (nextEntry == null) {
- atEof = true;
- throw new NoSuchElementException();
- }
+ Path result;
+ if (nextEntry == null && !atEof) {
+ result = readNextEntry();
+ } else {
+ result = nextEntry;
+ nextEntry = null;
}
- prevEntry = nextEntry;
- nextEntry = null;
- return prevEntry;
+ if (result == null)
+ throw new NoSuchElementException();
+ return result;
}
@Override
public void remove() {
- if (isClosed) {
- throwAsConcurrentModificationException(new
- ClosedDirectoryStreamException());
- }
- Path entry;
- synchronized (this) {
- if (prevEntry == null)
- throw new IllegalStateException("No previous entry to remove");
- entry = prevEntry;
- prevEntry = null;
- }
-
- // use (race-free) unlinkat if available
- try {
- if (stream instanceof UnixSecureDirectoryStream) {
- ((UnixSecureDirectoryStream)stream)
- .implDelete(entry.getName(), false, 0);
- } else {
- entry.delete();
- }
- } catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
- } catch (SecurityException se) {
- throwAsConcurrentModificationException(se);
- }
+ throw new UnsupportedOperationException();
}
}
-
- private static void throwAsConcurrentModificationException(Throwable t) {
- ConcurrentModificationException cme = new ConcurrentModificationException();
- cme.initCause(t);
- throw cme;
- }
-
}
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java Thu Sep 16 11:19:43 2010 -0700
@@ -166,7 +166,7 @@
* Deletes file/directory in this directory. Works in a race-free manner
* when invoked with flags.
*/
- void implDelete(Path obj, boolean haveFlags, int flags)
+ private void implDelete(Path obj, boolean haveFlags, int flags)
throws IOException
{
UnixPath file = getName(obj);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/net/sdp/SdpSupport.c Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#if defined(__solaris__)
+ #if !defined(PROTO_SDP)
+ #define PROTO_SDP 257
+ #endif
+#elif defined(__linux__)
+ #if !defined(AF_INET_SDP)
+ #define AF_INET_SDP 27
+ #endif
+#endif
+
+#include "jni.h"
+#include "jni_util.h"
+#include "net_util.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+ do { \
+ _result = _cmd; \
+ } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+
+/**
+ * Creates a SDP socket.
+ */
+static int create(JNIEnv* env)
+{
+ int s;
+
+#if defined(__solaris__)
+ #ifdef AF_INET6
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+ #else
+ int domain = AF_INET;
+ #endif
+ s = socket(domain, SOCK_STREAM, PROTO_SDP);
+#elif defined(__linux__)
+ /**
+ * IPv6 not supported by SDP on Linux
+ */
+ if (ipv6_available()) {
+ JNU_ThrowIOException(env, "IPv6 not supported");
+ return;
+ }
+ s = socket(AF_INET_SDP, SOCK_STREAM, 0);
+#else
+ /* not supported on other platforms at this time */
+ s = -1;
+ errno = EPROTONOSUPPORT;
+#endif
+
+ if (s < 0)
+ JNU_ThrowIOExceptionWithLastError(env, "socket");
+ return s;
+}
+
+/**
+ * Creates a SDP socket, returning file descriptor referencing the socket.
+ */
+JNIEXPORT jint JNICALL
+Java_sun_net_sdp_SdpSupport_create0(JNIEnv *env, jclass cls)
+{
+ return create(env);
+}
+
+/**
+ * Converts an existing file descriptor, that references an unbound TCP socket,
+ * to SDP.
+ */
+JNIEXPORT void JNICALL
+Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd)
+{
+ int s = create(env);
+ if (s >= 0) {
+ socklen_t len;
+ int arg, res;
+ struct linger linger;
+
+ /* copy socket options that are relevant to SDP */
+ len = sizeof(arg);
+ if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
+ len = sizeof(arg);
+ if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
+ len = sizeof(linger);
+ if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0)
+ setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len);
+
+ RESTARTABLE(dup2(s, fd), res);
+ if (res < 0)
+ JNU_ThrowIOExceptionWithLastError(env, "dup2");
+ RESTARTABLE(close(s), res);
+ }
+}
--- a/jdk/src/solaris/native/sun/net/spi/SdpProvider.c Thu Sep 16 11:17:32 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#if defined(__solaris__) && !defined(PROTO_SDP)
-#define PROTO_SDP 257
-#endif
-
-#include "jni.h"
-#include "jni_util.h"
-#include "net_util.h"
-
-#define RESTARTABLE(_cmd, _result) do { \
- do { \
- _result = _cmd; \
- } while((_result == -1) && (errno == EINTR)); \
-} while(0)
-
-JNIEXPORT void JNICALL
-Java_sun_net_spi_SdpProvider_convert(JNIEnv *env, jclass cls, jint fd)
-{
-#ifdef PROTO_SDP
-#ifdef AF_INET6
- int domain = ipv6_available() ? AF_INET6 : AF_INET;
-#else
- int domain = AF_INET;
-#endif
- int s = socket(domain, SOCK_STREAM, PROTO_SDP);
- if (s < 0) {
- JNU_ThrowIOExceptionWithLastError(env, "socket");
- } else {
- int arg, len, res;
- struct linger linger;
-
- /* copy socket options that are relevant to SDP */
- len = sizeof(arg);
- if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
- len = sizeof(arg);
- if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
- setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
- len = sizeof(linger);
- if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (void*)&linger, &len) == 0)
- setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&linger, len);
-
- RESTARTABLE(dup2(s, fd), res);
- if (res < 0)
- JNU_ThrowIOExceptionWithLastError(env, "dup2");
- RESTARTABLE(close(s), res);
- }
-#else
- JNU_ThrowInternalError(env, "should not reach here");
-#endif
-}
--- a/jdk/src/solaris/native/sun/nio/ch/IOUtil.c Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/solaris/native/sun/nio/ch/IOUtil.c Thu Sep 16 11:19:43 2010 -0700
@@ -67,12 +67,9 @@
configureBlocking(int fd, jboolean blocking)
{
int flags = fcntl(fd, F_GETFL);
+ int newflags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
- if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK))
- return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- else if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK))
- return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
- return 0;
+ return (flags == newflags) ? 0 : fcntl(fd, F_SETFL, newflags);
}
JNIEXPORT void JNICALL
@@ -83,27 +80,25 @@
JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed");
}
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_IOUtil_initPipe(JNIEnv *env, jobject this,
- jintArray intArray, jboolean block)
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_IOUtil_makePipe(JNIEnv *env, jobject this, jboolean blocking)
{
int fd[2];
- jint *ptr = 0;
if (pipe(fd) < 0) {
JNU_ThrowIOExceptionWithLastError(env, "Pipe failed");
- return;
+ return 0;
}
- if (block == JNI_FALSE) {
+ if (blocking == JNI_FALSE) {
if ((configureBlocking(fd[0], JNI_FALSE) < 0)
|| (configureBlocking(fd[1], JNI_FALSE) < 0)) {
JNU_ThrowIOExceptionWithLastError(env, "Configure blocking failed");
+ close(fd[0]);
+ close(fd[1]);
+ return 0;
}
}
- ptr = (*env)->GetPrimitiveArrayCritical(env, intArray, 0);
- ptr[0] = fd[0];
- ptr[1] = fd[1];
- (*env)->ReleasePrimitiveArrayCritical(env, intArray, ptr, 0);
+ return ((jlong) fd[0] << 32) | (jlong) fd[1];
}
JNIEXPORT jboolean JNICALL
@@ -131,21 +126,22 @@
{
if (n > 0) /* Number of bytes written */
return n;
- if (n < 0) {
- if (errno == EAGAIN)
- return IOS_UNAVAILABLE;
- if (errno == EINTR)
- return IOS_INTERRUPTED;
- }
- if (n == 0) {
+ else if (n == 0) {
if (reading) {
return IOS_EOF; /* EOF is -1 in javaland */
} else {
return 0;
}
}
- JNU_ThrowIOExceptionWithLastError(env, "Read/write failed");
- return IOS_THROWN;
+ else if (errno == EAGAIN)
+ return IOS_UNAVAILABLE;
+ else if (errno == EINTR)
+ return IOS_INTERRUPTED;
+ else {
+ const char *msg = reading ? "Read failed" : "Write failed";
+ JNU_ThrowIOExceptionWithLastError(env, msg);
+ return IOS_THROWN;
+ }
}
/* Declared in nio_util.h for use elsewhere in NIO */
@@ -155,21 +151,22 @@
{
if (n > 0) /* Number of bytes written */
return n;
- if (n < 0) {
- if (errno == EAGAIN)
- return IOS_UNAVAILABLE;
- if (errno == EINTR)
- return IOS_INTERRUPTED;
- }
- if (n == 0) {
+ else if (n == 0) {
if (reading) {
return IOS_EOF; /* EOF is -1 in javaland */
} else {
return 0;
}
}
- JNU_ThrowIOExceptionWithLastError(env, "Read/write failed");
- return IOS_THROWN;
+ else if (errno == EAGAIN)
+ return IOS_UNAVAILABLE;
+ else if (errno == EINTR)
+ return IOS_INTERRUPTED;
+ else {
+ const char *msg = reading ? "Read failed" : "Write failed";
+ JNU_ThrowIOExceptionWithLastError(env, msg);
+ return IOS_THROWN;
+ }
}
jint
--- a/jdk/src/windows/bin/java_md.c Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/windows/bin/java_md.c Thu Sep 16 11:19:43 2010 -0700
@@ -105,15 +105,15 @@
exit(1);
}
- /* Do this before we read jvm.cfg */
- EnsureJreInstallation(jrepath);
-
/* Find out where the JRE is that we will be using. */
if (!GetJREPath(jrepath, so_jrepath)) {
JLI_ReportErrorMessage(JRE_ERROR1);
exit(2);
}
+ /* Do this before we read jvm.cfg and after jrepath is initialized */
+ EnsureJreInstallation(jrepath);
+
/* Find the specified JVM type */
if (ReadKnownVMs(jrepath, (char*)GetArch(), JNI_FALSE) < 1) {
JLI_ReportErrorMessage(CFG_ERROR7);
@@ -162,6 +162,10 @@
#endif
#ifdef CRT_DLL
if (GetJREPath(crtpath, MAXPATHLEN)) {
+ if (JLI_StrLen(crtpath) + JLI_StrLen("\\bin\\") + JLI_StrLen(CRT_DLL) >= MAXPATHLEN) {
+ JLI_ReportErrorMessage(JRE_ERROR11);
+ return JNI_FALSE;
+ }
(void)JLI_StrCat(crtpath, "\\bin\\" CRT_DLL); /* Add crt dll */
JLI_TraceLauncher("CRT path is %s\n", crtpath);
if (_access(crtpath, 0) == 0) {
@@ -213,6 +217,7 @@
}
/* Does our bundle directory exist ? */
JLI_Snprintf(tmpbuf, sizeof(tmpbuf), "%s\\lib\\bundles", jrepath);
+ JLI_TraceLauncher("EnsureJreInstallation: %s\n", tmpbuf);
if (stat(tmpbuf, &s) != 0) {
return;
}
@@ -851,8 +856,7 @@
/*
* If this isn't the selected version, exec the selected version.
*/
- (void)JLI_StrCat(JLI_StrCat(JLI_StrCpy(path, jre), "\\bin\\"), progname);
- (void)JLI_StrCat(path, ".exe");
+ JLI_Snprintf(path, sizeof(path), "%s\\bin\\%s.exe", jre, progname);
/*
* Although Windows has an execv() entrypoint, it doesn't actually
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java Thu Sep 16 11:19:43 2010 -0700
@@ -28,7 +28,6 @@
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Iterator;
-import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.io.IOException;
@@ -121,17 +120,10 @@
}
}
- private static void throwAsConcurrentModificationException(Throwable t) {
- ConcurrentModificationException cme = new ConcurrentModificationException();
- cme.initCause(t);
- throw cme;
- }
-
private class WindowsDirectoryIterator implements Iterator<Path> {
private boolean atEof;
private String first;
private Path nextEntry;
- private Path prevEntry;
WindowsDirectoryIterator(String first) {
atEof = false;
@@ -156,7 +148,7 @@
if (filter.accept(entry))
return entry;
} catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
+ throw new DirectoryIteratorException(ioe);
}
return null;
}
@@ -177,21 +169,19 @@
// synchronize on closeLock to prevent close while reading
synchronized (closeLock) {
- if (!isOpen)
- throwAsConcurrentModificationException(new
- ClosedDirectoryStreamException());
try {
- name = FindNextFile(handle, findDataBuffer.address());
- if (name == null) {
- // NO_MORE_FILES
- return null;
+ if (isOpen) {
+ name = FindNextFile(handle, findDataBuffer.address());
}
} catch (WindowsException x) {
- try {
- x.rethrowAsIOException(dir);
- } catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
- }
+ IOException ioe = x.asIOException(dir);
+ throw new DirectoryIteratorException(ioe);
+ }
+
+ // NO_MORE_FILES or stream closed
+ if (name == null) {
+ atEof = true;
+ return null;
}
// grab the attributes from the WIN32_FIND_DATA structure
@@ -210,49 +200,28 @@
@Override
public synchronized boolean hasNext() {
- if (nextEntry == null && !atEof) {
+ if (nextEntry == null && !atEof)
nextEntry = readNextEntry();
- atEof = (nextEntry == null);
- }
return nextEntry != null;
}
@Override
public synchronized Path next() {
- if (nextEntry == null) {
- if (!atEof) {
- nextEntry = readNextEntry();
- }
- if (nextEntry == null) {
- atEof = true;
- throw new NoSuchElementException();
- }
+ Path result = null;
+ if (nextEntry == null && !atEof) {
+ result = readNextEntry();
+ } else {
+ result = nextEntry;
+ nextEntry = null;
}
- prevEntry = nextEntry;
- nextEntry = null;
- return prevEntry;
+ if (result == null)
+ throw new NoSuchElementException();
+ return result;
}
@Override
public void remove() {
- if (!isOpen) {
- throwAsConcurrentModificationException(new
- ClosedDirectoryStreamException());
- }
- Path entry;
- synchronized (this) {
- if (prevEntry == null)
- throw new IllegalStateException("no last element");
- entry = prevEntry;
- prevEntry = null;
- }
- try {
- entry.delete();
- } catch (IOException ioe) {
- throwAsConcurrentModificationException(ioe);
- } catch (SecurityException se) {
- throwAsConcurrentModificationException(se);
- }
+ throw new UnsupportedOperationException();
}
}
}
--- a/jdk/test/ProblemList.txt Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/ProblemList.txt Thu Sep 16 11:19:43 2010 -0700
@@ -201,9 +201,6 @@
# Windows X64, RuntimeException: MyThread expected to have RUNNABLE but got WAITING
java/lang/Thread/ThreadStateTest.java generic-all
-# Timeout on windows 64bit
-java/lang/ClassLoader/deadlock/TestCrossDelegate.sh generic-all
-
############################################################################
# jdk_management
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/oracle/net/Sanity.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.net.Sdp;
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.*;
+
+/**
+ * Exercise com.oracle.net.Sdp with each IP address plumbed to InfiniBand
+ * interfaces listed in a given file.
+ */
+
+public class Sanity {
+ public static void main(String[] args) throws Exception {
+ // The file is a list of interfaces to test.
+ Scanner s = new Scanner(new File(args[0]));
+ try {
+ while (s.hasNextLine()) {
+ String link = s.nextLine();
+ NetworkInterface ni = NetworkInterface.getByName(link);
+ if (ni != null) {
+ Enumeration<InetAddress> addrs = ni.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ InetAddress addr = addrs.nextElement();
+ System.out.format("Testing %s: %s\n", link, addr.getHostAddress());
+ test(addr);
+ }
+ }
+ }
+ } finally {
+ s.close();
+ }
+ }
+
+ static void test(InetAddress addr) throws Exception {
+ // Test SocketChannel and ServerSocketChannel
+ ServerSocketChannel ssc = Sdp.openServerSocketChannel();
+ try {
+ ssc.socket().bind(new InetSocketAddress(addr, 0));
+ int port = ssc.socket().getLocalPort();
+
+ // SocketChannel.connect (implicit bind)
+ SocketChannel client = Sdp.openSocketChannel();
+ try {
+ client.connect(new InetSocketAddress(addr, port));
+ SocketChannel peer = ssc.accept();
+ try {
+ testConnection(Channels.newOutputStream(client),
+ Channels.newInputStream(peer));
+ } finally {
+ peer.close();
+ }
+ } finally {
+ client.close();
+ }
+
+ // SocketChannel.connect (explicit bind)
+ client = Sdp.openSocketChannel();
+ try {
+ client.socket().bind(new InetSocketAddress(addr, 0));
+ client.connect(new InetSocketAddress(addr, port));
+ ssc.accept().close();
+ } finally {
+ client.close();
+ }
+ } finally {
+ ssc.close();
+ }
+
+ // Test Socket and ServerSocket
+ ServerSocket ss = Sdp.openServerSocket();
+ try {
+ ss.bind(new InetSocketAddress(addr, 0));
+ int port = ss.getLocalPort();
+
+ // Socket.connect (implicit bind)
+ Socket s = Sdp.openSocket();
+ try {
+ s.connect(new InetSocketAddress(addr, port));
+ Socket peer = ss.accept();
+ try {
+ testConnection(s.getOutputStream(), peer.getInputStream());
+ } finally {
+ peer.close();
+ }
+ } finally {
+ s.close();
+ }
+
+ // Socket.connect (explicit bind)
+ s = Sdp.openSocket();
+ try {
+ s.bind(new InetSocketAddress(addr, 0));
+ s.connect(new InetSocketAddress(addr, port));
+ ss.accept().close();
+ } finally {
+ s.close();
+ }
+ } finally {
+ ss.close();
+ }
+ }
+
+ static void testConnection(OutputStream out, InputStream in)
+ throws IOException
+ {
+ byte[] msg = "hello".getBytes();
+ out.write(msg);
+
+ byte[] ba = new byte[100];
+ int nread = 0;
+ while (nread < msg.length) {
+ int n = in.read(ba);
+ if (n < 0)
+ throw new IOException("EOF not expected!");
+ nread += n;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/oracle/net/sanity.sh Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 6965072
+# @summary Unit test for SDP support
+# @build Sanity
+# @run shell sanity.sh
+
+IB_LINKS=ib.links
+
+OS=`uname -s`
+case "$OS" in
+ SunOS )
+ /usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS}
+ if [ $? != 0 ]; then
+ echo "Unable to get InfiniBand parition link information"
+ exit 0
+ fi
+ ;;
+ Linux )
+ if [ ! -f /proc/net/sdp ]; then
+ echo "InfiniBand SDP module not installed"
+ exit 0
+ fi
+ egrep "^[ \t]+ib" /proc/net/dev|cut -d':' -f1|tr -d '\t ' > ${IB_LINKS}
+ ;;
+ * )
+ echo "This test only runs on Solaris or Linux"
+ exit 0
+ ;;
+esac
+
+if [ -z "$TESTJAVA" ]; then
+ JAVA=java
+ TESTCLASSES=.
+ TESTSRC=.
+else
+ JAVA="${TESTJAVA}/bin/java"
+fi
+
+CLASSPATH=${TESTCLASSES}:${TESTSRC}
+export CLASSPATH
+
+# Run sanity test (IPv4-only for now)
+$JAVA -Djava.net.preferIPv4Stack=true Sanity ${IB_LINKS}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/security/sasl/ntlm/NTLMTest.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6911951
+ * @summary NTLM should be a supported Java SASL mechanism
+ */
+import java.io.IOException;
+import javax.security.sasl.*;
+import javax.security.auth.callback.*;
+import java.util.*;
+
+import com.sun.security.ntlm.NTLMException;
+
+public class NTLMTest {
+
+ private static final String MECH = "NTLM";
+ private static final String REALM = "REALM";
+ private static final String PROTOCOL = "jmx";
+ private static final byte[] EMPTY = new byte[0];
+
+ private static final String USER1 = "dummy";
+ private static final char[] PASS1 = "bogus".toCharArray();
+ private static final String USER2 = "foo";
+ private static final char[] PASS2 = "bar".toCharArray();
+
+ private static final Map<String,char[]> maps =
+ new HashMap<String,char[]>();
+ static {
+ maps.put(USER1, PASS1);
+ maps.put(USER2, PASS2);
+ }
+
+ static char[] getPass(String d, String u) {
+ if (!d.equals(REALM)) return null;
+ return maps.get(u);
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ checkAuthOnly();
+ checkClientNameOverride();
+ checkServerDomainOverride();
+ checkClientDomainOverride();
+ checkVersions();
+ checkClientHostname();
+ }
+
+ static void checkVersions() throws Exception {
+ // Server accepts all version
+ checkVersion(null, null);
+ checkVersion("LM/NTLM", null);
+ checkVersion("LM", null);
+ checkVersion("NTLM", null);
+ checkVersion("NTLM2", null);
+ checkVersion("LMv2/NTLMv2", null);
+ checkVersion("LMv2", null);
+ checkVersion("NTLMv2", null);
+
+ // Client's default version is LMv2
+ checkVersion(null, "LMv2");
+
+ // Also works if they specified identical versions
+ checkVersion("LM/NTLM", "LM");
+ checkVersion("LM", "LM");
+ checkVersion("NTLM", "LM");
+ checkVersion("NTLM2", "NTLM2");
+ checkVersion("LMv2/NTLMv2", "LMv2");
+ checkVersion("LMv2", "LMv2");
+ checkVersion("NTLMv2", "LMv2");
+
+ // But should not work if different
+ try {
+ checkVersion("LM/NTLM", "LMv2");
+ throw new Exception("Should not succeed");
+ } catch (SaslException se) {
+ NTLMException ne = (NTLMException)se.getCause();
+ if (ne.errorCode() != NTLMException.AUTH_FAILED) {
+ throw new Exception("Failed false");
+ }
+ }
+ try {
+ checkVersion("LMv2/NTLMv2", "LM");
+ throw new Exception("Should not succeed");
+ } catch (SaslException se) {
+ NTLMException ne = (NTLMException)se.getCause();
+ if (ne.errorCode() != NTLMException.AUTH_FAILED) {
+ throw new Exception("Failed false");
+ }
+ }
+
+ }
+
+ /**
+ * A test on version matching
+ * @param vc ntlm version specified for client
+ * @param vs ntlm version specified for server
+ * @throws Exception
+ */
+ private static void checkVersion(String vc, String vs) throws Exception {
+ Map<String,Object> pc = new HashMap<>();
+ pc.put("com.sun.security.sasl.ntlm.version", vc);
+ Map<String,Object> ps = new HashMap<>();
+ ps.put("com.sun.security.sasl.ntlm.version", vs);
+ SaslClient clnt = Sasl.createSaslClient(
+ new String[]{MECH}, USER1, PROTOCOL, null, pc,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)cb;
+ ncb.setName(ncb.getDefaultName());
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback)cb).setPassword(PASS1);
+ }
+ }
+ }
+ });
+
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, ps,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ String domain = null, name = null;
+ PasswordCallback pcb = null;
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ name = ((NameCallback)cb).getDefaultName();
+ } else if (cb instanceof RealmCallback) {
+ domain = ((RealmCallback)cb).getDefaultText();
+ } else if (cb instanceof PasswordCallback) {
+ pcb = (PasswordCallback)cb;
+ }
+ }
+ if (pcb != null) {
+ pcb.setPassword(getPass(domain, name));
+ }
+ }
+ });
+
+ handshake(clnt, srv);
+ }
+
+ private static void checkClientHostname() throws Exception {
+ Map<String,Object> pc = new HashMap<>();
+ pc.put("com.sun.security.sasl.ntlm.hostname", "this.is.com");
+ SaslClient clnt = Sasl.createSaslClient(
+ new String[]{MECH}, USER1, PROTOCOL, null, pc,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)cb;
+ ncb.setName(ncb.getDefaultName());
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback)cb).setPassword(PASS1);
+ }
+ }
+ }
+ });
+
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ String domain = null, name = null;
+ PasswordCallback pcb = null;
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ name = ((NameCallback)cb).getDefaultName();
+ } else if (cb instanceof RealmCallback) {
+ domain = ((RealmCallback)cb).getDefaultText();
+ } else if (cb instanceof PasswordCallback) {
+ pcb = (PasswordCallback)cb;
+ }
+ }
+ if (pcb != null) {
+ pcb.setPassword(getPass(domain, name));
+ }
+ }
+ });
+
+ handshake(clnt, srv);
+ if (!"this.is.com".equals(
+ srv.getNegotiatedProperty("com.sun.security.sasl.ntlm.hostname"))) {
+ throw new Exception("Hostname not trasmitted to server");
+ }
+ }
+
+ /**
+ * Client realm override, but finally overridden by server response
+ */
+ private static void checkClientDomainOverride() throws Exception {
+ SaslClient clnt = Sasl.createSaslClient(
+ new String[]{MECH}, USER1, PROTOCOL, "ANOTHERREALM", null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)cb;
+ ncb.setName(ncb.getDefaultName());
+ } else if(cb instanceof RealmCallback) {
+ RealmCallback dcb = (RealmCallback)cb;
+ dcb.setText("THIRDDOMAIN");
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback)cb).setPassword(PASS1);
+ }
+ }
+ }
+ });
+
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ String domain = null, name = null;
+ PasswordCallback pcb = null;
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ name = ((NameCallback)cb).getDefaultName();
+ } else if (cb instanceof RealmCallback) {
+ domain = ((RealmCallback)cb).getDefaultText();
+ } else if (cb instanceof PasswordCallback) {
+ pcb = (PasswordCallback)cb;
+ }
+ }
+ if (pcb != null) {
+ pcb.setPassword(getPass(domain, name));
+ }
+ }
+ });
+
+ handshake(clnt, srv);
+ }
+
+ /**
+ * Client side user name provided in callback.
+ * @throws Exception
+ */
+ private static void checkClientNameOverride() throws Exception {
+ SaslClient clnt = Sasl.createSaslClient(
+ new String[]{MECH}, null, PROTOCOL, null, null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)cb;
+ ncb.setName(USER1);
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback)cb).setPassword(PASS1);
+ }
+ }
+ }
+ });
+
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, REALM, null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ String domain = null, name = null;
+ PasswordCallback pcb = null;
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ name = ((NameCallback)cb).getDefaultName();
+ } else if (cb instanceof RealmCallback) {
+ domain = ((RealmCallback)cb).getDefaultText();
+ } else if (cb instanceof PasswordCallback) {
+ pcb = (PasswordCallback)cb;
+ }
+ }
+ if (pcb != null) {
+ pcb.setPassword(getPass(domain, name));
+ }
+ }
+ });
+
+ handshake(clnt, srv);
+ }
+
+ /**
+ * server side domain provided in props.
+ * @throws Exception
+ */
+ private static void checkServerDomainOverride() throws Exception {
+ SaslClient clnt = Sasl.createSaslClient(
+ new String[]{MECH}, USER1, PROTOCOL, null, null,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ NameCallback ncb = (NameCallback)cb;
+ ncb.setName(ncb.getDefaultName());
+ } else if (cb instanceof PasswordCallback) {
+ ((PasswordCallback)cb).setPassword(PASS1);
+ }
+ }
+ }
+ });
+
+ Map<String,Object> ps = new HashMap<>();
+ ps.put("com.sun.security.sasl.ntlm.domain", REALM);
+ SaslServer srv = Sasl.createSaslServer(MECH, PROTOCOL, null, ps,
+ new CallbackHandler() {
+ public void handle(Callback[] callbacks)
+ throws IOException, UnsupportedCallbackException {
+ String domain = null, name = null;
+ PasswordCallback pcb = null;
+ for (Callback cb: callbacks) {
+ if (cb instanceof NameCallback) {
+ name = ((NameCallback)cb).getDefaultName();
+ } else if (cb instanceof RealmCallback) {
+ domain = ((RealmCallback)cb).getDefaultText();
+ } else if (cb instanceof PasswordCallback) {
+ pcb = (PasswordCallback)cb;
+ }
+ }
+ if (pcb != null) {
+ pcb.setPassword(getPass(domain, name));
+ }
+ }
+ });
+
+ handshake(clnt, srv);
+ }
+
+ private static void checkAuthOnly() throws Exception {
+ Map<String,Object> props = new HashMap<>();
+ props.put(Sasl.QOP, "auth-conf");
+ try {
+ Sasl.createSaslClient(
+ new String[]{MECH}, USER2, PROTOCOL, REALM, props, null);
+ throw new Exception("NTLM should not support auth-conf");
+ } catch (SaslException se) {
+ // Normal
+ }
+ }
+
+ private static void handshake(SaslClient clnt, SaslServer srv)
+ throws Exception {
+ if (clnt == null) {
+ throw new IllegalStateException(
+ "Unable to find client impl for " + MECH);
+ }
+ if (srv == null) {
+ throw new IllegalStateException(
+ "Unable to find server impl for " + MECH);
+ }
+
+ byte[] response = (clnt.hasInitialResponse()
+ ? clnt.evaluateChallenge(EMPTY) : EMPTY);
+ System.out.println("Initial:");
+ new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
+ byte[] challenge;
+
+ while (!clnt.isComplete() || !srv.isComplete()) {
+ challenge = srv.evaluateResponse(response);
+ response = null;
+ if (challenge != null) {
+ System.out.println("Challenge:");
+ new sun.misc.HexDumpEncoder().encodeBuffer(challenge, System.out);
+ response = clnt.evaluateChallenge(challenge);
+ }
+ if (response != null) {
+ System.out.println("Response:");
+ new sun.misc.HexDumpEncoder().encodeBuffer(response, System.out);
+ }
+ }
+
+ if (clnt.isComplete() && srv.isComplete()) {
+ System.out.println("SUCCESS");
+ if (!srv.getAuthorizationID().equals(USER1)) {
+ throw new Exception("Not correct user");
+ }
+ } else {
+ throw new IllegalStateException(
+ "FAILURE: mismatched state:"
+ + " client complete? " + clnt.isComplete()
+ + " server complete? " + srv.isComplete());
+ }
+
+ if (!clnt.getNegotiatedProperty(Sasl.QOP).equals("auth") ||
+ !srv.getNegotiatedProperty(Sasl.QOP).equals("auth") ||
+ !clnt.getNegotiatedProperty(
+ "com.sun.security.sasl.ntlm.domain").equals(REALM)) {
+ throw new Exception("Negotiated property error");
+ }
+ clnt.dispose();
+ srv.dispose();
+ }
+}
--- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh Thu Sep 16 11:19:43 2010 -0700
@@ -25,7 +25,7 @@
# @summary (cl) ClassLoader.loadClass locks all instances in chain
# when delegating
#
-# @run shell/timeout=10 TestCrossDelegate.sh
+# @run shell/timeout=300 TestCrossDelegate.sh
# if running by hand on windows, change TESTSRC and TESTCLASSES to "."
if [ "${TESTSRC}" = "" ] ; then
@@ -41,10 +41,6 @@
echo "FAILED!!!"
exit 1
fi
-echo TESTSRC=${TESTSRC}
-echo TESTCLASSES=${TESTCLASSES}
-echo TESTJAVA=${TESTJAVA}
-echo ""
# set platform-specific variables
OS=`uname -s`
@@ -55,11 +51,20 @@
Linux )
FS="/"
;;
- Windows* | CYGWIN* )
+ Windows*)
FS="\\"
;;
+ CYGWIN* )
+ FS="\\"
+ TESTCLASSES=`/usr/bin/cygpath -a -s -m ${TESTCLASSES}`
+ ;;
esac
+echo TESTSRC=${TESTSRC}
+echo TESTCLASSES=${TESTCLASSES}
+echo TESTJAVA=${TESTJAVA}
+echo ""
+
# compile test
${TESTJAVA}${FS}bin${FS}javac \
-d ${TESTCLASSES} \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessBuilder/SecurityManagerClinit.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2010 Google 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6980747
+ * @summary Check that Process-related classes have the proper
+ * doPrivileged blocks, and can be initialized with an adversarial
+ * security manager.
+ * @run main/othervm SecurityManagerClinit
+ * @author Martin Buchholz
+ */
+
+import java.io.*;
+import java.security.*;
+
+public class SecurityManagerClinit {
+ private static class Policy extends java.security.Policy {
+ private Permissions perms;
+
+ public Policy(Permission... permissions) {
+ perms = new Permissions();
+ for (Permission permission : permissions)
+ perms.add(permission);
+ }
+
+ public boolean implies(ProtectionDomain pd, Permission p) {
+ return perms.implies(p);
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ String javaExe =
+ System.getProperty("java.home") +
+ File.separator + "bin" + File.separator + "java";
+
+ // A funky contrived security setup, just for bug repro purposes.
+ java.security.Security.setProperty("package.access", "java.util");
+
+ final Policy policy =
+ new Policy
+ (new FilePermission("<<ALL FILES>>", "execute"),
+ new RuntimePermission("setSecurityManager"));
+ Policy.setPolicy(policy);
+
+ System.setSecurityManager(new SecurityManager());
+
+ try {
+ String[] cmd = { javaExe, "-version" };
+ Process p = Runtime.getRuntime().exec(cmd);
+ p.getOutputStream().close();
+ p.getInputStream().close();
+ p.getErrorStream().close();
+ p.waitFor();
+ } finally {
+ System.setSecurityManager(null);
+ }
+ }
+}
--- a/jdk/test/java/nio/channels/FileChannel/Transfer.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/nio/channels/FileChannel/Transfer.java Thu Sep 16 11:19:43 2010 -0700
@@ -23,6 +23,7 @@
/* @test
* @bug 4434723 4482726 4559072 4638365 4795550 5081340 5103988 6253145
+ * 6984545
* @summary Test FileChannel.transferFrom and transferTo
* @library ..
*/
@@ -55,6 +56,7 @@
xferTest06(); // for bug 5081340
xferTest07(); // for bug 5103988
xferTest08(); // for bug 6253145
+ xferTest09(); // for bug 6984545
}
private static void testFileChannel() throws Exception {
@@ -505,6 +507,27 @@
}
}
+ // Test that transferFrom with FileChannel source that is not readable
+ // throws NonReadableChannelException
+ static void xferTest09() throws Exception {
+ File source = File.createTempFile("source", null);
+ source.deleteOnExit();
+
+ File target = File.createTempFile("target", null);
+ target.deleteOnExit();
+
+ FileChannel fc1 = new FileOutputStream(source).getChannel();
+ FileChannel fc2 = new RandomAccessFile(target, "rw").getChannel();
+ try {
+ fc2.transferFrom(fc1, 0L, 0);
+ throw new RuntimeException("NonReadableChannelException expected");
+ } catch (NonReadableChannelException expected) {
+ } finally {
+ fc1.close();
+ fc2.close();
+ }
+ }
+
/**
* Creates file blah of specified size in bytes.
*/
--- a/jdk/test/java/nio/channels/Selector/ConnectWrite.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/nio/channels/Selector/ConnectWrite.java Thu Sep 16 11:19:43 2010 -0700
@@ -38,7 +38,6 @@
public static void main(String[] args) throws Exception {
test1(13);
- test1(9);
}
public static void test1(int port) throws Exception {
--- a/jdk/test/java/nio/file/DirectoryStream/Basic.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java Thu Sep 16 11:19:43 2010 -0700
@@ -104,20 +104,20 @@
stream.close();
}
- // check that IOExceptions throws by filters are propagated
+ // check that an IOException thrown by a filter is propagated
filter = new DirectoryStream.Filter<Path>() {
public boolean accept(Path file) throws IOException {
- throw new IOException();
+ throw new java.util.zip.ZipException();
}
};
stream = dir.newDirectoryStream(filter);
try {
stream.iterator().hasNext();
- throw new RuntimeException("ConcurrentModificationException expected");
- } catch (ConcurrentModificationException x) {
- Throwable t = x.getCause();
- if (!(t instanceof IOException))
- throw new RuntimeException("Cause is not IOException as expected");
+ throw new RuntimeException("DirectoryIteratorException expected");
+ } catch (DirectoryIteratorException x) {
+ IOException cause = x.getCause();
+ if (!(cause instanceof java.util.zip.ZipException))
+ throw new RuntimeException("Expected IOException not propagated");
} finally {
stream.close();
}
@@ -142,58 +142,49 @@
} catch (NotDirectoryException x) {
}
- // test iterator remove method
- stream = dir.newDirectoryStream();
+ // test UnsupportedOperationException
+ stream = dir.newDirectoryStream();
Iterator<Path> i = stream.iterator();
- while (i.hasNext()) {
- Path entry = i.next();
- if (!entry.getName().equals(foo))
- throw new RuntimeException("entry not expected");
+ i.next();
+ try {
i.remove();
+ throw new RuntimeException("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException uoe) {
}
- stream.close();
// test IllegalStateException
- dir.resolve(foo).createFile();
stream = dir.newDirectoryStream();
- i = stream.iterator();
- i.next();
+ stream.iterator();
try {
+ // attempt to obtain second iterator
stream.iterator();
throw new RuntimeException("IllegalStateException not thrown as expected");
} catch (IllegalStateException x) {
}
stream.close();
+
+ stream = dir.newDirectoryStream();
+ stream.close();
try {
+ // attempt to obtain iterator after stream is closed
stream.iterator();
throw new RuntimeException("IllegalStateException not thrown as expected");
} catch (IllegalStateException x) {
}
- try {
- i.hasNext();
- throw new RuntimeException("ConcurrentModificationException not thrown as expected");
- } catch (ConcurrentModificationException x) {
- Throwable t = x.getCause();
- if (!(t instanceof ClosedDirectoryStreamException))
- throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
- }
- try {
+
+ // test that iterator reads to end of stream when closed
+ stream = dir.newDirectoryStream();
+ i = stream.iterator();
+ stream.close();
+ while (i.hasNext())
i.next();
- throw new RuntimeException("ConcurrentModificationException not thrown as expected");
- } catch (ConcurrentModificationException x) {
- Throwable t = x.getCause();
- if (!(t instanceof ClosedDirectoryStreamException))
- throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
- }
+
+ stream = dir.newDirectoryStream();
+ i = stream.iterator();
+ stream.close();
try {
- i.remove();
- throw new RuntimeException("ConcurrentModificationException not thrown as expected");
- } catch (ConcurrentModificationException x) {
- Throwable t = x.getCause();
- if (!(t instanceof ClosedDirectoryStreamException))
- throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
- }
-
+ for (;;) i.next();
+ } catch (NoSuchElementException expected) { }
}
public static void main(String[] args) throws IOException {
--- a/jdk/test/java/nio/file/DirectoryStream/SecureDS.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/nio/file/DirectoryStream/SecureDS.java Thu Sep 16 11:19:43 2010 -0700
@@ -166,22 +166,6 @@
stream.deleteDirectory(dirEntry);
stream.deleteFile(fileEntry);
- // Test: remove
- // (requires resetting environment to get new iterator)
- stream.close();
- dir2.moveTo(dir1);
- dir1.resolve(fileEntry).createFile();
- stream = (SecureDirectoryStream<Path>)dir1.newDirectoryStream();
- dir1.moveTo(dir2);
- Iterator<Path> iter = stream.iterator();
- int removed = 0;
- while (iter.hasNext()) {
- iter.next();
- iter.remove();
- removed++;
- }
- assertTrue(removed == 1);
-
// clean-up
stream.close();
dir2.delete();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/etc/Exceptions.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6881498
+ * @summary Miscellenous tests on exceptions in java.nio.file
+ */
+
+import java.nio.file.*;
+import java.io.*;
+import java.util.Objects;
+import java.lang.reflect.*;
+
+public class Exceptions {
+
+ public static void main(String[] args) throws Exception {
+ testFileSystemException();
+ testDirectoryIteratorException();
+ }
+
+ static void testFileSystemException() throws Exception {
+ String thisFile = "source";
+ String otherFile = "target";
+ String reason = "Access denied";
+
+ // getFile/getOtherFile
+ testFileSystemException(thisFile, otherFile, reason);
+ testFileSystemException(null, otherFile, reason);
+ testFileSystemException(thisFile, null, reason);
+ testFileSystemException(thisFile, otherFile, null);
+
+ // serialization
+ FileSystemException exc;
+ exc = new FileSystemException(thisFile, otherFile, reason);
+ exc = (FileSystemException)deserialize(serialize(exc));
+ if (!exc.getFile().equals(thisFile) || !exc.getOtherFile().equals(otherFile))
+ throw new RuntimeException("Exception not reconstituted completely");
+ }
+
+ static void testFileSystemException(String thisFile,
+ String otherFile,
+ String reason)
+ {
+ FileSystemException exc = new FileSystemException(thisFile, otherFile, reason);
+ if (!Objects.equals(thisFile, exc.getFile()))
+ throw new RuntimeException("getFile returned unexpected result");
+ if (!Objects.equals(otherFile, exc.getOtherFile()))
+ throw new RuntimeException("getOtherFile returned unexpected result");
+ if (!Objects.equals(reason, exc.getReason()))
+ throw new RuntimeException("getReason returned unexpected result");
+ }
+
+ static void testDirectoryIteratorException() throws Exception {
+ // NullPointerException
+ try {
+ new DirectoryIteratorException(null);
+ throw new RuntimeException("NullPointerException expected");
+ } catch (NullPointerException expected) { }
+
+ // serialization
+ DirectoryIteratorException exc;
+ exc = new DirectoryIteratorException(new IOException());
+ exc = (DirectoryIteratorException)deserialize(serialize(exc));
+ IOException ioe = exc.getCause();
+ if (ioe == null)
+ throw new RuntimeException("Cause should not be null");
+
+ // when deserializing then the cause should be an IOException
+ hackCause(exc, null);
+ try {
+ deserialize(serialize(exc));
+ throw new RuntimeException("InvalidObjectException expected");
+ } catch (InvalidObjectException expected) { }
+
+ hackCause(exc, new RuntimeException());
+ try {
+ deserialize(serialize(exc));
+ throw new RuntimeException("InvalidObjectException expected");
+ } catch (InvalidObjectException expected) { }
+ }
+
+
+ // Use reflection to set a Throwable's cause.
+ static void hackCause(Throwable t, Throwable cause)
+ throws NoSuchFieldException, IllegalAccessException
+ {
+ Field f = Throwable.class.getDeclaredField("cause");
+ f.setAccessible(true);
+ f.set(t, cause);
+ }
+
+ // Serialize the given object to a byte[]
+ static byte[] serialize(Object o) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(o);
+ oos.close();
+ return baos.toByteArray();
+ }
+
+ // Read an object from its serialized form
+ static Object deserialize(byte[] bytes)
+ throws IOException, ClassNotFoundException
+ {
+ ByteArrayInputStream in = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(in);
+ Object result = ois.readObject();
+ ois.close();
+ return result;
+ }
+}
--- a/jdk/test/java/util/concurrent/forkjoin/Integrate.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/java/util/concurrent/forkjoin/Integrate.java Thu Sep 16 11:19:43 2010 -0700
@@ -206,7 +206,7 @@
q.fork();
ar = recEval(c, r, fc, fr, ar);
if (!q.tryUnfork()) {
- q.quietlyHelpJoin();
+ q.quietlyJoin();
return ar + q.area;
}
return ar + recEval(l, c, fl, fc, al);
@@ -254,7 +254,7 @@
(q = new DQuad(l, c, al)).fork();
ar = recEval(c, r, fc, fr, ar);
if (q != null && !q.tryUnfork()) {
- q.quietlyHelpJoin();
+ q.quietlyJoin();
return ar + q.area;
}
return ar + recEval(l, c, fl, fc, al);
--- a/jdk/test/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java Thu Sep 16 11:19:43 2010 -0700
@@ -157,7 +157,7 @@
if (cnt == 90 && robot != null) {
// area where we blitted to should be either white or green
Point p = frame.getLocationOnScreen();
- p.move(in.left+10, in.top+10);
+ p.translate(in.left+10, in.top+10);
BufferedImage bi =
robot.createScreenCapture(
new Rectangle(p.x, p.y, IMAGE_W/2, IMAGE_H/2));
@@ -166,7 +166,7 @@
// the are where we didn't render should stay white
p = frame.getLocationOnScreen();
- p.move(in.left, in.top+IMAGE_H+5);
+ p.translate(in.left, in.top+IMAGE_H+5);
bi = robot.createScreenCapture(
new Rectangle(p.x, p.y,
frame.getWidth()-in.left-in.right,
--- a/jdk/test/sun/net/sdp/ProbeIB.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/sun/net/sdp/ProbeIB.java Thu Sep 16 11:19:43 2010 -0700
@@ -34,21 +34,16 @@
public class ProbeIB {
public static void main(String[] args) throws IOException {
- Scanner s = new Scanner(new File("/etc/path_to_inst"));
+ Scanner s = new Scanner(new File(args[0]));
try {
while (s.hasNextLine()) {
- String line = s.nextLine();
- if (line.startsWith("#"))
- continue;
- String[] fields = line.split("\\s+");
- if (!fields[2].equals("\"ibd\""))
- continue;
- String name = fields[2].substring(1, fields[2].length()-1) + fields[1];
- NetworkInterface ni = NetworkInterface.getByName(name);
+ String link = s.nextLine();
+ NetworkInterface ni = NetworkInterface.getByName(link);
if (ni != null) {
Enumeration<InetAddress> addrs = ni.getInetAddresses();
while (addrs.hasMoreElements()) {
- System.out.println(addrs.nextElement().getHostAddress());
+ InetAddress addr = addrs.nextElement();
+ System.out.println(addr.getHostAddress());
}
}
}
--- a/jdk/test/sun/net/sdp/sanity.sh Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/sun/net/sdp/sanity.sh Thu Sep 16 11:19:43 2010 -0700
@@ -33,14 +33,15 @@
echo "This is a Solaris-only test"
exit 0
fi
-SDPADM=/usr/sbin/sdpadm
-if [ ! -f ${SDPADM} ]; then
- echo "SDP not available"
- exit 0
-fi
-${SDPADM} status|grep Enabled
-if [ $? != 0 ]; then
- echo "SDP not enabled"
+
+IB_LINKS=ib.links
+IB_ADDRS=ib.addrs
+
+# Display IB partition link information
+# (requires Solaris 11, will fail on Solaris 10)
+/usr/sbin/dladm show-part -o LINK -p > ${IB_LINKS}
+if [ $? != 0 ]; then
+ echo "Unable to get IB parition link information"
exit 0
fi
@@ -56,13 +57,13 @@
export CLASSPATH
# Probe for IP addresses plumbed to IB interfaces
-$JAVA -Djava.net.preferIPv4Stack=true ProbeIB > ib_addrs
+$JAVA -Djava.net.preferIPv4Stack=true ProbeIB ${IB_LINKS} > ${IB_ADDRS}
# Create sdp.conf
SDPCONF=sdp.conf
rm ${SDPCONF}
touch ${SDPCONF}
-cat ib_addrs | while read ADDR
+cat ${IB_ADDRS} | while read ADDR
do
echo "bind ${ADDR} *" > ${SDPCONF}
echo "connect ${ADDR} *" >> ${SDPCONF}
--- a/jdk/test/sun/net/www/http/ChunkedInputStream/ChunkedEncodingTest.java Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/sun/net/www/http/ChunkedInputStream/ChunkedEncodingTest.java Thu Sep 16 11:19:43 2010 -0700
@@ -38,7 +38,7 @@
public class ChunkedEncodingTest{
private static MessageDigest serverDigest, clientDigest;
- private static byte[] serverMac, clientMac;
+ private static volatile byte[] serverMac, clientMac;
static void client(String u) throws Exception {
URL url = new URL(u);
@@ -106,7 +106,7 @@
while (is.read() != -1);
is.close();
- t.sendResponseHeaders (200, MESSAGE_LENGTH);
+ t.sendResponseHeaders (200, 0);
OutputStream os = t.getResponseBody();
DigestOutputStream dos = new DigestOutputStream(os, serverDigest);
--- a/jdk/test/sun/security/tools/jarsigner/emptymanifest.sh Thu Sep 16 11:17:32 2010 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/emptymanifest.sh Thu Sep 16 11:19:43 2010 -0700
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -49,13 +49,23 @@
KT="$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS"
JAR=$TESTJAVA${FS}bin${FS}jar
+JAVA=$TESTJAVA${FS}bin${FS}java
+JAVAC=$TESTJAVA${FS}bin${FS}javac
JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
rm $KS $JFILE
echo A > A
echo B > B
mkdir META-INF
-printf "\r\n" > META-INF${FS}MANIFEST.MF
+cat <<EOF > CrLf.java
+class CrLf {
+ public static void main(String[] args) throws Exception {
+ System.out.write(new byte[] {'\r', '\n'});
+ }
+}
+EOF
+$JAVAC CrLf.java
+$JAVA CrLf > META-INF${FS}MANIFEST.MF
zip $JFILE META-INF${FS}MANIFEST.MF A B
$KT -alias a -dname CN=a -keyalg rsa -genkey -validity 300
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/MiscTests.java Thu Sep 16 11:19:43 2010 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 6856415 6981001
+ * @summary Miscellaneous tests, Exceptions, EnsureJRE etc.
+ * @compile -XDignore.symbol.file MiscTests.java TestHelper.java
+ * @run main MiscTests
+ */
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class MiscTests {
+
+ // 6856415: Checks to ensure that proper exceptions are thrown by java
+ static void test6856415() {
+ // No pkcs library on win-x64, so we bail out.
+ if (TestHelper.is64Bit && TestHelper.isWindows) {
+ return;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append("public static void main(String... args) {\n");
+ sb.append("java.security.Provider p = new sun.security.pkcs11.SunPKCS11(args[0]);\n");
+ sb.append("java.security.Security.insertProviderAt(p, 1);\n");
+ sb.append("}");
+ File testJar = new File("Foo.jar");
+ testJar.delete();
+ try {
+ TestHelper.createJar(testJar, sb.toString());
+ } catch (FileNotFoundException fnfe) {
+ throw new RuntimeException(fnfe);
+ }
+ TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javaCmd,
+ "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak");
+ for (String s : tr.testOutput) {
+ System.out.println(s);
+ }
+ if (!tr.contains("java.security.AccessControlException:" +
+ " access denied (\"java.lang.RuntimePermission\"" +
+ " \"accessClassInPackage.sun.security.pkcs11\")")) {
+ System.out.println(tr.status);
+ }
+ }
+ // 6981001 : Check EnsureJreInstallation is ok, note we cannot
+ // thoroughly test this function, we simply do our best.
+ static void test6981001() {
+ if (TestHelper.is64Bit || !TestHelper.isWindows) {
+ return;
+ }
+ Map<String, String> env = new HashMap<String, String>();
+ env.put("_JAVA_LAUNCHER_DEBUG", "true");
+ TestHelper.TestResult tr = TestHelper.doExec(env, TestHelper.javaCmd);
+ if (!tr.contains(TestHelper.JAVAHOME + "\\lib\\bundles")) {
+ System.out.println(tr.status);
+ }
+ }
+ public static void main(String... args) {
+ test6856415();
+ test6981001();
+ if (TestHelper.testExitValue != 0) {
+ throw new Error(TestHelper.testExitValue + " tests failed");
+ }
+}
+}
--- a/jdk/test/tools/launcher/VerifyExceptions.java Thu Sep 16 11:17:32 2010 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6856415
- * @summary Checks to ensure that proper exceptions are thrown by java
- * @compile -XDignore.symbol.file VerifyExceptions.java TestHelper.java
- * @run main VerifyExceptions
- */
-
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-
-public class VerifyExceptions {
-
- static void test6856415() {
- // No pkcs library on win-x64, so we bail out.
- if (TestHelper.is64Bit && TestHelper.isWindows) {
- return;
- }
- StringBuilder sb = new StringBuilder();
- sb.append("public static void main(String... args) {\n");
- sb.append("java.security.Provider p = new sun.security.pkcs11.SunPKCS11(args[0]);\n");
- sb.append("java.security.Security.insertProviderAt(p, 1);\n");
- sb.append("}");
- File testJar = new File("Foo.jar");
- testJar.delete();
- try {
- TestHelper.createJar(testJar, sb.toString());
- } catch (FileNotFoundException fnfe) {
- throw new RuntimeException(fnfe);
- }
- TestHelper.TestResult tr = TestHelper.doExec(TestHelper.javacCmd,
- "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak");
- tr.checkNegative();
- tr.contains("Exception in thread \"main\" java.security.AccessControlException: access denied (\"java.lang.RuntimePermission\" \"accessClassInPackage.sun.security.pkcs11\")\")");
- }
-
- public static void main(String... args) {
- test6856415();
- }
-}