changeset 353:5996f2328c7c nio2-b92

Fixes/updates for nio2-b92 - NPE in multicast sample when network interface not specified - IPv6 hop count uses route default (linux only)) - DatagramChannel#getOption throws UOE instead of IAE for bogus option - CREATE and TRUNCATE combination of open options does not work (win only) - setOwner fails to set owner when privileges available (win only)) - moveTo across volumes or copyTo preserving attributes didn't copy security attrs (win only) - Directory attributes not copied correctly when moving/copying across fs (solaris/linux only) - ACL set/get throws confusing message when NFSv4 ACLs not supported on fs (solaris only) - Timer thread visible to user supplied ThreadFactory - Provider permission checks insufficient - NamedAttributeView#read missing IAE - NamedAttributeView#read didn't handle read-only buffer (linux only) - NamedAttributeView confusing exception when attribute name larger than max (linux only) - NamedAttributeView missing null check (win only) - Unable to access named attributes of sym links (win only) - ArrayIndexOutOfBounds when name empty (solaris only) - Eliminate IoFuture - CompletionHandler should define three methods - Clarify how cancellation should behave - Remove bogus UOE from attribute package - Path missing getFileSystem method - Part one of updates to AsynchronousChannelGroup
author alanb
date Tue, 24 Jun 2008 20:05:07 +0100
parents 6306f07e76bc
children 64e1998c929c
files make/java/nio/FILES_java.gmk make/java/nio/Makefile make/java/nio/mapfile-linux make/java/nio/mapfile-solaris make/mksample/nio/Makefile make/mksample/nio/aio/Makefile src/share/classes/java/nio/channels/AsynchronousByteChannel.java src/share/classes/java/nio/channels/AsynchronousChannel.java src/share/classes/java/nio/channels/AsynchronousChannelGroup.java src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java src/share/classes/java/nio/channels/AsynchronousFileChannel.java src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java src/share/classes/java/nio/channels/AsynchronousSocketChannel.java src/share/classes/java/nio/channels/CompletionHandler.java src/share/classes/java/nio/channels/FileChannel.java src/share/classes/java/nio/channels/IoFuture.java src/share/classes/java/nio/channels/package-info.java src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java src/share/classes/java/nio/file/FileSystem.java src/share/classes/java/nio/file/Files.java src/share/classes/java/nio/file/Path.java src/share/classes/java/nio/file/attribute/AclFileAttributeView.java src/share/classes/java/nio/file/attribute/Attributes.java src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java src/share/classes/java/nio/file/attribute/DosFileAttributeView.java src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java src/share/classes/java/nio/file/attribute/NamedAttributeView.java src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java src/share/classes/java/nio/file/spi/AbstractPath.java src/share/classes/java/nio/file/spi/FileSystemProvider.java src/share/classes/sun/nio/ch/AbstractFuture.java src/share/classes/sun/nio/ch/AbstractIoFuture.java src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java src/share/classes/sun/nio/ch/Cancellable.java src/share/classes/sun/nio/ch/CompletedFuture.java src/share/classes/sun/nio/ch/CompletedIoFuture.java src/share/classes/sun/nio/ch/DatagramChannelImpl.java src/share/classes/sun/nio/ch/FileChannelImpl.java src/share/classes/sun/nio/ch/Invoker.java src/share/classes/sun/nio/ch/PendingFuture.java src/share/classes/sun/nio/ch/PendingIoFuture.java src/share/classes/sun/nio/ch/PortableAsynchronousFileChannelImpl.java src/share/classes/sun/nio/ch/ThreadPool.java src/share/classes/sun/nio/ch/ThreadPoolManager.java src/share/sample/nio/aio/EchoServer.java src/share/sample/nio/multicast/Reader.java src/solaris/classes/sun/nio/ch/EPollPort.java src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java src/solaris/classes/sun/nio/ch/SolarisEventPort.java src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java src/solaris/classes/sun/nio/fs/LinuxFileSystem.java src/solaris/classes/sun/nio/fs/LinuxNamedAttributeView.java src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java src/solaris/classes/sun/nio/fs/SolarisFileSystem.java src/solaris/classes/sun/nio/fs/SolarisNamedAttributeView.java src/solaris/classes/sun/nio/fs/UnixCopyFile.java src/solaris/classes/sun/nio/fs/UnixFileSystem.java src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java src/solaris/classes/sun/nio/fs/UnixPath.java src/solaris/native/sun/nio/ch/Net.c src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c src/solaris/native/sun/nio/fs/genSolarisConstants.c src/windows/classes/sun/nio/ch/Iocp.java src/windows/classes/sun/nio/ch/PendingIoCache.java src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java src/windows/classes/sun/nio/fs/WindowsChannelFactory.java src/windows/classes/sun/nio/fs/WindowsConstants.java src/windows/classes/sun/nio/fs/WindowsFileCopy.java src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java src/windows/classes/sun/nio/fs/WindowsPath.java src/windows/classes/sun/nio/fs/WindowsSecurity.java src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c test/java/nio/channels/AsynchronousChannelGroup/Basic.java test/java/nio/channels/AsynchronousChannelGroup/Restart.java test/java/nio/channels/AsynchronousFileChannel/Basic.java test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java test/java/nio/channels/AsynchronousSocketChannel/Basic.java test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java test/java/nio/file/DirectoryStream/SecureDS.java test/java/nio/file/Path/CopyAndMove.java test/java/nio/file/Path/Misc.java test/java/nio/file/Path/SBC.java test/java/nio/file/TestUtil.java test/java/nio/file/attribute/DosFileAttributeView/Basic.java test/java/nio/file/attribute/NamedAttributeView/Basic.java test/java/nio/file/attribute/PosixFileAttributeView/Basic.java
diffstat 101 files changed, 3302 insertions(+), 2382 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/nio/FILES_java.gmk	Tue Jun 24 18:30:03 2008 +0100
+++ b/make/java/nio/FILES_java.gmk	Tue Jun 24 20:05:07 2008 +0100
@@ -46,7 +46,6 @@
 	java/nio/channels/FileLock.java \
 	java/nio/channels/GatheringByteChannel.java \
 	java/nio/channels/InterruptibleChannel.java \
-	java/nio/channels/IoFuture.java \
 	java/nio/channels/MembershipKey.java \
 	java/nio/channels/MulticastChannel.java \
 	java/nio/channels/NetworkChannel.java \
@@ -153,15 +152,16 @@
 	\
 	sun/nio/ByteBuffered.java \
 	\
-	sun/nio/ch/AbstractIoFuture.java \
+	sun/nio/ch/AbstractFuture.java \
         sun/nio/ch/AbstractPollArrayWrapper.java \
 	sun/nio/ch/AllocatedNativeObject.java \
 	sun/nio/ch/AsynchronousChannelGroupImpl.java \
 	sun/nio/ch/AsynchronousFileChannelImpl.java \
 	sun/nio/ch/AsynchronousServerSocketChannelImpl.java \
 	sun/nio/ch/AsynchronousSocketChannelImpl.java \
+	sun/nio/ch/Cancellable.java \
 	sun/nio/ch/ChannelInputStream.java \
-	sun/nio/ch/CompletedIoFuture.java \
+	sun/nio/ch/CompletedFuture.java \
         sun/nio/ch/DatagramChannelImpl.java \
         sun/nio/ch/DatagramDispatcher.java \
 	sun/nio/ch/DatagramSocketAdaptor.java \
@@ -187,7 +187,7 @@
 	sun/nio/ch/NativeThreadSet.java \
 	sun/nio/ch/Net.java \
 	sun/nio/ch/OptionKey.java \
-	sun/nio/ch/PendingIoFuture.java \
+	sun/nio/ch/PendingFuture.java \
 	sun/nio/ch/PipeImpl.java \
 	sun/nio/ch/PollArrayWrapper.java \
 	sun/nio/ch/Reflect.java \
--- a/make/java/nio/Makefile	Tue Jun 24 18:30:03 2008 +0100
+++ b/make/java/nio/Makefile	Tue Jun 24 20:05:07 2008 +0100
@@ -164,6 +164,7 @@
 	sun/nio/fs/WindowsPath.java \
 	sun/nio/fs/WindowsPathParser.java \
 	sun/nio/fs/WindowsPathType.java \
+	sun/nio/fs/WindowsSecurity.java \
 	sun/nio/fs/WindowsUriSupport.java \
 	sun/nio/fs/WindowsUserPrincipal.java \
 	sun/nio/fs/WindowsWatchService.java
--- a/make/java/nio/mapfile-linux	Tue Jun 24 18:30:03 2008 +0100
+++ b/make/java/nio/mapfile-linux	Tue Jun 24 20:05:07 2008 +0100
@@ -170,6 +170,7 @@
 		Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
 		Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
 		Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
 		Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
 		Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
 		Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
--- a/make/java/nio/mapfile-solaris	Tue Jun 24 18:30:03 2008 +0100
+++ b/make/java/nio/mapfile-solaris	Tue Jun 24 20:05:07 2008 +0100
@@ -156,6 +156,7 @@
 		Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
 		Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
 		Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
 		Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
 		Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
 		Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
--- a/make/mksample/nio/Makefile	Tue Jun 24 18:30:03 2008 +0100
+++ b/make/mksample/nio/Makefile	Tue Jun 24 20:05:07 2008 +0100
@@ -31,7 +31,7 @@
 PRODUCT = java
 include $(BUILDDIR)/common/Defs.gmk
 
-SUBDIRS = file multicast server
+SUBDIRS = aio file multicast server
 all build clean clobber::
 	$(SUBDIRS-loop)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/mksample/nio/aio/Makefile	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,50 @@
+#
+# Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+#
+# Makefile for the nio/aio sample code
+#
+
+BUILDDIR = ../../..
+
+PRODUCT = java
+
+include $(BUILDDIR)/common/Defs.gmk
+
+SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/aio
+SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/aio
+
+SAMPLE_FILES =							\
+	$(SAMPLE_DST_DIR)/EchoServer.java
+
+all build: $(SAMPLE_FILES)
+
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+	$(install-file)
+
+clean clobber:
+	$(RM) -r $(SAMPLE_DST_DIR)
+
+.PHONY: all build clean clobber
--- a/src/share/classes/java/nio/channels/AsynchronousByteChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousByteChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -26,6 +26,7 @@
 package java.nio.channels;
 
 import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
 
 /**
  * An asynchronous channel that can read and write bytes.
@@ -56,10 +57,10 @@
      * Reads a sequence of bytes from this channel into the given buffer.
      *
      * <p> This method initiates an operation to read a sequence of bytes from
-     * this channel into the given buffer. The method returns an {@link IoFuture}
+     * this channel into the given buffer. The method returns a {@link Future}
      * representing the pending result of the operation. The result of the
-     * operation, obtained by invoking the {@code IoFuture} 's {@link
-     * IoFuture#get() get} method, is the number of bytes read or {@code -1} if
+     * operation, obtained by invoking the {@code Future} 's {@link
+     * Future#get() get} method, is the number of bytes read or {@code -1} if
      * all bytes have been read and the channel has reached end-of-stream.
      *
      * <p> This method initiates a read operation to read up to <i>r</i> bytes
@@ -93,8 +94,7 @@
      * @param   dst
      *          The buffer into which bytes are to be transferred
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The completion handler object; can be {@code null}
      *
@@ -106,9 +106,9 @@
      *          If the channel does not allow more than one read to be outstanding
      *          and a previous read has not completed
      */
-    <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                 A attachment,
-                                 CompletionHandler<Integer,? super A> handler);
+    <A> Future<Integer> read(ByteBuffer dst,
+                             A attachment,
+                             CompletionHandler<Integer,? super A> handler);
 
     /**
      * Reads a sequence of bytes from this channel into the given buffer.
@@ -129,16 +129,16 @@
      *          If the channel does not allow more than one read to be outstanding
      *          and a previous read has not completed
      */
-    <A> IoFuture<Integer,A> read(ByteBuffer dst);
+    Future<Integer> read(ByteBuffer dst);
 
     /**
      * Writes a sequence of bytes to this channel from the given buffer.
      *
      * <p> This method initiates an operation to write a sequence of bytes to
      * this channel from the given buffer. This method returns a {@link
-     * IoFuture} representing the pending result of the operation. The result
-     * of the operation, obtained by invoking the <tt>IoFuture</tt>'s {@link
-     * IoFuture#get() get} method, is the number of bytes written, possibly zero.
+     * Future} representing the pending result of the operation. The result
+     * of the operation, obtained by invoking the <tt>Future</tt>'s {@link
+     * Future#get() get} method, is the number of bytes written, possibly zero.
      *
      * <p> This method initiates a write operation to write up to <i>r</i> bytes
      * to the channel, where <i>r</i> is the number of bytes remaining in the
@@ -170,20 +170,19 @@
      * @param   src
      *          The buffer from which bytes are to be retrieved
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The completion handler object; can be {@code null}
      *
-     * @return A Future representing the result of the operation
+     * @return  A Future representing the result of the operation
      *
      * @throws  WritePendingException
      *          If the channel does not allow more than one write to be outstanding
      *          and a previous write has not completed
      */
-    <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                  A attachment,
-                                  CompletionHandler<Integer,? super A> handler);
+    <A> Future<Integer> write(ByteBuffer src,
+                              A attachment,
+                              CompletionHandler<Integer,? super A> handler);
 
     /**
      * Writes a sequence of bytes to this channel from the given buffer.
@@ -202,5 +201,5 @@
      *          If the channel does not allow more than one write to be outstanding
      *          and a previous write has not completed
      */
-    <A> IoFuture<Integer,A> write(ByteBuffer src);
+    Future<Integer> write(ByteBuffer src);
 }
--- a/src/share/classes/java/nio/channels/AsynchronousChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -26,25 +26,29 @@
 package java.nio.channels;
 
 import java.io.IOException;
+import java.util.concurrent.Future;  // javadoc
 
 /**
  * A channel that supports asynchronous I/O operations. Asynchronous I/O
  * operations will usually take one of two forms:
  *
  * <ol>
- * <li><pre>{@link IoFuture}&lt;R,A&gt; <em>operation</em>(<em>...</em>)</pre></li>
- * <li><pre><em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}&lt;R,? super A&gt handler)</pre></li>
+ * <li><pre>{@link Future}&lt;V&gt; <em>operation</em>(<em>...</em>)</pre></li>
+ * <li><pre>Future&lt;V&gt; <em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}&lt;V,? super A&gt handler)</pre></li>
  * </ol>
  *
  * where <i>operation</i> is the name of the I/O operation (read or write for
- * example), <i>R</i> is the result type of the operation, and <i>A</i> is the
- * type of an object attached to provide context when consuming the result.
+ * example), <i>V</i> is the result type of the I/O operation, and <i>A</i> is
+ * the type of an object attached to the I/O operation to provide context when
+ * consuming the result. The attachment is important for cases where a
+ * <em>state-less</em> {@code CompletionHandler} is used to consume the result
+ * of many I/O operations.
  *
- * <p> In the first form, the methods defined by the {@link java.util.concurrent.Future
- * Future} interface may be used to check if the operation has completed, wait for
- * its completion, and to retrieve the result. In the second form, a {@link
+ * <p> In the first form, the methods defined by the {@link Future Future}
+ * interface may be used to check if the operation has completed, wait for its
+ * completion, and to retrieve the result. In the second form, a {@link
  * CompletionHandler} is invoked to consume the result of the I/O operation when
- * it completes or fails.
+ * it completes, fails, or is cancelled.
  *
  * <p> A channel that implements this interface is <em>asynchronously
  * closeable</em>: If an I/O operation is outstanding on the channel and the
@@ -56,6 +60,36 @@
  * may not allow more than one read and one write operation to be outstanding at
  * any given time.
  *
+ * <h4>Cancellation</h4>
+ *
+ * <p> The {@code Future} interface defines the {@link Future#cancel cancel}
+ * method to cancel execution of a task. If an implementation of this interface
+ * supports a means to cancel I/O operations, and where cancellation may leave
+ * the channel, or the entity to which it is connected, in an inconsistent state,
+ * then the channel is put into an implementation specific <em>error state</em>
+ * that prevents further attempts to initiate I/O operations on the channel. For
+ * example, if a read operation is cancelled but the implementation cannot
+ * guarantee that bytes have not been read from the channel then it puts the
+ * channel into error state state; further attempts to initiate a {@code read}
+ * operation causes an unspecified runtime exception to be thrown.
+ *
+ * <p> Where the {@code cancel} method is invoked with the {@code
+ * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation
+ * may be interrupted by closing the channel. This will cause any other I/O
+ * operations outstanding on the channel to complete with the exception {@link
+ * AsynchronousCloseException}.
+ *
+ * <p> If a {@code CompletionHandler} is specified when initiating an I/O
+ * operation, and the {@code cancel} method is invoked to cancel the I/O
+ * operation before it completes, then the {@code CompletionHandler} is invoked.
+ * Invoking the {@code Future}'s {@code get} method throws {@link
+ * java.util.concurrent.CancellationException CancellationException}.
+ *
+ * <p> Where the {@code cancel} method is invoked to cancel read or write
+ * operations then it recommended that all buffers used in the I/O operations be
+ * discarded or care taken to ensure that the buffers are not accessed while the
+ * channel remains open.
+ *
  *  @since 1.7
  */
 
--- a/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,7 +27,8 @@
 
 import java.nio.channels.spi.AsynchronousChannelProvider;
 import java.io.IOException;
-import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -35,91 +36,35 @@
  *
  * <p> An asynchronous channel group encapsulates the mechanics required to
  * handle the completion of I/O operations initiated by {@link AsynchronousChannel
- * asynchronous channels} that are bound to the group. A group maintains a pool
- * of threads to handle I/O events and dispatch to {@link CompletionHandler
- * completion-handlers} that consume the result of asynchronous operations
- * performed on channels in the group. In addition to handling I/O events, the
- * pooled threads may also execute other tasks required to support the execution
- * of asynchronous I/O operations.
+ * asynchronous channels} that are bound to the group. A group has an associated
+ * thread pool to which tasks are submitted to handle I/O events and dispatch to
+ * {@link CompletionHandler completion-handlers} that consume the result of
+ * asynchronous operations performed on channels in the group. In addition to
+ * handling I/O events, the pooled threads may also execute other tasks required
+ * to support the execution of asynchronous I/O operations.
  *
- * <p> An asynchronous channel group is created by invoking the {@link #open
- * open} method defined by this class. Channels are bound to a group by
- * specifying the group when constructing the channel. The completion handler
- * for an I/O operation initiated on a channel bound to a group is guaranteed
- * to be invoked by the initiating thread itself (for the case that the I/O
- * operation completes immediately) or by one of the pooled threads in the
- * group. The parameter to the {@code open} method when creating a group is a
- * {@link Map} containing parameters to configure the group's thread pool as
- * follows:
+ * <p> An asynchronous channel group is created by invoking one of the {@link
+ * #open open} methods defined by this class. Channels are bound to a group by
+ * specifying the group when constructing the channel. The associated thread
+ * pool is created automatically or is provided to the {@code open} method when
+ * creating the group. When created automatically, the {@code open} method
+ * specifies a value, known as the <em>initial size</em>, that is used as a
+ * hint to size the thread pool. Depending on the implementation, the value may
+ * also be used as an indication as to the number of concurrent threads allowed
+ * to wait on I/O events.
  *
- * <p> {@note The means by which a group is configured is an open issue. The
- * original approach was to allow a j.u.c.Executor be specified when creating
- * the group. This turns out to be too awkwful in practice as the implementation
- * needs to know the maximum number of threads. Some implementations may also
- * need to disallow keep-alive. For now the group is configured with properties
- * that configure the thread pool. We need feedback on its usage and need to
- * decide if the construction should be changed to use a builder rather than
- * a map.}
+ * <p> Where an {@link ExecutorService} is provided when creating a group,
+ * then the group <em>takes ownership</em> of the thread pool. In other words,
+ * it is intended to be used for the exclusive use of the resulting asynchronous
+ * channel group. Termination of the group results in the shutdown of the
+ * executor service.
  *
- * <table border>
- *   <tr>
- *     <th>Key</th>
- *     <th>Description</th>
- *   </tr>
- *   <tr>
- *     <td> {@code maximumPoolSize} </td>
- *     <td> The maximum number of threads to allow in the pool. The parameter
- *     value is an {@code Integer}, or a {@code String} representing a signed
- *     decimal integer, that is the maximum number of threads allowed in the
- *     thread pool at any time. To allow for implementations that dedicate at
- *     least one thread to handling I/O events, the minimum value for this
- *     parameter is {@code 2}. When both the {@code maximumPoolSize} and {@code
- *     handlerPoolSize} parameters are specified then the value of the {@code
- *     maximumPoolSize} parameter must be larger than the value of the {@code
- *     handlerPoolSize} parameter. </td>
- *   </tr>
- *   <tr>
- *     <td> {@code handlerPoolSize} </td>
- *     <td> The maximum number of threads that may be dedicated to handling
- *     I/O events. The parameter value is an {@code Integer}, or a {@code
- *     String} representing a signed decimal integer, that is the maximum number
- *     of threads that may be dedicated to tasks that handle I/O events and
- *     dispatch to completion handlers that consume the result of I/O operations.
- *     The minimum value for this parameter is {@code 1}. The parameter may be
- *     ignored by implementations that do not dedicate threads to handling
- *     I/O events. </td>
- *   </tr>
- *   <tr>
- *     <td> {@code threadFactory} </td>
- *     <td> The factory to use to create threads. The parameter value is a
- *     {@link java.util.concurrent.ThreadFactory ThreadFactory} implementation
- *     that may be used to set the thread name, thread group, priority, and
- *     daemon status. Its {@link java.util.concurrent.ThreadFactory#newThread
- *     newThread} method is invoked to create each thread in the thread pool.
- *     Failure of a {@code ThreadFactory} to create a thread when asked leads
- *     to unspecified behaviour. </td>
- *   </tr>
- *   <tr>
- *     <td> {@code prestartAllHandlerThreads} </td>
- *     <td> Where an implementation has threads dedicated to handling I/O
- *     events then this parameter indicates if the threads should be started
- *     when the group is created. The parameter value is a {@code Boolean},
- *     or a {@code String} representing a boolean value. If the value of the
- *     parameter is {@code true} (or the value "true" ignoring case), then
- *     all <i>handler thread</i> are started. The parameter may be ignored by
- *     implementations that do not dedicate threads to handling I/O events. </td>
- *   </tr>
- * </table>
- *
- * <p> In addition to the above, the {@code Map} may contain other
- * implementation-dependent configuration parameters.
- *
- * <p> In addition to groups created by invoking the {@code open} method, the
- * Java virtual machine maintains a system-wide <em>default group</em> that is
- * constructed automatically. Asynchronous channels that do not specify a group
- * at construction time are bound to the default group. The thread pool for
- * the default group may be configured by means of system properties where
- * required:
+ * <p> In addition to asynchronous channel groups created by invoking one of the
+ * {@code open} methods, the Java virtual machine maintains a system-wide
+ * <em>default group</em> that is constructed automatically. Asynchronous
+ * channels that do not specify a group at construction time are bound to the
+ * default group. The default group may be configured by means of system
+ * properties where required:
  *
  * <table border>
  *   <tr>
@@ -127,17 +72,6 @@
  *     <th>Description</th>
  *   </tr>
  *   <tr>
- *     <td> {@code java.nio.channels.DefaultThreadPool.maximumPoolSize} </td>
- *     <td> The value of the {@code maximumPoolSize} parameter for the default
- *     group. </td>
- *   </tr>
- *   <tr>
- *   <tr>
- *     <td> {@code java.nio.channels.DefaultThreadPool.handlerPoolSize} </td>
- *     <td> The value of the {@code handlerPoolSize} parameter for the default
- *     group. </td>
- *   </tr>
- *   <tr>
  *   <tr>
  *     <td> {@code java.nio.channels.DefaultThreadPool.threadFactory} </td>
  *     <td> The value of this property is taken to be the fully-qualified name
@@ -145,20 +79,39 @@
  *     class. The class is loaded using the system class loader and instantiated.
  *     The factory's {@link java.util.concurrent.ThreadFactory#newThread
  *     newThread} method is invoked to create each thread for the default
- *     group's thread pool. Failure of a {@code ThreadFactory} to create a thread
- *     when asked leads to unspecified behaviour. </td>
+ *     group's thread pool. Where the process to load and instantiate the value
+ *     of the property fails, the value of the property is ignored.
+ * </td>
  *   </tr>
  *   <tr>
- *     <td> {@code java.nio.channels.DefaultThreadPool.prestartAllHandlerThreads} </td>
- *     <td> The value of the {@code prestartAllHandlerThreads} parameter for the default
- *     group. </td>
+ *     <td> {@code java.nio.channels.DefaultThreadPool.initialSize} </td>
+ *     <td> The value of the {@code initialSize} parameter for the default
+ *     group.</td>
  *   </tr>
  * </table>
  *
- * <p> Where a system property is not defined, or contains an invalid value,
- * or the process to load and instantiate the value of the {@code
- * java.nio.channels.DefaultThreadPool.threadFactory} property fails, then
- * implementation specific defaults are used.
+ * <p> {@note TDB: Need to specify if the default group creates daemon threads
+ * or not. If completion handlers do critical tasks then they should not be
+ * daemons. On the other hand, developers will complain that the VM doesn't
+ * exit automatically.}
+ *
+ * <a name="threading"><h4>Threading</h4></a>
+ *
+ * <p> The completion handler for an I/O operation initiated on a channel bound
+ * to a group is guaranteed to be invoked by the initiating thread itself (for
+ * the case that the I/O operation completes immediately) or by one of the
+ * pooled threads in the group.
+ *
+ * <p> {@note TBD: There are cases where the initiating thread should not invoke
+ * the handler directly. For example, where thread identity is important then
+ * the handler should only be run by a thread that is in channel group's thread
+ * pool. For AsynchronousServerSocketChannel you can potentially get better
+ * concurrency if the handler for the accept operation is not invoked on the
+ * initiating thread. These cases provide a reasonable default behavior and
+ * we are seeking feedback as to if a policy setting is required to have it
+ * otherwise. In other words, are there cases where the thread identity is not
+ * important and it would be desirable to execute on the initiating thread
+ * where possible.}
  *
  * <a name="shutdown"><h4>Shutdown and Termination</h4></a>
  *
@@ -212,26 +165,76 @@
     /**
      * Creates an asynchronous channel group.
      *
-     * <p> The new group is created by invoking the {@link
-     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousChannelGroup
+     * <p> This method creates the asynchronous channel group and its associated
+     * thread pool. The {@code factory} parameter is the {@link ThreadFactory}
+     * to create threads. The {@code initialSize} parameter is used as a
+     * <em>hint</em> when sizing the thread pool. Depending on the
+     * implementation, the value of the parameter may provide an indication as to
+     * the number of concurrent threads allowed to wait on I/O events. The
+     * maximum allowed threads in the thread pool depends on the implementation
+     * but is required to be greater than or equal to the value of the {@code
+     * initialSize} parameter.
+     *
+     * <p> The group is created by invoking the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousChannelGroup(ThreadFactory,int)
      * openAsynchronousChannelGroup} method of the system-wide default {@link
      * java.nio.channels.spi.AsynchronousChannelProvider} object.
      *
-     * @param   params
-     *          A map of parameters to configure the group's thread pool; may
-     *          be empty
+     * @param   factory
+     *          The thread factory to create threads
+     * @param   initialSize
+     *          Used to size the associated thread pool or a negative value
+     *          for an implementation chosen size
      *
      * @return  A new asynchronous channel group
      *
-     * @throws  IllegalArgumentException
-     *          If a parameter value is invalid
      * @throws  IOException
      *          If an I/O error occurs
      */
-    public static AsynchronousChannelGroup open(Map<String,?> params)
+    public static AsynchronousChannelGroup open(ThreadFactory factory, int initialSize)
         throws IOException
     {
-        return AsynchronousChannelProvider.provider().openAsynchronousChannelGroup(params);
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(factory, initialSize);
+    }
+
+    /**
+     * Creates an asynchronous channel group.
+     *
+     * <p> The {@code executor} parameter is the {@code ExecutorService} to
+     * which tasks are submitted to handle I/O events and dispatch completion
+     * results for operations initiated on asynchronous channels in the group.
+     * The nature of these tasks is highly implementation specific and so care
+     * should be taken when configuring the {@code Executor}. Minimally it
+     * should support an unbounded work queue and should not run tasks on the
+     * caller thread of the {@link ExecutorService#execute execute} method.
+     *
+     * <p> The executor is intended to be used for the exclusive use of the
+     * resulting asynchronous channel group. Adjusting the maximum allowed
+     * number of threads or other policy parameters after the channel group
+     * is not recommended. Termination of the group results in the orderly
+     * {@link ExecutorService#shutdown shutdown} of the executor service.
+     * Shutting down the executor service by other means results in unspecified
+     * behavior.
+     *
+     * <p> The group is created by invoking the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService)
+     * openAsynchronousChannelGroup} method of the system-wide default {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider} object.
+     *
+     * @param   executor
+     *          The thread pool for the resulting group
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousChannelGroup open(ExecutorService executor)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(executor);
     }
 
     /**
@@ -245,6 +248,11 @@
     /**
      * Tells whether or not this group has terminated.
      *
+     * <p> Where this method returns {@code true}, and the group was {@link
+     * #open(ExecutorService) constructed} with an {@link ExecutorService}, then
+     * the {@code ExecutorService} has also {@link ExecutorService#isTerminated
+     * terminated}.
+     *
      * @return  {@code true} if this group has terminated
      */
     public abstract boolean isTerminated();
--- a/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,6 +27,7 @@
 
 import java.nio.channels.spi.*;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
 import java.io.IOException;
 import java.net.SocketOption;
 import java.net.SocketAddress;
@@ -103,15 +104,20 @@
  *
  *  // print the source address of all packets that we receive
  *  dc.receive(buffer, buffer, new CompletionHandler&lt;SocketAddress,ByteBuffer&gt;() {
- *      public void completed(IoFuture&lt;SocketAddress,ByteBuffer&gt; result) {
+ *      public void completed(SocketAddress sa, ByteBuffer buffer) {
  *          try {
- *               SocketAddress sa = result.getNow();
+ *               SocketAddress sa = result.get();
  *               System.out.println(sa);
  *
- *               ByteBuffer buffer = result.attachment();
  *               buffer.clear();
  *               dc.receive(buffer, buffer, this);
- *           } catch (IOException x) { ... }
+ *           } catch (...) { ... }
+ *      }
+ *      public void failed(Throwable exc ByteBuffer buffer) {
+ *          ...
+ *      }
+ *      public void cancelled(ByteBuffer buffer) {
+ *          ...
  *      }
  *  });
  * </pre>
@@ -319,8 +325,8 @@
      * Receives a datagram via this channel.
      *
      * <p> This method initiates the receiving of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
-     * The <tt>IoFuture</tt>'s {@link IoFuture#get() get} method returns
+     * <tt>Future</tt> representing the pending result of the operation.
+     * The <tt>Future</tt>'s {@link Future#get() get} method returns
      * the source address of the datagram upon successful completion.
      *
      * <p> The datagram is transferred into the given byte buffer starting at
@@ -349,30 +355,29 @@
      * @param   unit
      *          The time unit of the <tt>timeout</tt> argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the timeout is negative or the buffer is read-only
      * @throws  ReadPendingException
      *          If a read operation is already in progress on this channel
      */
-    public abstract <A> IoFuture<SocketAddress,A> receive(ByteBuffer dst,
-                                                          long timeout,
-                                                          TimeUnit unit,
-                                                          A attachment,
-                                                          CompletionHandler<SocketAddress,? super A> handler);
+    public abstract <A> Future<SocketAddress> receive(ByteBuffer dst,
+                                                      long timeout,
+                                                      TimeUnit unit,
+                                                      A attachment,
+                                                      CompletionHandler<SocketAddress,? super A> handler);
 
     /**
      * Receives a datagram via this channel.
      *
      * <p> This method initiates the receiving of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
-     * The <tt>IoFuture</tt>'s {@link IoFuture#get() get} method returns
+     * <tt>Future</tt> representing the pending result of the operation.
+     * The <tt>Future</tt>'s {@link Future#get() get} method returns
      * the source address of the datagram upon successful completion.
      *
      * <p> This method is equivalent to invoking {@link
@@ -382,21 +387,20 @@
      * @param   dst
      *          The buffer into which the datagram is to be transferred
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the buffer is read-only
      * @throws  ReadPendingException
      *          If a read operation is already in progress on this channel
      */
-    public final <A> IoFuture<SocketAddress,A> receive(ByteBuffer dst,
-                                                       A attachment,
-                                                       CompletionHandler<SocketAddress,? super A> handler)
+    public final <A> Future<SocketAddress> receive(ByteBuffer dst,
+                                                   A attachment,
+                                                   CompletionHandler<SocketAddress,? super A> handler)
     {
         return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
     }
@@ -405,8 +409,8 @@
      * Receives a datagram via this channel.
      *
      * <p> This method initiates the receiving of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
-     * The <tt>IoFuture</tt>'s {@link IoFuture#get() get} method returns
+     * <tt>Future</tt> representing the pending result of the operation.
+     * The <tt>Future</tt>'s {@link Future#get() get} method returns
      * the source address of the datagram upon successful completion.
      *
      * <p> This method is equivalent to invoking {@link
@@ -417,14 +421,14 @@
      * @param   dst
      *          The buffer into which the datagram is to be transferred
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the buffer is read-only
      * @throws  ReadPendingException
      *          If a read operation is already in progress on this channel
      */
-    public final <A> IoFuture<SocketAddress,A> receive(ByteBuffer dst) {
+    public final <A> Future<SocketAddress> receive(ByteBuffer dst) {
         return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 
@@ -432,10 +436,10 @@
      * Sends a datagram via this channel.
      *
      * <p> This method initiates sending of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
+     * <tt>Future</tt> representing the pending result of the operation.
      * The operation sends the remaining bytes in the given buffer as a single
      * datagram to the given target address. The result of the operation, obtained
-     * by invoking the <tt>IoFuture</tt>'s {@link IoFuture#get() get}
+     * by invoking the <tt>Future</tt>'s {@link Future#get() get}
      * method, is the number of bytes sent.
      *
      * <p> The datagram is transferred from the byte buffer as if by a regular
@@ -460,12 +464,11 @@
      * @param   unit
      *          The time unit of the <tt>timeout</tt> argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  UnresolvedAddressException
      *          If the given remote address is not fully resolved
@@ -480,21 +483,21 @@
      *          If a security manager has been installed and it does not permit
      *          datagrams to be sent to the given address
      */
-    public abstract <A> IoFuture<Integer,A> send(ByteBuffer src,
-                                                 SocketAddress target,
-                                                 long timeout,
-                                                 TimeUnit unit,
-                                                 A attachment,
-                                                 CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> send(ByteBuffer src,
+                                             SocketAddress target,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
 
     /**
      * Sends a datagram via this channel.
      *
      * <p> This method initiates sending of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
+     * <tt>Future</tt> representing the pending result of the operation.
      * The operation sends the remaining bytes in the given buffer as a single
      * datagram to the given target address. The result of the operation, obtained
-     * by invoking the <tt>IoFuture</tt>'s {@link IoFuture#get() get}
+     * by invoking the <tt>Future</tt>'s {@link Future#get() get}
      * method, is the number of bytes sent.
      *
      * <p> This method is equivalent to invoking {@link
@@ -506,12 +509,11 @@
      * @param   target
      *          The address to which the datagram is to be sent
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  UnresolvedAddressException
      *          If the given remote address is not fully resolved
@@ -526,10 +528,10 @@
      *          If a security manager has been installed and it does not permit
      *          datagrams to be sent to the given address
      */
-    public final <A> IoFuture<Integer,A> send(ByteBuffer src,
-                                              SocketAddress target,
-                                              A attachment,
-                                              CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> send(ByteBuffer src,
+                                          SocketAddress target,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
     {
         return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler);
     }
@@ -538,10 +540,10 @@
      * Sends a datagram via this channel.
      *
      * <p> This method initiates sending of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
+     * <tt>Future</tt> representing the pending result of the operation.
      * The operation sends the remaining bytes in the given buffer as a single
      * datagram to the given target address. The result of the operation, obtained
-     * by invoking the <tt>IoFuture</tt>'s {@link IoFuture#get() get}
+     * by invoking the <tt>Future</tt>'s {@link Future#get() get}
      * method, is the number of bytes sent.
      *
      * <p> This method is equivalent to invoking {@link
@@ -554,7 +556,7 @@
      * @param   target
      *          The address to which the datagram is to be sent
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  UnresolvedAddressException
      *          If the given remote address is not fully resolved
@@ -569,9 +571,7 @@
      *          If a security manager has been installed and it does not permit
      *          datagrams to be sent to the given address
      */
-    public final <A> IoFuture<Integer,A> send(ByteBuffer src,
-                                              SocketAddress target)
-    {
+    public final Future<Integer> send(ByteBuffer src, SocketAddress target) {
         return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 
@@ -580,8 +580,8 @@
      * Receives a datagram via this channel.
      *
      * <p> This method initiates the receiving of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
-     * The <tt>IoFuture</tt>'s {@link IoFuture#get() get} method returns
+     * <tt>Future</tt> representing the pending result of the operation.
+     * The <tt>Future</tt>'s {@link Future#get() get} method returns
      * the number of bytes transferred upon successful completion.
      *
      * <p> This method may only be invoked if this channel is connected, and it
@@ -603,12 +603,11 @@
      * @param   unit
      *          The time unit of the <tt>timeout</tt> argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the timeout is negative or buffer is read-only
@@ -617,11 +616,11 @@
      * @throws  NotYetConnectedException
      *          If this channel is not connected
      */
-    public abstract <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                                 long timeout,
-                                                 TimeUnit unit,
-                                                 A attachment,
-                                                 CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
 
     /**
      * @throws  ReadPendingException       {@inheritDoc}
@@ -629,9 +628,9 @@
      *          If this channel is not connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                              A attachment,
-                                              CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> read(ByteBuffer dst,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
     {
         return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
     }
@@ -642,7 +641,7 @@
      *          If this channel is not connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst) {
+    public final Future<Integer> read(ByteBuffer dst) {
         return read(dst, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 
@@ -650,10 +649,10 @@
      * Writes a datagram to this channel.
      *
      * <p> This method initiates sending of a datagram, returning a
-     * <tt>IoFuture</tt> representing the pending result of the operation.
+     * <tt>Future</tt> representing the pending result of the operation.
      * The operation sends the remaining bytes in the given buffer as a single
      * datagram. The result of the operation, obtained by invoking the
-     * <tt>IoFuture</tt>'s {@link IoFuture#get() get} method, is the
+     * <tt>Future</tt>'s {@link Future#get() get} method, is the
      * number of bytes sent.
      *
      * <p> The datagram is transferred from the byte buffer as if by a regular
@@ -675,12 +674,11 @@
      * @param   unit
      *          The time unit of the <tt>timeout</tt> argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  a <tt>Future</tt> object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the timeout is negative
@@ -689,20 +687,20 @@
      * @throws  NotYetConnectedException
      *          If this channel is not connected
      */
-    public abstract <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                                  long timeout,
-                                                  TimeUnit unit,
-                                                  A attachment,
-                                                  CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long timeout,
+                                              TimeUnit unit,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
     /**
      * @throws  WritePendingException       {@inheritDoc}
      * @throws  NotYetConnectedException
      *          If this channel is not connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                               A attachment,
-                                               CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
     {
         return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
     }
@@ -713,7 +711,7 @@
      *          If this channel is not connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src) {
+    public final Future<Integer> write(ByteBuffer src) {
         return write(src, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 }
--- a/src/share/classes/java/nio/channels/AsynchronousFileChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousFileChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -31,7 +31,8 @@
 import java.nio.file.spi.*;
 import java.nio.ByteBuffer;
 import java.io.IOException;
-import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutorService;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Collections;
@@ -65,23 +66,23 @@
  * </ul>
  *
  * <p> The {@link #read read}, {@link #write write}, and {@link #lock lock}
- * methods defined by this class are asynchronous  and return an {@link IoFuture}
+ * methods defined by this class are asynchronous  and return a {@link Future}
  * to represent the pending result of the operation. This may be used to check
  * if the operation has completed, to wait for its completion, and to retrieve
  * the result. These method may optionally specify a {@link CompletionHandler}
  * that is invoked to consume the result of the I/O operation when it completes.
  *
- * <p> An {@link AsynchronousFileChannel} is associated with a thread pool to
+ * <p> An {@code AsynchronousFileChannel} is associated with a thread pool to
  * which tasks are submitted to handle I/O events and dispatch to completion
  * handlers that consume the results of I/O operations on the channel. The
- * parameters that configure the thread pool are defined by the {@link
- * AsynchronousChannelGroup} class and are specified to the {@link
- * #open(Path,Set,Map,Attribute[]) open} method when opening the file. When
- * an {@link AsynchronousFileChannel} is created without a map of parameters to
- * configure a thread pool then the channel is associated with a system-dependent
- * and default thread pool that may be shared with other channels of this type.
- * The default thread pool is configured by the system properties defined by the
- * {@link AsynchronousChannelGroup} class.
+ * completion handler for an I/O operation is guaranteed to be invoked by the
+ * initiating thread itself (for the case that the I/O operation completes
+ * immediately) or by one of the threads in the associated thread pool. When
+ * an {@code AsynchronousFileChannel} is created without specifying a thread
+ * pool then the channel is associated with a system-dependent and default
+ * thread pool that may be shared with other channels of this type. The default
+ * thread pool is configured by the system properties defined by the {@link
+ * AsynchronousChannelGroup} class.
  *
  * <p> Channels of this type are safe for use by multiple concurrent threads. The
  * {@link Channel#close close} method may be invoked at any time, as specified
@@ -205,11 +206,6 @@
      * <p> An implementation may also support additional implementation-specific
      * options.
      *
-     * <p> The {@code params} parameter is a {@link Map} containing parameters
-     * to configure a thread pool for the resulting channel. The {@code Map}
-     * may contain any of the parameters defined by the {@link
-     * AsynchronousChannelGroup} class.
-     *
      * <p> The {@code attrs} parameter is an optional array of file {@link Attribute
      * attributes} to set atomically when creating the file.
      *
@@ -221,9 +217,9 @@
      *          The path of the file to open or create
      * @param   options
      *          Options specifying how the file is opened
-     * @param   params
-     *          The parameters to configure the thread pool or {@code null} to
-     *          associate the channel with the default thread pool
+     * @param   executor
+     *          The thread pool or {@code null} to associate the channel with
+     *          the default thread pool
      * @param   attrs
      *          An optional list of attributes to set atomically when creating
      *          the file
@@ -252,14 +248,12 @@
      */
     public static AsynchronousFileChannel open(Path file,
                                                Set<? extends OpenOption> options,
-                                               Map<String,?> params,
+                                               ExecutorService executor,
                                                Attribute<?>... attrs)
         throws IOException
     {
-        if (file != null && !(file instanceof AbstractPath))
-            throw new UnsupportedOperationException();
-        FileSystemProvider provider = ((AbstractPath)file).getFileSystem().provider();
-        return provider.newAsynchronousFileChannel(file, options, params, attrs);
+        FileSystemProvider provider = file.getFileSystem().provider();
+        return provider.newAsynchronousFileChannel(file, options, executor, attrs);
     }
 
     private static final Attribute<?>[] NO_ATTRIBUTES = new Attribute[0];
@@ -271,7 +265,7 @@
      * <p> An invocation of this method behaves in exactly the same way as the
      * invocation
      * <pre>
-     *     ch.{@link #open(Path,Set,Map,Attribute[]) open}(file, opts, null, new Attribute&lt;?&gt;[0]);
+     *     ch.{@link #open(Path,Set,ExecutorService,Attribute[]) open}(file, opts, null, new Attribute&lt;?&gt;[0]);
      * </pre>
      * where {@code opts} is a {@code Set} containing the options specified to
      * this method.
@@ -401,8 +395,8 @@
      * Acquires a lock on the given region of this channel's file.
      *
      * <p> This method initiates an operation to acquire a lock on the given region
-     * of this channel's file. The method returns an {@code IoFuture} representing
-     * the pending result of the operation. Its {@link IoFuture#get() get}
+     * of this channel's file. The method returns a {@code Future} representing
+     * the pending result of the operation. Its {@link Future#get() get}
      * method returns the {@link FileLock} on successful completion.
      *
      * <p> The region specified by the {@code position} and {@code size}
@@ -448,12 +442,11 @@
      *          {@code false} to request an exclusive lock, in which case this
      *          channel must be open for writing (and possibly reading)
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  a {@code Future} object representing the pending result
      *
      * @throws  OverlappingFileLockException
      *          If a lock that overlaps the requested region is already held by
@@ -466,18 +459,18 @@
      * @throws  NonWritableChannelException
      *          If {@code shared} is false but this channel was not opened for writing
      */
-    public abstract <A> IoFuture<FileLock,A> lock(long position,
-                                                  long size,
-                                                  boolean shared,
-                                                  A attachment,
-                                                  CompletionHandler<FileLock,? super A> handler);
+    public abstract <A> Future<FileLock> lock(long position,
+                                              long size,
+                                              boolean shared,
+                                              A attachment,
+                                              CompletionHandler<FileLock,? super A> handler);
 
     /**
      * Acquires an exclusive lock on this channel's file.
      *
      * <p> This method initiates an operation to acquire an exclusive lock on this
-     * channel's file. The method returns an {@code IoFuture} representing
-     * the pending result of the operation. Its {@link IoFuture#get() get}
+     * channel's file. The method returns a {@code Future} representing
+     * the pending result of the operation. Its {@link Future#get() get}
      * method returns the {@link FileLock} on successful completion.
      *
      * <p> An invocation of this method of the form {@code ch.lock(att,handler)}
@@ -487,12 +480,11 @@
      * </pre>
      *
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  a {@code Future} object representing the pending result
      *
      * @throws  OverlappingFileLockException
      *          If a lock is already held by this Java virtual machine, or there
@@ -500,8 +492,8 @@
      * @throws  NonWritableChannelException
      *          If this channel was not opened for writing
      */
-    public final <A> IoFuture<FileLock,A> lock(A attachment,
-                                               CompletionHandler<FileLock,? super A> handler)
+    public final <A> Future<FileLock> lock(A attachment,
+                                           CompletionHandler<FileLock,? super A> handler)
     {
         return lock(0L, Long.MAX_VALUE, false, attachment, handler);
     }
@@ -510,8 +502,8 @@
      * Acquires an exclusive lock on this channel's file.
      *
      * <p> This method initiates an operation to acquire an exclusive lock on this
-     * channel's file. The method returns an {@code IoFuture} representing the
-     * pending result of the operation. Its {@link IoFuture#get() get} method
+     * channel's file. The method returns an {@code Future} representing the
+     * pending result of the operation. Its {@link Future#get() get} method
      * returns the {@link FileLock} on successful completion.
      *
      * <p> An invocation of this method behaves in exactly the same way as the
@@ -520,7 +512,7 @@
      *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, null)
      * </pre>
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  an {@code Future} object representing the pending result
      *
      * @throws  OverlappingFileLockException
      *          If a lock is already held by this Java virtual machine, or there
@@ -528,7 +520,7 @@
      * @throws  NonWritableChannelException
      *          If this channel was not opened for writing
      */
-    public final <A> IoFuture<FileLock,A> lock() {
+    public final Future<FileLock> lock() {
         return lock(0L, Long.MAX_VALUE, false, null, null);
     }
 
@@ -621,8 +613,8 @@
      *
      * <p> This method initiates the reading of a sequence of bytes from this
      * channel into the given buffer, starting at the given file position. This
-     * method returns an {@code IoFuture} representing the pending result of the
-     * operation. The IoFuture's {@link IoFuture#get() get} method returns the
+     * method returns an {@code Future} representing the pending result of the
+     * operation. The Future's {@link Future#get() get} method returns the
      * number of bytes read or {@code -1} if the given position is greater than
      * or equal to the file's size at the time that the read is attempted.
      *
@@ -638,22 +630,21 @@
      *          The file position at which the transfer is to begin;
      *          must be non-negative
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  an {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the position is negative or the buffer is read-only
      * @throws  NonReadableChannelException
      *          If this channel was not opened for reading
      */
-    public abstract <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                                 long position,
-                                                 A attachment,
-                                                 CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long position,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
 
     /**
      * Reads a sequence of bytes from this channel into the given buffer,
@@ -661,8 +652,8 @@
      *
      * <p> This method initiates the reading of a sequence of bytes from this
      * channel into the given buffer, starting at the given file position. This
-     * method returns an {@code IoFuture} representing the pending result of the
-     * operation. The IoFuture's {@link IoFuture#get() get} method returns the
+     * method returns an {@code Future} representing the pending result of the
+     * operation. The Future's {@link Future#get() get} method returns the
      * number of bytes read or {@code -1} if the given position is greater
      * than or equal to the file's size at the time that the read is attempted.
      *
@@ -676,15 +667,14 @@
      *          The file position at which the transfer is to begin;
      *          must be non-negative
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  an {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the position is negative or the buffer is read-only
      * @throws  NonReadableChannelException
      *          If this channel was not opened for reading
      */
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst, long position)
-    {
+    public final Future<Integer> read(ByteBuffer dst, long position) {
         return read(dst, position, null, null);
     }
 
@@ -694,8 +684,8 @@
      *
      * <p> This method initiates the writing of a sequence of bytes to this channel
      * from the given buffer, starting at the given file position. The method
-     * returns an {@code IoFuture} representing the pending result of the write
-     * operation. The IoFuture's {@link IoFuture#get() get} method returns the
+     * returns an {@code Future} representing the pending result of the write
+     * operation. The Future's {@link Future#get() get} method returns the
      * number of bytes written.
      *
      * <p> This method works in the same manner as the {@link
@@ -712,22 +702,21 @@
      *          The file position at which the transfer is to begin;
      *          must be non-negative
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  an {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the position is negative
      * @throws  NonWritableChannelException
      *          If this channel was not opened for writing
      */
-    public abstract <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                                  long position,
-                                                  A attachment,
-                                                  CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long position,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
 
     /**
      * Writes a sequence of bytes to this channel from the given buffer, starting
@@ -735,8 +724,8 @@
      *
      * <p> This method initiates the writing of a sequence of bytes to this channel
      * from the given buffer, starting at the given file position. The method
-     * returns an {@code IoFuture} representing the pending result of the write
-     * operation. The IoFuture's {@link IoFuture#get() get} method returns the
+     * returns an {@code Future} representing the pending result of the write
+     * operation. The Future's {@link Future#get() get} method returns the
      * number of bytes written.
      *
      * <p> This method is equivalent to invoking {@link
@@ -749,16 +738,14 @@
      *          The file position at which the transfer is to begin;
      *          must be non-negative
      *
-     * @return  an {@code IoFuture} object representing the pending result
+     * @return  an {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the position is negative
      * @throws  NonWritableChannelException
      *          If this channel was not opened for writing
      */
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                               long position)
-    {
+    public final Future<Integer> write(ByteBuffer src, long position) {
         return write(src, position, null, null);
     }
 }
--- a/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -28,6 +28,7 @@
 import java.nio.channels.spi.*;
 import java.net.SocketOption;
 import java.net.SocketAddress;
+import java.util.concurrent.Future;
 import java.io.IOException;
 
 /**
@@ -74,17 +75,18 @@
  *      AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000));
  *
  *  listener.accept(null, new CompletionHandler&lt;AsynchronousSocketChannel,Void&gt;() {
- *      public void completed(IoFuture&lt;AsynchronousSocketChannel,Void&gt; result) {
- *          try {
- *              AsynchronousSocketChannel ch = result.getNow();
- *              :
- *          } catch (IOException x) {
- *              // accept failed
- *          }
+ *      public void completed(AsynchronousSocketChannel ch, Void att) {
+ *          handle(ch);
  *
  *          // accept the next connection
  *          listener.accept(null, this);
  *      }
+ *      public void failed(Throwable exc, Void att) {
+ *          ...
+ *      }
+ *      public void cancelled(Void att) {
+ *          ...
+ *      }
  *  });
  * </pre>
  *
@@ -238,8 +240,8 @@
      * Accepts a connection.
      *
      * <p> This method initiates accepting a connection made to this channel's
-     * socket, returning an {@link IoFuture} representing the pending result
-     * of the operation. The {@code IoFuture}'s {@link IoFuture#get() get}
+     * socket, returning a {@link Future} representing the pending result
+     * of the operation. The {@code Future}'s {@link Future#get() get}
      * method will return the {@link AsynchronousSocketChannel} for the new
      * connection on successful completion.
      *
@@ -259,19 +261,18 @@
      * SecurityException}.
      *
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned <tt>IoFuture</tt> object; can be <tt>null</tt>
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  an <tt>Future</tt> object representing the pending result
      *
      * @throws  AcceptPendingException
      *          If an accept operation is already in progress on this channel
      * @throws  NotYetBoundException
      *          If this channel's socket has not yet been bound
      */
-    public abstract <A> IoFuture<AsynchronousSocketChannel,A>
+    public abstract <A> Future<AsynchronousSocketChannel>
         accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler);
 
     /**
@@ -281,14 +282,14 @@
      * #accept(Object,CompletionHandler)} with the {@code attachment}
      * and handler parameters set to {@code null}.
      *
-     * @return  an <tt>IoFuture</tt> object representing the pending result
+     * @return  an <tt>Future</tt> object representing the pending result
      *
      * @throws  AcceptPendingException
      *          If an accept operation is already in progress on this channel
      * @throws  NotYetBoundException
      *          If this channel's socket has not yet been bound
      */
-    public final <A> IoFuture<AsynchronousSocketChannel,A> accept() {
+    public final Future<AsynchronousSocketChannel> accept() {
         return accept(null, null);
     }
 }
--- a/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,6 +27,7 @@
 
 import java.nio.channels.spi.*;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
 import java.io.IOException;
 import java.net.SocketOption;
 import java.net.SocketAddress;
@@ -268,9 +269,9 @@
      * Connects this channel.
      *
      * <p> This method initiates an operation to connect this channel, returning
-     * an {@code IoFuture} representing the pending result of the operation. If
-     * the connection is successfully established then the {@code IoFuture}'s
-     * {@link IoFuture#get() get} method will return {@code null}. If the
+     * a {@code Future} representing the pending result of the operation. If
+     * the connection is successfully established then the {@code Future}'s
+     * {@link Future#get() get} method will return {@code null}. If the
      * connection cannot be established then the channel is closed. In that case,
      * invoking the {@code get} method throws {@link
      * java.util.concurrent.ExecutionException} with an {@code IOException} as
@@ -285,12 +286,11 @@
      * @param   remote
      *          The remote address to which this channel is to be connected
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  UnresolvedAddressException
      *          If the given remote address is not fully resolved
@@ -306,9 +306,9 @@
      *
      * @see #getConnectedAddress
      */
-    public abstract <A> IoFuture<Void,A> connect(SocketAddress remote,
-                                                 A attachment,
-                                                 CompletionHandler<Void,? super A> handler);
+    public abstract <A> Future<Void> connect(SocketAddress remote,
+                                             A attachment,
+                                             CompletionHandler<Void,? super A> handler);
 
     /**
      * Connects this channel.
@@ -320,7 +320,7 @@
      * @param   remote
      *          The remote address to which this channel is to be connected
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  UnresolvedAddressException
      *          If the given remote address is not fully resolved
@@ -334,7 +334,7 @@
      *          If a security manager has been installed
      *          and it does not permit access to the given remote endpoint
      */
-    public final <A> IoFuture<Void,A> connect(SocketAddress remote) {
+    public final Future<Void> connect(SocketAddress remote) {
         return connect(remote, null, null);
     }
 
@@ -342,9 +342,9 @@
      * Reads a sequence of bytes from this channel into the given buffer.
      *
      * <p> This method initiates the reading of a sequence of bytes from this
-     * channel into the given buffer, returning an {@code IoFuture} representing
-     * the pending result of the operation. The {@code IoFuture}'s {@link
-     * IoFuture#get() get} method returns the number of bytes read or {@code -1}
+     * channel into the given buffer, returning a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method returns the number of bytes read or {@code -1}
      * if all bytes have been read and channel has reached end-of-stream.
      *
      * <p> If a timeout is specified and the timeout elapses before the operation
@@ -366,12 +366,11 @@
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the {@code timeout} parameter is negative or the buffer is
@@ -381,11 +380,11 @@
      * @throws  NotYetConnectedException
      *          If this channel is not yet connected
      */
-    public abstract <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                                 long timeout,
-                                                 TimeUnit unit,
-                                                 A attachment,
-                                                 CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
 
     /**
      * @throws  IllegalArgumentException        {@inheritDoc}
@@ -394,7 +393,7 @@
      *          If this channel is not yet connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst,
+    public final <A> Future<Integer> read(ByteBuffer dst,
                                               A attachment,
                                               CompletionHandler<Integer,? super A> handler)
     {
@@ -408,7 +407,7 @@
      *          If this channel is not yet connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst) {
+    public final Future<Integer> read(ByteBuffer dst) {
         return read(dst, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 
@@ -445,9 +444,9 @@
      * I/O operation is performed with the maximum number of buffers allowed by
      * the operating system.
      *
-     * <p> The return value from this method is an {@code IoFuture} representing
-     * the pending result of the operation. The {@code IoFuture}'s {@link
-     * IoFuture#get() get} method returns the number of bytes read or {@code -1L}
+     * <p> The return value from this method is a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method returns the number of bytes read or {@code -1L}
      * if all bytes have been read and the channel has reached end-of-stream.
      *
      * <p> If a timeout is specified and the timeout elapses before the operation
@@ -472,12 +471,11 @@
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  IndexOutOfBoundsException
      *          If the pre-conditions for the {@code offset}  and {@code length}
@@ -490,20 +488,20 @@
      * @throws  NotYetConnectedException
      *          If this channel is not yet connected
      */
-    public abstract <A> IoFuture<Long,A> read(ByteBuffer[] dsts,
-                                              int offset,
-                                              int length,
-                                              long timeout,
-                                              TimeUnit unit,
-                                              A attachment,
-                                              CompletionHandler<Long,? super A> handler);
+    public abstract <A> Future<Long> read(ByteBuffer[] dsts,
+                                          int offset,
+                                          int length,
+                                          long timeout,
+                                          TimeUnit unit,
+                                          A attachment,
+                                          CompletionHandler<Long,? super A> handler);
 
     /**
      * Writes a sequence of bytes to this channel from the given buffer.
      *
      * <p> This method initiates the writing of a sequence of bytes to this channel
-     * from the given buffer, returning an {@code IoFuture} representing the
-     * pending result of the operation. The {@code IoFuture}'s {@link IoFuture#get()
+     * from the given buffer, returning a {@code Future} representing the
+     * pending result of the operation. The {@code Future}'s {@link Future#get()
      * get} method will return the number of bytes written.
      *
      * <p> If a timeout is specified and the timeout elapses before the operation
@@ -525,12 +523,11 @@
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  IllegalArgumentException
      *          If the {@code timeout} parameter is negative
@@ -539,11 +536,11 @@
      * @throws  NotYetConnectedException
      *          If this channel is not yet connected
      */
-    public abstract <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                                  long timeout,
-                                                  TimeUnit unit,
-                                                  A attachment,
-                                                  CompletionHandler<Integer,? super A> handler);
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long timeout,
+                                              TimeUnit unit,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
 
     /**
      * @throws  WritePendingException          {@inheritDoc}
@@ -551,9 +548,9 @@
      *          If this channel is not yet connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                               A attachment,
-                                               CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
 
     {
         return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
@@ -565,7 +562,7 @@
      *          If this channel is not yet connected
      */
     @Override
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src) {
+    public final Future<Integer> write(ByteBuffer src) {
         return write(src, 0L, TimeUnit.MILLISECONDS, null, null);
     }
 
@@ -601,9 +598,9 @@
      * remaining), exceeds this limit, then the I/O operation is performed with
      * the maximum number of buffers allowed by the operating system.
      *
-     * <p> The return value from this method is an {@code IoFuture} representing
-     * the pending result of the operation. The {@code IoFuture}'s {@link
-     * IoFuture#get() get} method will return the number of bytes written.
+     * <p> The return value from this method is a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method will return the number of bytes written.
      *
      * <p> If a timeout is specified and the timeout elapses before the operation
      * completes then it completes with the exception {@link
@@ -627,12 +624,11 @@
      * @param   unit
      *          The time unit of the {@code timeout} argument
      * @param   attachment
-     *          The object to {@link IoFuture#attachment() attach} to the
-     *          returned {@code IoFuture} object; can be {@code null}
+     *          The object to attach to the I/O operation; can be {@code null}
      * @param   handler
      *          The handler for consuming the result; can be {@code null}
      *
-     * @return  An {@code IoFuture} object representing the pending result
+     * @return  A {@code Future} object representing the pending result
      *
      * @throws  IndexOutOfBoundsException
      *          If the pre-conditions for the {@code offset}  and {@code length}
@@ -644,11 +640,11 @@
      * @throws  NotYetConnectedException
      *          If this channel is not yet connected
      */
-    public abstract <A> IoFuture<Long,A> write(ByteBuffer[] srcs,
-                                               int offset,
-                                               int length,
-                                               long timeout,
-                                               TimeUnit unit,
-                                               A attachment,
-                                               CompletionHandler<Long,? super A> handler);
+    public abstract <A> Future<Long> write(ByteBuffer[] srcs,
+                                           int offset,
+                                           int length,
+                                           long timeout,
+                                           TimeUnit unit,
+                                           A attachment,
+                                           CompletionHandler<Long,? super A> handler);
 }
--- a/src/share/classes/java/nio/channels/CompletionHandler.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/CompletionHandler.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,30 +30,49 @@
  *
  * <p> The asynchronous channels defined in this package allow a completion
  * handler to be specified to consume the result of an asynchronous operation.
- * When an operation completes the handler's {@link #completed(IoFuture)
- * completed} method is invoked with the result.
+ * The {@link #completed completed} is invoked when the I/O operation completes
+ * successfully. The {@link #failed failed} method is invoked if the I/O
+ * operations fails. The {@link #cancelled cancelled} is invoked when the I/O
+ * operation is cancelled by invoking the {@link
+ * java.util.concurrent.Future#cancel cancel} method. The implementations of
+ * these methods should complete in a timely manner so as to avoid keeping the
+ * invoking thread from dispatching to other completion handlers.
  *
- * @param   <R>     The result type
- * @param   <A>     The type of the object attached to the {@link IoFuture}
+ * @param   <V>     The result type of the I/O operation
+ * @param   <A>     The type of the object attached to the I/O operation
  *
  * @since 1.7
  */
 
-public interface CompletionHandler<R,A> {
+public interface CompletionHandler<V,A> {
 
     /**
      * Invoked when an operation has completed.
      *
-     * <p> The {@code result} parameter is the {@link IoFuture} representing the
-     * result of the operation returned when the I/O operation was initiated.
-     * Its {@link IoFuture#getNow() getNow} method may be invoked to retrieve
-     * the result.
+     * @param   result
+     *          The result of the I/O operation.
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void completed(V result, A attachment);
+
+    /**
+     * Invoked when an operation fails.
      *
-     * <p> This method should complete in a timely manner so as to avoid keeping
-     * this thread from dispatching to other completion handlers.
+     * @param   exc
+     *          The exception
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void failed(Throwable exc, A attachment);
+
+    /**
+     * Invoked when an operation is cancelled by invoking the {@link
+     * java.util.concurrent.Future#cancel cancel} method.
      *
-     * @param   result
-     *          The {@code IoFuture} representing the result of the operation
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
      */
-    void completed(IoFuture<R,A> result);
+    void cancelled(A attachment);
+
 }
--- a/src/share/classes/java/nio/channels/FileChannel.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/FileChannel.java	Tue Jun 24 20:05:07 2008 +0100
@@ -285,9 +285,7 @@
                                    Attribute<?>... attrs)
         throws IOException
     {
-        if (file != null && !(file instanceof AbstractPath))
-            throw new UnsupportedOperationException();
-        FileSystemProvider provider = ((AbstractPath)file).getFileSystem().provider();
+        FileSystemProvider provider = file.getFileSystem().provider();
         return provider.newFileChannel(file, options, attrs);
     }
 
--- a/src/share/classes/java/nio/channels/IoFuture.java	Tue Jun 24 18:30:03 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package java.nio.channels;
-
-import java.util.concurrent.*;
-import java.io.IOException;
-
-/**
- * A {@code Future} representing the result of an asynchronous I/O operation.
- *
- * <p> In addition to the methods defined by the {@code Future} interface, an
- * {@code IoFuture} allows for the attachment of a single arbitrary object. The
- * object can be used to associate application-specific data or context required
- * when consuming the result of the I/O operation. This is important for cases
- * where the same {@link CompletionHandler} is used to consume the result of
- * several I/O operations. The attachment object, if any, is specified when
- * initiating the operation. The {@link #attachment() attachment} method is used
- * to retrieve  it. The attachment may later be discarded by {@link #attach(Object)
- * attaching} {@code null}.
- *
- * @param   <R>     The result type
- * @param   <A>     The attachment type
- *
- * @since 1.7
- */
-
-public interface IoFuture<R,A>
-    extends Future<R>
-{
-    /**
-     * Returns the channel upon which the asynchronous I/O operation was
-     * initiated.
-     *
-     * @return  The asynchronous channel
-     */
-    AsynchronousChannel channel();
-
-    /**
-     * Retrieves the result of a completed I/O operation.
-     *
-     * <p> The method is intended to be invoked from a {@link CompletionHandler}
-     * to retrieve the result of a completed I/O operation. It is equivalent to
-     * invoking the {@link #get() get} method to retrieve the result except
-     * that the method does not wait for the result.
-     *
-     * @return  The result
-     *
-     * @throws  IOException
-     *          If the I/O operation completed because an I/O error occurred
-     * @throws  SecurityException
-     *          If a security manager is installed and it denied access
-     *          required to complete the I/O operation
-     * @throws  CancellationException
-     *          If the I/O operation cancelled by invoking the {@link #cancel
-     *          cancel} method
-     * @throws  IllegalStateException
-     *          If the operation has not completed
-     */
-    R getNow() throws IOException;
-
-    /**
-     * Attempts to cancel execution of this I/O operation.
-     *
-     * <p> Where the implementation supports a means to cancel I/O operations,
-     * and where cancellation may leave the channel, or the entity to which it
-     * is connected, in an inconsistent state, then the channel is put into an
-     * implementation specific <em>error state</em> that prevents further
-     * attempts to initiate I/O operations on the channel. For example, if a read
-     * operation is cancelled but the implementation cannot guarantee that bytes
-     * have not been read from the channel then it puts the channel into error
-     * state state; further attempts to initiate a {@code read} operation causes
-     * an unspecified runtime exception to be thrown.
-     *
-     * <p> Where the value of the {@code mayInterruptIfRunning} parameter is
-     * {@code true}, then I/O operation may be cancelled <em>forcefully</em>
-     * by closing the channel. If there are other I/O operations outstanding on
-     * the channel then these operation will complete with the exception {@link
-     * AsynchronousCloseException}.
-     *
-     * <p> If a {@link CompletionHandler} was specified when this I/O operation
-     * was initiated, and the I/O operation has not completed, then the
-     * completion handler will not be executed.
-     *
-     * <p> Where this method is used to attempt to cancel read or write
-     * operations then it recommended that all {@link java.nio.ByteBuffer buffers}
-     * used in the I/O operations be discarded or care taken to ensure that the
-     * buffers are not accessed while the channel remains open.
-     *
-     * <p> This method otherwise behaves exactly as specified by the {@link
-     * Future} interface.
-     *
-     * @param   mayInterruptIfRunning
-     *          {@code true} if the operation should be cancelled forcefully
-     *          (possibly by closing the channel), {@code false} otherwise
-     *
-     * @return  {@code false} if the I/O operation could not be cancelled,
-     *          typically because it has already completed; {@code true} otherwise
-     */
-    @Override
-    boolean cancel(boolean mayInterruptIfRunning);
-
-    /**
-     * Retrieves the current attachment.
-     *
-     * @return  The object currently attached to this channel future or {@code null}
-     *          if there is no attachment
-     */
-    A attachment();
-
-    /**
-     * Attaches the given object to this channel future.
-     *
-     * <p> An attached object may later be retrieved via the {@link #attachment()
-     * attachment} method. Only one object may be attached at a time; invoking this
-     * method causes any previous attachment to be discarded. The current attachment
-     * may be discarded by attaching {@code null}.
-     *
-     * @param   ob
-     *          The object to be attached; may be {@code null}
-     *
-     * @return  The previously-attached object, if any, otherwise {@code null}
-     *
-     */
-    A attach(A ob);
-}
--- a/src/share/classes/java/nio/channels/package-info.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/package-info.java	Tue Jun 24 20:05:07 2008 +0100
@@ -236,8 +236,6 @@
  *     <td>An asynchronous channel to a datagram-oriented socket</td></tr>
  * <tr><td valign=top><tt>{@link java.nio.channels.CompletionHandler}</tt></td>
  *     <td>A handler for consuming the result of an asynchronous operation</td></tr>
- * <tr><td valign=top><tt>{@link java.nio.channels.IoFuture}</tt></td>
- *     <td>A Future representing the result of an asynchronous I/O operation</td></tr>
  * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousChannelGroup}</tt></td>
  *     <td>A grouping of asynchronous channels for the purpose of resource sharing</td></tr>
  * </table></blockquote>
@@ -248,8 +246,8 @@
  * <p> {@link java.nio.channels.AsynchronousChannel Asynchronous channels} are a
  * special type of channel capable of asynchronous I/O operations. Asynchronous
  * channels are non-blocking and define methods to initiate asynchronous
- * operations, returning an {@link java.nio.channels.IoFuture} representing the
- * pending result of each operation. The {@code IoFuture} can be used to poll or
+ * operations, returning a {@link java.util.concurrent.Future} representing the
+ * pending result of each operation. The {@code Future} can be used to poll or
  * wait for the result of the operation. Asynchronous I/O operations can also
  * specify a {@link java.nio.channels.CompletionHandler} to invoke when the
  * operation completes. A completion handler is user provided code that is executed
--- a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -28,10 +28,11 @@
 import java.nio.channels.*;
 import java.net.ProtocolFamily;
 import java.io.IOException;
-import java.util.Map;
 import java.util.Iterator;
 import java.util.ServiceLoader;
 import java.util.ServiceConfigurationError;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
@@ -56,6 +57,14 @@
     private static final Object lock = new Object();
     private static AsynchronousChannelProvider provider = null;
 
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("asynchronousChannelProvider"));
+        return null;
+    }
+    private AsynchronousChannelProvider(Void ignore) { }
+
     /**
      * Initializes a new instance of this class.
      *
@@ -64,9 +73,7 @@
      *          {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
      */
     protected AsynchronousChannelProvider() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null)
-            sm.checkPermission(new RuntimePermission("asynchronousChannelProvider"));
+        this(checkPermission());
     }
 
     private static boolean loadProviderFromProperty() {
@@ -168,15 +175,28 @@
     /**
      * Constructs a new asynchronous channel group.
      *
-     * @param   params
-     *          A map of parameters to configure the group's thread pool; may
-     *          be empty
+     * @param   factory
+     *          The factory to use to create threads
+     * @param   initialSize
+     *          The number of threads to initially create in the pool
      *
      * @throws  IOException
      *          If an I/O error occurs
      */
     public abstract AsynchronousChannelGroup openAsynchronousChannelGroup
-        (Map<String,?> params) throws IOException;
+        (ThreadFactory factory, int initialSize) throws IOException;
+
+    /**
+     * Constructs a new asynchronous channel group.
+     *
+     * @param   executor
+     *          The thread pool
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousChannelGroup openAsynchronousChannelGroup
+        (ExecutorService executor) throws IOException;
 
     /**
      * Opens an asynchronous server-socket channel.
--- a/src/share/classes/java/nio/file/FileSystem.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/FileSystem.java	Tue Jun 24 20:05:07 2008 +0100
@@ -314,6 +314,10 @@
      *   <td>Matches file names ending in {@code .java}</td>
      * </tr>
      * <tr>
+     *   <td>{@code *.*}</td>
+     *   <td>Matches file names containing a dot</td>
+     * </tr>
+     * <tr>
      * <tr>
      *   <td>{@code *.{java,class}}</td>
      *   <td>Matches file names ending with {@code .java} or {@code .class}</td>
--- a/src/share/classes/java/nio/file/Files.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/Files.java	Tue Jun 24 20:05:07 2008 +0100
@@ -268,9 +268,9 @@
                                      DirectoryAction action)
         throws IOException
     {
-        if (dir != null && !(dir instanceof AbstractPath))
+        if (dir != null && !(dir instanceof Path))
             throw new IllegalArgumentException("'dir' is not associated with a FileSystem");
-        final NameMatcher matcher = ((AbstractPath)dir).getFileSystem()
+        final NameMatcher matcher = ((Path)dir).getFileSystem()
             .getNameMatcher(syntaxAndPattern);
         DirectoryStream.Filter filter = new DirectoryStream.Filter() {
             @Override
@@ -322,8 +322,8 @@
      * or an {@code Error} or {@code RuntimeException} is thrown by the visitor.
      *
      * <p> For each file encountered this method attempts to gets its {@link
-     * java.nio.file.spi.BasicFileAttributes}. If the attributes cannot be read
-     * then the visitor's {@link FileVisitor#visitFileFailed visitFileFailed}
+     * java.nio.file.attribute.BasicFileAttributes}. If the attributes cannot be
+     * read then the visitor's {@link FileVisitor#visitFileFailed visitFileFailed}
      * method is invoked. Otherwise, the attributes are read, and if the file is
      * not a directory, then the visitor's {@link FileVisitor#visitFile visitFile}
      * method is invoked.
--- a/src/share/classes/java/nio/file/Path.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/Path.java	Tue Jun 24 20:05:07 2008 +0100
@@ -123,6 +123,13 @@
     protected Path() { }
 
     /**
+     * Returns the file system that created this object.
+     *
+     * @return  The file system that created this object
+     */
+    public abstract FileSystem getFileSystem();
+
+    /**
      * Constructs a {@code Path} by converting the given path string.
      *
      * <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath
--- a/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -104,7 +104,6 @@
     AclFileAttributeView bind(FileRef obj, boolean followLinks);
 
     /**
-     * @throws  UnsupportedOperationException           {@inheritDoc}
      * @throws  IllegalStateException                   {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
      * @throws  SecurityException                       {@inheritDoc}
@@ -127,9 +126,6 @@
      * @return  An ordered list of {@link AclEntry entries} representing the
      *          ACL
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support reading a symbolic link's ACL
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for reading
@@ -171,9 +167,6 @@
      *
      * @return  This attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating a symbolic link's ACL
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
--- a/src/share/classes/java/nio/file/attribute/Attributes.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/Attributes.java	Tue Jun 24 20:05:07 2008 +0100
@@ -99,9 +99,7 @@
      * @return  The POSIX file attributes
      *
      * @throws  UnsupportedOperationException
-     *          If the {@code PosixFileAttributeView} is not available, or if
-     *          not following links, the file is a link, and the implementation
-     *          does not support reading the attributes of a symbolic link
+     *          If the {@code PosixFileAttributeView} is not available
      * @throws  IOException
      *          If an I/O error occurs
      * @throws  SecurityException
@@ -144,9 +142,7 @@
      * @return  The DOS file attributes
      *
      * @throws  UnsupportedOperationException
-     *          If the {@code DosFileAttributeView} is not available, or if
-     *          not following links, the file is a link, and the implementation
-     *          does not support reading the attributes of a symbolic link
+     *          If the {@code DosFileAttributeView} is not available
      * @throws  IOException
      *          If an I/O error occurs
      * @throws  SecurityException
--- a/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -110,9 +110,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalArgumentException
      *          If any of the parameters is a negative value other than {@code
      *          -1L}
--- a/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -51,9 +51,6 @@
     DosFileAttributeView bind(FileRef file, boolean followLinks);
 
     /**
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support reading the attributes of a symbolic link
      * @throws  IllegalStateException                   {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
      * @throws  SecurityException                       {@inheritDoc}
@@ -63,9 +60,6 @@
         throws IOException;
 
     /**
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalStateException                   {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
      * @throws  SecurityException                       {@inheritDoc}
@@ -89,9 +83,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
@@ -117,9 +108,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
@@ -145,9 +133,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
@@ -173,9 +158,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
--- a/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -55,9 +55,6 @@
      *
      * @return  the file owner
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support reading the owner of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for reading
@@ -85,9 +82,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the owner of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound, or if bound to an object
      *          that is not open for writing
--- a/src/share/classes/java/nio/file/attribute/NamedAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/NamedAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -83,9 +83,6 @@
      * @return  An object to iterate over the names of the file's named
      *          attributes
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support accessing named attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound
      * @throws  IOException
@@ -107,9 +104,6 @@
      *
      * @return  The size of the attribute value, in bytes.
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support accessing named attributes of a symbolic link
      * @throws  ArithmeticException
      *          If the size of the attribute is larger than {@link Integer#MAX_VALUE}
      * @throws  IllegalStateException
@@ -144,9 +138,8 @@
      *
      * @return  The number of bytes read, possibly zero
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support accessing named attributes of a symbolic link
+     * @throws  IllegalArgumentException
+     *          If the destination buffer is read-only
      * @throws  IllegalStateException
      *          If the attribute view is not bound
      * @throws  IOException
@@ -180,7 +173,7 @@
      * attribute and the creation of attribute are atomic with repect to other
      * file system activities.
      *
-     * <p> Where there is insufficient spec to store the attribute, or the
+     * <p> Where there is insufficient space to store the attribute, or the
      * attribute name or value exceed an implementation specific maximum size
      * then an {@code IOException} is thrown.
      *
@@ -191,9 +184,6 @@
      *
      * @return  The number of bytes written, possibly zero
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support accessing named attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound
      * @throws  IOException
@@ -215,9 +205,6 @@
      *
      * @return  This file attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support accessing named attributes of a symbolic link
      * @throws  IllegalStateException
      *          If the attribute view is not bound
      * @throws  IOException
--- a/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -101,9 +101,6 @@
     PosixFileAttributeView bind(FileRef file, boolean followLinks);
 
     /**
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support reading the attributes of a symbolic link
      * @throws  IllegalStateException      {@inheritDoc}
      * @throws  IOException                {@inheritDoc}
      * @throws  SecurityException
@@ -145,7 +142,6 @@
     Attribute<Set<PosixFilePermission>> newPermissionsAttribute();
 
     /**
-     * @throws  UnsupportedOperationException           {@inheritDoc}
      * @throws  IllegalStateException                   {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
      * @throws  SecurityException                       {@inheritDoc}
@@ -164,9 +160,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the permissions of a symbolic link
      * @throws  ClassCastException
      *          If the sets contains elements that are not of type {@code
      *          PosixFilePermission}
@@ -196,9 +189,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the owner of a symbolic link
      * @throws  IllegalArgumentException
      *          If the pre-conditions for the {@code owner} parameter is not met
      * @throws  IllegalStateException
@@ -226,9 +216,6 @@
      *
      * @return  this attribute view
      *
-     * @throws  UnsupportedOperationException
-     *          If not following links, the file is a link, and the implementation
-     *          does not support updating the group-owner of a symbolic link
      * @throws  IllegalArgumentException
      *          If the pre-conditions for the {@code group} parameter is not met
      * @throws  IllegalStateException
--- a/src/share/classes/java/nio/file/spi/AbstractPath.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/spi/AbstractPath.java	Tue Jun 24 20:05:07 2008 +0100
@@ -33,8 +33,7 @@
 import java.util.*;
 
 /**
- * Base implementation class for a {@code Path} that is associated with a {@link
- * FileSystem}.
+ * Base implementation class for a {@code Path}.
  *
  * <p> This class implements several of the methods defined by the {@code Path}
  * interface and provides default implementation for others.
@@ -53,14 +52,6 @@
      */
     protected AbstractPath() { }
 
-    /**
-     * Returns the file system that created this object.
-     *
-     * @return  The file system that created this object
-     */
-    public abstract FileSystem getFileSystem();
-
-
     @Override
     public final Path resolve(DirectoryEntry entry) {
         return resolve(entry.getName());
@@ -330,9 +321,7 @@
     public final Path copyTo(Path target, CopyOption... options)
         throws IOException
     {
-        if ((target instanceof AbstractPath) &&
-            (getFileSystem().provider() == ((AbstractPath)target).getFileSystem().provider()))
-        {
+        if ((getFileSystem().provider() == target.getFileSystem().provider())) {
             implCopyTo(target, options);
         } else {
             xProviderCopyTo(target, options);
@@ -359,9 +348,7 @@
     public final Path moveTo(Path target, CopyOption... options)
         throws IOException
     {
-        if ((target instanceof AbstractPath) &&
-            (getFileSystem().provider() == ((AbstractPath)target).getFileSystem().provider()))
-        {
+        if ((getFileSystem().provider() == target.getFileSystem().provider())) {
             implMoveTo(target, options);
         } else {
             // different providers so copy + delete
@@ -462,8 +449,12 @@
                               attrs.lastAccessTime(),
                               attrs.creationTime(),
                               attrs.resolution());
-            } catch (UnsupportedOperationException x) {
-                // ignore
+            } catch (IOException x) {
+                // rollback
+                try {
+                    target.delete(false);
+                } catch (IOException ignore) { }
+                throw x;
             }
         }
     }
--- a/src/share/classes/java/nio/file/spi/FileSystemProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/java/nio/file/spi/FileSystemProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,6 +30,7 @@
 import java.nio.channels.*;
 import java.net.URI;
 import java.util.*;
+import java.util.concurrent.ExecutorService;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.io.IOException;
@@ -86,6 +87,14 @@
     // used to avoid recursive loading of instaled providers
     private static boolean loadingProviders  = false;
 
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("fileSystemProvider"));
+        return null;
+    }
+    private FileSystemProvider(Void ignore) { }
+
     /**
      * Initializes a new instance of this class.
      *
@@ -99,9 +108,7 @@
      *          {@link RuntimePermission}<tt>("fileSystemProvider")</tt>
      */
     protected FileSystemProvider() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null)
-            sm.checkPermission(new RuntimePermission("fileSystemProvider"));
+        this(checkPermission());
     }
 
     // loads all installed providers
@@ -380,7 +387,7 @@
      * asynchronous file channel to access the file.
      *
      * <p> This method is invoked by the {@link
-     * AsynchronousFileChannel#open(Path,Set,Map,Attribute[])
+     * AsynchronousFileChannel#open(Path,Set,ExecutorService,Attribute[])
      * AsynchronousFileChannel.open} method to open an asynchronous file channel.
      * A provider that does not support all the features required to construct
      * an asynchronous file channel throws {@code UnsupportedOperationException}.
@@ -392,9 +399,9 @@
      *          The path of the file to open or create
      * @param   options
      *          Options specifying how the file is opened
-     * @param   params
-     *          The parameters to configure the thread pool or {@code null} to
-     *          associate the channel with the default thread pool
+     * @param   executor
+     *          The thread pool or {@code null} to associate the channel with
+     *          the default thread pool
      * @param   attrs
      *          An optional list of attributes to set atomically when creating
      *          the file
@@ -419,7 +426,7 @@
      */
     public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
                                                               Set<? extends OpenOption> options,
-                                                              Map<String,?> params,
+                                                              ExecutorService executor,
                                                               Attribute<?>... attrs)
         throws IOException
     {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/AbstractFuture.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.AsynchronousChannel;
+import java.util.concurrent.Future;
+
+/**
+ * Base implementation of Future used for asynchronous I/O
+ */
+
+abstract class AbstractFuture<V,A>
+    implements Future<V>
+{
+    private final AsynchronousChannel channel;
+    private final A attachment;
+
+    protected AbstractFuture(AsynchronousChannel channel, A attachment) {
+        this.channel = channel;
+        this.attachment = attachment;
+    }
+
+    final AsynchronousChannel channel() {
+        return channel;
+    }
+
+    final A attachment() {
+        return attachment;
+    }
+
+    /**
+     * Returns true if the operation has completed successfully.
+     */
+    abstract boolean isCompleted();
+
+    /**
+     * Returns the result of the operation if it has completed successfully.
+     */
+    abstract V value();
+
+    /**
+     * Returns the exception if the operation has failed.
+     */
+    abstract Throwable exception();
+}
--- a/src/share/classes/sun/nio/ch/AbstractIoFuture.java	Tue Jun 24 18:30:03 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.nio.ch;
-
-import java.nio.channels.IoFuture;
-import java.nio.channels.AsynchronousChannel;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Base implementation of IoFuture.
- */
-
-abstract class AbstractIoFuture<R,A>
-    implements IoFuture<R,A>
-{
-    private final AsynchronousChannel channel;
-    private volatile AtomicReference<Object> obj;   // created lazily
-
-    protected AbstractIoFuture(AsynchronousChannel channel, A attachment) {
-        this.channel = channel;
-        if (attachment != null) {
-            this.obj = new AtomicReference<Object>(attachment);
-        }
-    }
-
-    @Override
-    public final AsynchronousChannel channel() {
-        return channel;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public final A attachment() {
-        AtomicReference<Object> ref = obj;
-        return (ref == null) ? null : (A) ref.get();
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public final A attach(A ob) {
-        if (obj == null) {
-            synchronized (this) {
-                if (obj == null) {
-                    obj = new AtomicReference<Object>(ob);
-                    return null;
-                }
-            }
-        }
-        return (A) obj.getAndSet(ob);
-    }
-}
--- a/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -62,11 +62,10 @@
         super(provider);
         this.executor = pool.executor();
 
-        // use same ThreadFactory as main thread pool (only the daemon-ness is
-        // interesting since the timeout tasks don't invoke completion handlers
-        // directly).
+        // use default thread factory as thread should not be visible to
+        // application (it doesn't execute completion handlers).
         this.timeoutExecutor = (ScheduledThreadPoolExecutor)
-            Executors.newScheduledThreadPool(1, pool.threadFactory());
+            Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory());
         this.timeoutExecutor.setRemoveOnCancelPolicy(true);
     }
 
@@ -107,9 +106,9 @@
     abstract void closeAllChannels() throws IOException;
 
     /**
-     * Shutdown any worker threads waiting for I/O events.
+     * Shutdown any handler tasks waiting for I/O events.
      */
-    abstract void shutdownWorkers();
+    abstract void shutdownHandlerTasks();
 
 
     private void shutdownExecutors() {
@@ -142,7 +141,7 @@
         synchronized (shutdownNowLock) {
             if (!terminateInitiated) {
                 terminateInitiated = true;
-                shutdownWorkers();
+                shutdownHandlerTasks();
                 shutdownExecutors();
             }
         }
@@ -157,7 +156,7 @@
             if (!terminateInitiated) {
                 terminateInitiated = true;
                 closeAllChannels();
-                shutdownWorkers();
+                shutdownHandlerTasks();
                 shutdownExecutors();
             }
         }
--- a/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -26,6 +26,7 @@
 package sun.nio.ch;
 
 import java.nio.channels.*;
+import java.util.concurrent.ExecutorService;
 import java.io.IOException;
 
 /**
@@ -35,7 +36,14 @@
 abstract class AsynchronousFileChannelImpl
     extends AsynchronousFileChannel
 {
-    protected AsynchronousFileChannelImpl() {
+    private final ExecutorService executor;
+
+    protected AsynchronousFileChannelImpl(ExecutorService executor) {
+        this.executor = executor;
+    }
+
+    final ExecutorService executor() {
+        return executor;
     }
 
     /**
--- a/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -37,6 +37,7 @@
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Collections;
+import java.util.concurrent.Executor;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -45,8 +46,10 @@
  */
 
 abstract class AsynchronousServerSocketChannelImpl
-    extends AsynchronousServerSocketChannel
+    extends AsynchronousServerSocketChannel implements Cancellable
 {
+    private final Executor executor;
+
     protected final FileDescriptor fd;
 
     // the local address to which the channel's socket is bound
@@ -59,12 +62,22 @@
     private ReadWriteLock closeLock = new ReentrantReadWriteLock();
     private volatile boolean open = true;
 
+    // set true when accept operation is cancelled
+    private volatile boolean acceptKilled;
 
-    AsynchronousServerSocketChannelImpl(AsynchronousChannelProvider provider) {
+
+    AsynchronousServerSocketChannelImpl(AsynchronousChannelProvider provider,
+                                        Executor executor)
+    {
         super(provider);
+        this.executor = executor;
         this.fd = Net.serverSocket(true);
     }
 
+    final Executor executor() {
+        return executor;
+    }
+
     @Override
     public final boolean isOpen() {
         return open;
@@ -105,6 +118,15 @@
         implClose();
     }
 
+    final boolean isAcceptKilled() {
+        return acceptKilled;
+    }
+
+    @Override
+    public final void onCancel(PendingFuture<?,?> task) {
+        acceptKilled = true;
+    }
+
     @Override
     public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
         throws IOException
--- a/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -36,17 +36,15 @@
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Collections;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.Executor;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
 
 /**
  * Base implementation of AsynchronousSocketChannel
  */
 
 abstract class AsynchronousSocketChannelImpl
-    extends AsynchronousSocketChannel
+    extends AsynchronousSocketChannel implements Cancellable
 {
     protected final FileDescriptor fd;
 
@@ -174,25 +172,44 @@
         enableWriting(false);
     }
 
+    final void killReading() {
+        synchronized (readLock) {
+            readKilled = true;
+        }
+    }
+
+    final void killWriting() {
+        synchronized (writeLock) {
+            writeKilled = true;
+        }
+    }
+
+    final void killConnect() {
+        // when a connect is cancelled then the connection may have been
+        // established so prevent reading or writing.
+        killReading();
+        killWriting();
+    }
+
     /**
      * Invoked by read to initiate the I/O operation.
      */
-    abstract <R extends Number,A> IoFuture<R,A> readImpl(ByteBuffer[] dsts,
-                                                         boolean isScatteringRead,
-                                                         long timeout,
-                                                         TimeUnit unit,
-                                                         A attachment,
-                                                         CompletionHandler<R,? super A> handler);
+    abstract <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts,
+                                                     boolean isScatteringRead,
+                                                     long timeout,
+                                                     TimeUnit unit,
+                                                     A attachment,
+                                                     CompletionHandler<V,? super A> handler);
 
-    private <R extends Number,A> IoFuture<R,A> read(ByteBuffer[] dsts,
-                                                    boolean isScatteringRead,
-                                                    long timeout,
-                                                    TimeUnit unit,
-                                                    A attachment,
-                                                    CompletionHandler<R,? super A> handler)
+    private <V extends Number,A> Future<V> read(ByteBuffer[] dsts,
+                                                boolean isScatteringRead,
+                                                long timeout,
+                                                TimeUnit unit,
+                                                A attachment,
+                                                CompletionHandler<V,? super A> handler)
     {
         if (!isOpen()) {
-            IoFuture<R,A> result = CompletedIoFuture
+            CompletedFuture<V,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
@@ -209,7 +226,7 @@
         // check and update state
         synchronized (readLock) {
             if (readKilled)
-                throw new RuntimeException("Reading not allowed due to timeout");
+                throw new RuntimeException("Reading not allowed due to timeout or cancellation");
             if (reading)
                 throw new ReadPendingException();
             if (readShutdown) {
@@ -224,13 +241,13 @@
         // immediately complete with -1 if shutdown for read
         // immediately complete with 0 if no space remaining
         if (shutdown || !hasSpaceToRead) {
-            IoFuture<R,A> result;
+            CompletedFuture<V,A> result;
             if (isScatteringRead) {
                 Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
-                result = CompletedIoFuture.withResult(this, value, attachment);
+                result = CompletedFuture.withResult(this, value, attachment);
             } else {
                 int value = (shutdown) ? -1 : 0;
-                result = CompletedIoFuture.withResult(this, value, attachment);
+                result = CompletedFuture.withResult(this, value, attachment);
             }
             Invoker.invoke(handler, result, executor, false, true);
             return result;
@@ -240,11 +257,11 @@
     }
 
     @Override
-    public final <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                              long timeout,
-                                              TimeUnit unit,
-                                              A attachment,
-                                              CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> read(ByteBuffer dst,
+                                          long timeout,
+                                          TimeUnit unit,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
     {
         if (dst.isReadOnly())
             throw new IllegalArgumentException("Read-only buffer");
@@ -254,13 +271,13 @@
     }
 
     @Override
-    public final <A> IoFuture<Long,A> read(ByteBuffer[] dsts,
-                                           int offset,
-                                           int length,
-                                           long timeout,
-                                           TimeUnit unit,
-                                           A attachment,
-                                           CompletionHandler<Long,? super A> handler)
+    public final <A> Future<Long> read(ByteBuffer[] dsts,
+                                       int offset,
+                                       int length,
+                                       long timeout,
+                                       TimeUnit unit,
+                                       A attachment,
+                                       CompletionHandler<Long,? super A> handler)
     {
         if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
             throw new IndexOutOfBoundsException();
@@ -275,19 +292,19 @@
     /**
      * Invoked by write to initiate the I/O operation.
      */
-    abstract <R extends Number,A> IoFuture<R,A> writeImpl(ByteBuffer[] srcs,
-                                                          boolean isGatheringWrite,
-                                                          long timeout,
-                                                          TimeUnit unit,
-                                                          A attachment,
-                                                          CompletionHandler<R,? super A> handler);
+    abstract <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs,
+                                                      boolean isGatheringWrite,
+                                                      long timeout,
+                                                      TimeUnit unit,
+                                                      A attachment,
+                                                      CompletionHandler<V,? super A> handler);
 
-    private <R extends Number,A> IoFuture<R,A> write(ByteBuffer[] srcs,
-                                                     boolean isGatheringWrite,
-                                                     long timeout,
-                                                     TimeUnit unit,
-                                                     A attachment,
-                                                     CompletionHandler<R,? super A> handler)
+    private <V extends Number,A> Future<V> write(ByteBuffer[] srcs,
+                                                 boolean isGatheringWrite,
+                                                 long timeout,
+                                                 TimeUnit unit,
+                                                 A attachment,
+                                                 CompletionHandler<V,? super A> handler)
     {
         boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining();
 
@@ -300,7 +317,7 @@
             // check and update state
             synchronized (writeLock) {
                 if (writeKilled)
-                    throw new RuntimeException("Writing not allowed due to timeout");
+                    throw new RuntimeException("Writing not allowed due to timeout or cancellation");
                 if (writing)
                     throw new WritePendingException();
                 if (writeShutdown) {
@@ -317,7 +334,7 @@
 
         // channel is closed or shutdown for write
         if (closed) {
-            IoFuture<R,A> result = CompletedIoFuture
+            CompletedFuture<V,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
@@ -325,11 +342,11 @@
 
         // nothing to write so complete immediately
         if (!hasDataToWrite) {
-            IoFuture<R,A> result;
+            CompletedFuture<V,A> result;
             if (isGatheringWrite) {
-                result = CompletedIoFuture.withResult(this, 0L, attachment);
+                result = CompletedFuture.withResult(this, 0L, attachment);
             } else {
-                result = CompletedIoFuture.withResult(this, 0, attachment);
+                result = CompletedFuture.withResult(this, 0, attachment);
             }
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
@@ -339,11 +356,11 @@
     }
 
     @Override
-    public final <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                               long timeout,
-                                               TimeUnit unit,
-                                               A attachment,
-                                               CompletionHandler<Integer,? super A> handler)
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           long timeout,
+                                           TimeUnit unit,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
     {
         ByteBuffer[] bufs = new ByteBuffer[1];
         bufs[0] = src;
@@ -351,13 +368,13 @@
     }
 
     @Override
-    public final <A> IoFuture<Long,A> write(ByteBuffer[] srcs,
-                                            int offset,
-                                            int length,
-                                            long timeout,
-                                            TimeUnit unit,
-                                            A attachment,
-                                            CompletionHandler<Long,? super A> handler)
+    public final <A> Future<Long> write(ByteBuffer[] srcs,
+                                        int offset,
+                                        int length,
+                                        long timeout,
+                                        TimeUnit unit,
+                                        A attachment,
+                                        CompletionHandler<Long,? super A> handler)
     {
         if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
             throw new IndexOutOfBoundsException();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/Cancellable.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+/**
+ * Implemented by asynchronous channels that require notification when an I/O
+ * operation is cancelled.
+ */
+
+interface Cancellable {
+    /**
+     * Invoked to notify channel that cancel has been invoked while holding
+     * the Future's lock.
+     */
+    void onCancel(PendingFuture<?,?> task);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/CompletedFuture.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.AsynchronousChannel;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.io.IOException;
+
+/**
+ * An IoFuture representing the result of an I/O operation that has already
+ * completed.
+ */
+
+final class CompletedFuture<V,A>
+    extends AbstractFuture<V,A>
+{
+    private final V result;
+    private final Throwable exc;
+
+    private CompletedFuture(AsynchronousChannel channel,
+                            V result,
+                            Throwable exc,
+                            A attachment)
+    {
+        super(channel, attachment);
+        this.result = result;
+        this.exc = exc;
+    }
+
+    @SuppressWarnings("unchecked")
+    static <V,A> CompletedFuture<V,A> withResult(AsynchronousChannel channel,
+                                                 Object result,
+                                                 A attachment)
+    {
+        return new CompletedFuture(channel, result, null, attachment);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <V,A> CompletedFuture<V,A> withFailure(AsynchronousChannel channel,
+                                                    Throwable exc,
+                                                    A attachment)
+    {
+        // exception must be IOException or SecurityException
+        if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
+            exc = new IOException(exc);
+        return new CompletedFuture(channel, null, exc, attachment);
+    }
+
+    @Override
+    public V get() throws ExecutionException {
+        if (exc != null)
+            throw new ExecutionException(exc);
+        return result;
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit) throws ExecutionException {
+        if (unit == null)
+            throw new NullPointerException();
+        if (exc != null)
+            throw new ExecutionException(exc);
+        return result;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return false;
+    }
+
+    @Override
+    public boolean isDone() {
+        return true;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return false;
+    }
+
+    @Override
+    boolean isCompleted() {
+        return true;
+    }
+
+    @Override
+    Throwable exception() {
+        return exc;
+    }
+
+    @Override
+    V value() {
+        return result;
+    }
+}
--- a/src/share/classes/sun/nio/ch/CompletedIoFuture.java	Tue Jun 24 18:30:03 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.nio.ch;
-
-import java.nio.channels.AsynchronousChannel;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.ExecutionException;
-import java.io.IOException;
-
-/**
- * An IoFuture representing the result of an I/O operation that has already
- * completed.
- */
-
-final class CompletedIoFuture<R,A>
-    extends AbstractIoFuture<R,A>
-{
-    private final R result;
-    private final Throwable exc;
-
-    private CompletedIoFuture(AsynchronousChannel channel,
-                              R result,
-                              Throwable exc,
-                              A attachment)
-    {
-        super(channel, attachment);
-        this.result = result;
-        this.exc = exc;
-    }
-
-    @SuppressWarnings("unchecked")
-    static <R,A> CompletedIoFuture<R,A> withResult(AsynchronousChannel channel,
-                                                   Object result,
-                                                   A attachment)
-    {
-        return new CompletedIoFuture(channel, result, null, attachment);
-    }
-
-    @SuppressWarnings("unchecked")
-    static <R,A> CompletedIoFuture<R,A> withFailure(AsynchronousChannel channel,
-                                                    Throwable exc,
-                                                    A attachment)
-    {
-        // exception must be IOException or SecurityException
-        if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
-            exc = new IOException(exc);
-        return new CompletedIoFuture(channel, null, exc, attachment);
-    }
-
-    @Override
-    public R get() throws ExecutionException {
-        if (exc != null)
-            throw new ExecutionException(exc);
-        return result;
-    }
-
-    @Override
-    public R get(long timeout, TimeUnit unit) throws ExecutionException {
-        if (unit == null)
-            throw new NullPointerException();
-        if (exc != null)
-            throw new ExecutionException(exc);
-        return result;
-    }
-
-    @Override
-    public R getNow() throws IOException {
-        if (exc != null) {
-            if (exc instanceof IOException)
-                throw (IOException)exc;
-            if (exc instanceof SecurityException)
-                throw (SecurityException)exc;
-            throw new AssertionError("Should not get here");
-        }
-        return result;
-    }
-
-    @Override
-    public boolean isCancelled() {
-        return false;
-    }
-
-    @Override
-    public boolean isDone() {
-        return true;
-    }
-
-    @Override
-    public boolean cancel(boolean mayInterruptIfRunning) {
-        return false;
-    }
-}
--- a/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -223,7 +223,7 @@
         if (name == null)
             throw new NullPointerException();
         if (!options().contains(name))
-            throw new UnsupportedOperationException("Invalid option name");
+            throw new IllegalArgumentException("Invalid option name");
 
         synchronized (stateLock) {
             ensureOpen();
--- a/src/share/classes/sun/nio/ch/FileChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/FileChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -893,6 +893,7 @@
             synchronized (this) {
                 if (fileLockTable == null) {
                     if (isSharedFileLockTable()) {
+                        ensureOpen();
                         // FIXME - doesn't handle sync close
                         fileLockTable =
                             FileLockTable.newSharedFileLockTable(this, fd);
--- a/src/share/classes/sun/nio/ch/Invoker.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/Invoker.java	Tue Jun 24 20:05:07 2008 +0100
@@ -26,8 +26,7 @@
 package sun.nio.ch;
 
 import java.nio.channels.*;
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.*;
 
 /**
  * Defines static methods to invoke a completion handler with a given result.
@@ -84,18 +83,22 @@
 
 
     /**
-     * Invokes the completion handler with the given result.
+     * Invokes the completion handler with the given result if the operation
+     * has not been cancelled.
      */
     @SuppressWarnings("unchecked")
-    static <R,A> void invoke(CompletionHandler<R,? super A> handler,
-                             IoFuture<R,A> result)
+    static <V,A> void invoke(CompletionHandler<V,? super A> handler,
+                             AbstractFuture<V,A> result)
     {
-        if (handler != null) {
-            // don't invoke handler if cancelled
-            if (result instanceof PendingIoFuture &&
-                ((PendingIoFuture<R,A>)result).wasCancelInvoked()) return;
+        if (handler != null && !result.isCancelled()) {
+            //handler.completed(result, result.attachment());
 
-            handler.completed((IoFuture)result);
+            if (result.isCompleted()) {
+                handler.completed(result.value(), result.attachment());
+            } else {
+                handler.failed(result.exception(), result.attachment());
+            }
+
             // clear interrupt
             Thread.interrupted();
         }
@@ -114,8 +117,8 @@
      * The {@code allowToInvokeDirectly} flag indicates if the handler can be
      * invoked by the initiating thread.
      */
-    static <R,A> void invoke(final CompletionHandler<R,? super A> handler,
-                             final IoFuture<R,A> result,
+    static <V,A> void invoke(final CompletionHandler<V,? super A> handler,
+                             final AbstractFuture<V,A> result,
                              Executor executor,
                              final boolean isSpecial,
                              boolean allowToInvokeDirectly)
@@ -196,8 +199,7 @@
                 return;
             } catch (RejectedExecutionException x) {
                 // thread pool has been shutdown so fall-through and execute
-                // the task on this thread. The task will fail immediately
-                // with AsynchronousCloseException.
+                // the task on this thread.
             }
         }
         task.run();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/nio/ch/PendingFuture.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+/**
+ * A Future for a pending I/O operation. A PendingFuture allows for the
+ * attachment of an additional arbitrary context object and a timer task.
+ */
+
+final class PendingFuture<V,A>
+    extends AbstractFuture<V,A>
+{
+    private static final CancellationException CANCELLED =
+        new CancellationException();
+
+    private final CompletionHandler<V,? super A> handler;
+    private final CountDownLatch latch;
+
+    // true if result (or exception) is available
+    private volatile boolean haveResult;
+    private volatile V result;
+    private volatile Throwable exc;
+
+    // optional timer task that is cancelled when result becomes available
+    private Future<?> timeoutTask;
+
+    // optional context object
+    private volatile Object context;
+
+
+    PendingFuture(AsynchronousChannel channel,
+                  CompletionHandler<V,? super A> handler,
+                  A attachment,
+                  Object context)
+    {
+        super(channel, attachment);
+        this.handler = handler;
+        this.context = context;
+        latch = new CountDownLatch(1);
+    }
+
+    PendingFuture(AsynchronousChannel channel,
+                  CompletionHandler<V,? super A> handler,
+                  A attachment)
+    {
+        this(channel, handler, attachment, null);
+    }
+
+    CompletionHandler<V,? super A> handler() {
+        return handler;
+    }
+
+    void setContext(Object context) {
+        this.context = context;
+    }
+
+    Object getContext() {
+        return context;
+    }
+
+    void setTimeoutTask(Future<?> task) {
+        synchronized (this) {
+            if (haveResult) {
+                task.cancel(false);
+            } else {
+                this.timeoutTask = task;
+           }
+        }
+    }
+
+    /**
+     * Sets the result, or a no-op if the result or exception is already set.
+     */
+    void setResult(V res) {
+        synchronized (this) {
+            if (haveResult)
+                return;
+            result = res;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+        }
+        latch.countDown();
+    }
+
+    /**
+     * Sets the result, or a no-op if the result or exception is already set.
+     */
+    void setFailure(Throwable x) {
+        if (!(x instanceof IOException) && !(x instanceof SecurityException))
+            x = new IOException(x);
+        synchronized (this) {
+            if (haveResult)
+                return;
+            exc = x;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+        }
+        latch.countDown();
+    }
+
+    @Override
+    public V get() throws ExecutionException, InterruptedException {
+        if (!haveResult)
+            latch.await();
+        if (exc != null) {
+            if (exc == CANCELLED)
+                throw new CancellationException();
+            throw new ExecutionException(exc);
+        }
+        return result;
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit)
+        throws ExecutionException, InterruptedException, TimeoutException
+    {
+        if (!haveResult && !latch.await(timeout, unit))
+            throw new TimeoutException();
+        if (exc != null) {
+            if (exc == CANCELLED)
+                throw new CancellationException();
+            throw new ExecutionException(exc);
+        }
+        return result;
+    }
+
+    @Override
+    boolean isCompleted() {
+        return (haveResult && exc == null);
+    }
+
+    @Override
+    Throwable exception() {
+        return (exc != CANCELLED) ? exc : null;
+    }
+
+    @Override
+    V value() {
+        return result;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return (exc == CANCELLED);
+    }
+
+    @Override
+    public boolean isDone() {
+        return haveResult;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        synchronized (this) {
+            if (haveResult)
+                return false;    // already completed
+
+            // A shutdown of the channel group will close all channels and
+            // shutdown the executor. To ensure that the completion handler
+            // is executed we submit the task while holding the lock.
+            try {
+                Executor executor = null;
+                AsynchronousChannel ch = channel();
+                if (ch instanceof AsynchronousSocketChannelImpl)
+                    executor = ((AsynchronousSocketChannelImpl)ch).executor();
+                if (ch instanceof AsynchronousServerSocketChannelImpl)
+                    executor = ((AsynchronousServerSocketChannelImpl)ch).executor();
+                if (ch instanceof AsynchronousFileChannelImpl)
+                    executor = ((AsynchronousFileChannelImpl)ch).executor();
+                assert executor != null;
+
+                final Future<V> res = this;
+
+                executor.execute(new Runnable() {
+                    public void run() {
+                        while (!haveResult) {
+                            try {
+                                latch.await();
+                            } catch (InterruptedException ignore) { }
+                        }
+                        //handler().completed(res, attachment());
+                        handler().cancelled(attachment());
+                    }
+                });
+            } catch (RejectedExecutionException rej) {
+                // should not happen
+                throw new AssertionError(rej);
+            }
+
+            // notify channel
+            if (channel() instanceof Cancellable)
+                ((Cancellable)channel()).onCancel(this);
+
+            // set result and cancel timer
+            exc = CANCELLED;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+        }
+
+        // close channel if forceful cancel
+        if (mayInterruptIfRunning) {
+            try {
+                channel().close();
+            } catch (IOException ignore) { }
+        }
+
+        // release waiters (this also releases the invoker)
+        latch.countDown();
+        return true;
+    }
+}
--- a/src/share/classes/sun/nio/ch/PendingIoFuture.java	Tue Jun 24 18:30:03 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-/*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.nio.ch;
-
-import java.nio.channels.*;
-import java.util.concurrent.*;
-import java.io.IOException;
-
-/**
- * An IoFuture for a pending I/O operation. A PendingIoFuture allows for the
- * attachment of an additional arbitrary context object and a timer task.
- */
-
-final class PendingIoFuture<R,A>
-    extends AbstractIoFuture<R,A>
-{
-    private final CompletionHandler<R, ? super A> handler;
-    private final CountDownLatch latch;
-
-    // true if result (or exception) is available
-    private volatile boolean haveResult;
-    private volatile R result;
-    private volatile Throwable exc;
-    private volatile boolean closedByCancel;
-
-    // optional timer task that is cancelled when result becomes available
-    private Future<?> timeoutTask;
-
-    // optional context object
-    private volatile Object context;
-
-
-    PendingIoFuture(AsynchronousChannel channel,
-                    CompletionHandler<R, ? super A> handler,
-                    A attachment)
-    {
-        super(channel, attachment);
-        this.handler = handler;
-        latch = new CountDownLatch(1);
-    }
-
-    CompletionHandler<R,? super A> handler() {
-        return handler;
-    }
-
-    void setContext(Object context) {
-        this.context = context;
-    }
-
-    Object getContext() {
-        return context;
-    }
-
-    void setTimeoutTask(Future<?> task) {
-        synchronized (this) {
-            if (haveResult) {
-                task.cancel(false);
-            } else {
-                this.timeoutTask = task;
-           }
-        }
-    }
-
-    /**
-     * Sets the result, or a no-op if the result or exception is already set.
-     */
-    void setResult(R res) {
-        synchronized (this) {
-            if (haveResult)
-                return;
-            result = res;
-            haveResult = true;
-            if (timeoutTask != null)
-                timeoutTask.cancel(false);
-        }
-        latch.countDown();
-    }
-
-    /**
-     * Sets the result, or a no-op if the result or exception is already set.
-     */
-    void setFailure(Throwable x) {
-        if (!(x instanceof IOException) && !(x instanceof SecurityException))
-            x = new IOException(x);
-        synchronized (this) {
-            if (haveResult)
-                return;
-            exc = x;
-            haveResult = true;
-            if (timeoutTask != null)
-                timeoutTask.cancel(false);
-        }
-        latch.countDown();
-    }
-
-    @Override
-    public R get() throws ExecutionException, InterruptedException {
-        latch.await();
-        if (exc != null) {
-            if (exc instanceof CancellationException)
-                throw new CancellationException();
-            throw new ExecutionException(exc);
-        }
-        return result;
-    }
-
-    @Override
-    public R get(long timeout, TimeUnit unit)
-        throws ExecutionException, InterruptedException, TimeoutException
-    {
-        if (!latch.await(timeout, unit))
-            throw new TimeoutException();
-        if (exc != null) {
-            if (exc instanceof CancellationException)
-                throw new CancellationException();
-            throw new ExecutionException(exc);
-        }
-        return result;
-    }
-
-    @Override
-    public R getNow() throws IOException {
-        if (!isDone())
-            throw new IllegalStateException("I/O operation has not completed");
-        if (exc != null) {
-            if (exc instanceof CancellationException)
-                throw new CancellationException();
-            if (exc instanceof IOException)
-                throw (IOException)exc;
-            if (exc instanceof SecurityException)
-                throw (SecurityException)exc;
-            throw new AssertionError("Should not get here");
-        }
-        return result;
-    }
-
-    @Override
-    public boolean isCancelled() {
-        return closedByCancel;
-    }
-
-    // package-private
-    boolean wasCancelInvoked() {
-        return (exc instanceof CancellationException);
-    }
-
-    @Override
-    public boolean isDone() {
-        return haveResult;
-    }
-
-    @Override
-    public boolean cancel(boolean mayInterruptIfRunning) {
-        // set result to CancellationException if result not already set
-        synchronized (this) {
-            if (haveResult)
-                return false;
-            exc = new CancellationException();
-            if (mayInterruptIfRunning)
-                closedByCancel = true;
-            haveResult = true;
-            if (timeoutTask != null)
-                timeoutTask.cancel(false);
-        }
-
-        // cancel operation by closing channel.
-        if (mayInterruptIfRunning) {
-            try {
-                channel().close();
-            } catch (IOException ignore) {
-            }
-        }
-
-        // release waiters after channel is closed
-        latch.countDown();
-
-        return closedByCancel;
-    }
-}
--- a/src/share/classes/sun/nio/ch/PortableAsynchronousFileChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/PortableAsynchronousFileChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -53,7 +53,6 @@
     private final FileChannelImpl fci;
     private final boolean reading;
     private final boolean writing;
-    private final ExecutorService executor;
 
     private static ExecutorService defaultExecutor() {
         if (defaultExecutor == null) {
@@ -75,10 +74,10 @@
                                                 boolean writing,
                                                 ExecutorService executor)
     {
+        super(executor);
         this.fci = fci;
         this.reading = reading;
         this.writing = writing;
-        this.executor = executor;
     }
 
     public static AsynchronousFileChannel wrap(FileChannel fc,
@@ -111,10 +110,10 @@
             fci.close();
         } finally {
             // if channel has its own thread pool then shut it down.
-            if (executor != defaultExecutor) {
+            if (executor() != defaultExecutor) {
                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
                     public Void run() {
-                        executor.shutdown();
+                        executor().shutdown();
                         return null;
                     }
                 });
@@ -158,11 +157,11 @@
     }
 
     @Override
-    public <A> IoFuture<FileLock,A> lock(final long position,
-                                         final long size,
-                                         final boolean shared,
-                                         A attachment,
-                                         final CompletionHandler<FileLock,? super A> handler)
+    public <A> Future<FileLock> lock(final long position,
+                                     final long size,
+                                     final boolean shared,
+                                     A attachment,
+                                     final CompletionHandler<FileLock,? super A> handler)
     {
         // FIXME - check position and size?
 
@@ -171,16 +170,16 @@
         } catch (IOException x) {
             if (!(x instanceof ClosedChannelException))
                 throw new AssertionError(x);
-            IoFuture<FileLock,A> result = CompletedIoFuture
+            CompletedFuture<FileLock,A> result = CompletedFuture
                 .withFailure(this, x, attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
         final FileLockImpl fli = fci.checkAndAddFileLock(position, size, shared);
 
-        final PendingIoFuture<FileLock,A> result =
-            new PendingIoFuture<FileLock,A>(this, null, attachment);
+        final PendingFuture<FileLock,A> result =
+            new PendingFuture<FileLock,A>(this, null, attachment);
         final AsynchronousFileChannel ch = this;
 
         Runnable task = new Runnable() {
@@ -199,7 +198,7 @@
             }
         };
         try {
-            executor.execute(task);
+            executor().execute(task);
         } catch (RejectedExecutionException x) {
             task.run();
         }
@@ -222,10 +221,10 @@
     }
 
     @Override
-    public <A> IoFuture<Integer,A> read(final ByteBuffer dst,
-                                        final long position,
-                                        A attachment,
-                                        final CompletionHandler<Integer,? super A> handler)
+    public <A> Future<Integer> read(final ByteBuffer dst,
+                                    final long position,
+                                    A attachment,
+                                    final CompletionHandler<Integer,? super A> handler)
     {
         if (position < 0)
             throw new IllegalArgumentException("Negative position");
@@ -236,19 +235,19 @@
 
         // complete immediately if channel closed or no space remaining
         if (!isOpen() || (dst.remaining() == 0)) {
-            IoFuture<Integer,A> result;
+            CompletedFuture<Integer,A> result;
             if (isOpen()) {
-                result = CompletedIoFuture.withResult(this, 0, attachment);
+                result = CompletedFuture.withResult(this, 0, attachment);
             } else {
-                result = CompletedIoFuture.withFailure(this,
+                result = CompletedFuture.withFailure(this,
                     new ClosedChannelException(), attachment);
             }
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
-        final PendingIoFuture<Integer,A> result =
-            new PendingIoFuture<Integer,A>(this, null, attachment);
+        final PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, null, attachment);
 
         Runnable task = new Runnable() {
             public void run() {
@@ -266,7 +265,7 @@
             }
         };
         try {
-            executor.execute(task);
+            executor().execute(task);
         } catch (RejectedExecutionException x) {
             task.run();
         }
@@ -275,10 +274,10 @@
     }
 
     @Override
-    public <A> IoFuture<Integer,A> write(final ByteBuffer src,
-                                         final long position,
-                                         A attachment,
-                                         final CompletionHandler<Integer,? super A> handler)
+    public <A> Future<Integer> write(final ByteBuffer src,
+                                     final long position,
+                                     A attachment,
+                                     final CompletionHandler<Integer,? super A> handler)
     {
         if (position < 0)
             throw new IllegalArgumentException("Negative position");
@@ -287,19 +286,19 @@
 
         // complete immediately if channel is closed or no bytes remaining
         if (!isOpen() || (src.remaining() == 0)) {
-            IoFuture<Integer,A> result;
+            CompletedFuture<Integer,A> result;
             if (isOpen()) {
-                result = CompletedIoFuture.withResult(this, 0, attachment);
+                result = CompletedFuture.withResult(this, 0, attachment);
             } else {
-                result = CompletedIoFuture.withFailure(this,
+                result = CompletedFuture.withFailure(this,
                     new ClosedChannelException(), attachment);
             }
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
-        final PendingIoFuture<Integer,A> result =
-            new PendingIoFuture<Integer,A>(this, null, attachment);
+        final PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, null, attachment);
 
         Runnable task = new Runnable() {
             public void run() {
@@ -317,10 +316,9 @@
             }
         };
         try {
-            executor.execute(task);
+            executor().execute(task);
         } catch (RejectedExecutionException x) {
             task.run();
-            throw new AssertionError(x);
         }
 
         return result;
--- a/src/share/classes/sun/nio/ch/ThreadPool.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ThreadPool.java	Tue Jun 24 20:05:07 2008 +0100
@@ -38,10 +38,9 @@
 public final class ThreadPool {
     private static final String PROP_PREFIX = "java.nio.channels.DefaultThreadPool.";
 
-    private static final String HANDLER_POOL_SIZE = "handlerPoolSize";
-    private static final String MAXIMUM_POOL_SIZE = "maximumPoolSize";
+    private static final String INITIAL_SIZE = "initialSize";
     private static final String THREAD_FACTORY = "threadFactory";
-    private static final String PRESTART_ALL_HANDLER_THREAD = "prestartAllHandlerThreads";
+    private static final String MAX_POOL_SIZE = "maximumPoolSize";
 
     private static final ThreadFactory defaultThreadFactory = new ThreadFactory() {
          @Override
@@ -54,23 +53,27 @@
 
     private static volatile ThreadPool defaultThreadPool;
 
-    private final int handlerPoolSize;
+    private final ThreadFactory threadFactory;
+    private final int initialSize;
     private final int maximumPoolSize;
-    private final ThreadFactory threadFactory;
-    private final boolean prestartAllHandlerThreads;
 
     // created lazily to avoid creating Exeuctor for default group when not needed.
     private volatile ExecutorService executor;
 
-    private ThreadPool(int handlerPoolSize,
-                       int maximumPoolSize,
-                       ThreadFactory threadFactory,
-                       boolean prestartAllHandlerThreads)
+    private ThreadPool(ThreadFactory threadFactory,
+                       int initialSize,
+                       int maximumPoolSize)
     {
-        this.handlerPoolSize = handlerPoolSize;
+        this.threadFactory = threadFactory;
+        this.initialSize = initialSize;
         this.maximumPoolSize = maximumPoolSize;
-        this.threadFactory = threadFactory;
-        this.prestartAllHandlerThreads = prestartAllHandlerThreads;
+    }
+
+    private ThreadPool(ExecutorService executor, int initialSize) {
+        this.threadFactory = null;
+        this.initialSize = initialSize;
+        this.maximumPoolSize = -1;
+        this.executor = executor;
     }
 
     // return the default (system-wide) thread pool
@@ -78,7 +81,7 @@
         if (defaultThreadPool == null) {
             synchronized (ThreadPool.class) {
                 if (defaultThreadPool == null) {
-                    defaultThreadPool = createUsingDefaults();
+                    defaultThreadPool = create();
                 }
             }
         }
@@ -87,83 +90,55 @@
 
     // create thread pool based on default parameters
     static ThreadPool create() {
-        return createUsingDefaults();
-    }
+        int initialSize = getInitialSizeFromProperty();
+        if (initialSize < 0)
+            initialSize = Runtime.getRuntime().availableProcessors();
 
-    // based on given parameters (or defaults if parameters not specified)
-    public static ThreadPool create(Map<String,?> params) {
-        int handlerPoolSize = getParamValueAsInt(params, HANDLER_POOL_SIZE, -1);
-        int maximumPoolSize = getParamValueAsInt(params, MAXIMUM_POOL_SIZE, -1);
+        int maximumPoolSize = getMaximumPoolSizeFromProperty();
+        if (maximumPoolSize < 0)
+            maximumPoolSize = computeMaximumPoolSizeFromInitialSize(initialSize);
 
-        if (handlerPoolSize < 1 && handlerPoolSize != -1) {
-            throw new IllegalArgumentException(HANDLER_POOL_SIZE +
-                " must be 1 or greater");
-        }
-        if (maximumPoolSize < 2 && maximumPoolSize != -1) {
-            throw new IllegalArgumentException(MAXIMUM_POOL_SIZE +
-                " must be 2 or greater");
-        }
-        if (handlerPoolSize >= maximumPoolSize && maximumPoolSize != -1) {
-            throw new IllegalArgumentException(MAXIMUM_POOL_SIZE +
-                " must be larger than " + HANDLER_POOL_SIZE);
-        }
-
-        // default pool sizes if one or both is not specified
-        if (handlerPoolSize == -1) {
-            if (maximumPoolSize == -1) {
-                handlerPoolSize = getDefault().handlerPoolSize();
-                maximumPoolSize = getDefault().maximumPoolSize();
-            } else {
-                handlerPoolSize = maximumPoolSize / 2;
-            }
-        }
-        if (maximumPoolSize == -1) {
-            maximumPoolSize = handlerPoolSize * 2;
-        }
-
-        ThreadFactory threadFactory;
-        if (params.containsKey(THREAD_FACTORY)) {
-            Object value = params.get(THREAD_FACTORY);
-            if (value == null)
-                throw new NullPointerException("Value of " + THREAD_FACTORY + " is null");
-            if (!(value instanceof ThreadFactory)) {
-                throw new IllegalArgumentException("Value of " + THREAD_FACTORY +
-                    " not of type ThreadFactory");
-            }
-            threadFactory = (ThreadFactory)value;
-        } else {
+        ThreadFactory threadFactory = getThreadFactoryFromProperty();
+        if (threadFactory == null) {
             threadFactory = defaultThreadFactory;
         }
 
-        boolean prestartAllHandlerThreads = getParamValueAsBoolean(params,
-            PRESTART_ALL_HANDLER_THREAD, getDefault().prestartAllHandlerThreads());
-
-        return new ThreadPool(handlerPoolSize,
-                              maximumPoolSize,
-                              threadFactory,
-                              prestartAllHandlerThreads);
+        return new ThreadPool(threadFactory, initialSize, maximumPoolSize);
     }
 
-    int handlerPoolSize() {
-        return handlerPoolSize;
+    // create using user-supplied ExecutorService
+    public static ThreadPool create(ExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException("'executor' is null");
+        int initialSize = 0;
+        if (executor instanceof ThreadPoolExecutor) {
+            initialSize = ((ThreadPoolExecutor)executor).getMaximumPoolSize() / 2;
+        }
+        return new ThreadPool(executor, initialSize);
     }
 
-    int maximumPoolSize() {
-        return maximumPoolSize;
+    // create using parameters
+    static ThreadPool create(ThreadFactory factory, int initialSize) {
+        if (factory == null)
+            throw new NullPointerException("'factory' is null");
+        int maximumPoolSize = computeMaximumPoolSizeFromInitialSize(initialSize);
+        return new ThreadPool(factory, initialSize, maximumPoolSize);
     }
 
-    ThreadFactory threadFactory() {
-        return threadFactory;
+    int initialSize() {
+        return initialSize;
     }
 
-    boolean prestartAllHandlerThreads() {
-        return prestartAllHandlerThreads;
+    static ThreadFactory defaultThreadFactory() {
+        return defaultThreadFactory;
     }
 
     ExecutorService executor() {
         if (executor == null) {
             synchronized (this) {
                 if (executor == null) {
+                    assert maximumPoolSize > 0;
+                    assert threadFactory != null;
                     executor = Executors
                         .newFixedThreadPool(maximumPoolSize, threadFactory);
                 }
@@ -172,39 +147,21 @@
         return executor;
     }
 
-    private static ThreadPool createUsingDefaults() {
-        int handlerPoolSize = getHandlerPoolSizePropValue();
-        int maximumPoolSize = getMaximumPoolSizePropValue();
-        ThreadFactory threadFactory = getThreadFactoryPropValue();
-        boolean prestartAllHandlerThreads = getPrestartAllHandlerThreadsPropValue();
-        // adjust or use defaults
-        int nProcs = Runtime.getRuntime().availableProcessors();
-        if (maximumPoolSize == -1) {
-            if (handlerPoolSize == -1)
-                handlerPoolSize = nProcs;
-            maximumPoolSize = handlerPoolSize * 2;
-        }
-        if (handlerPoolSize == -1 || handlerPoolSize >= maximumPoolSize) {
-            handlerPoolSize = maximumPoolSize / 2;
-        }
-
-        if (threadFactory == null) {
-            threadFactory = defaultThreadFactory;
-        }
-
-        return new ThreadPool(handlerPoolSize,
-                              maximumPoolSize,
-                              threadFactory,
-                              prestartAllHandlerThreads);
+    private static int computeMaximumPoolSizeFromInitialSize(int initialSize) {
+        if (initialSize > 0)
+            return 2*initialSize;
+        int max = Runtime.getRuntime().availableProcessors();
+        return (max >= 2) ? max : 2;
     }
 
-    private static int getHandlerPoolSizePropValue() {
+    private static int getInitialSizeFromProperty() {
         String value = AccessController.doPrivileged(new
-            GetPropertyAction(PROP_PREFIX + HANDLER_POOL_SIZE));
+            GetPropertyAction(PROP_PREFIX + INITIAL_SIZE));
         if (value != null) {
             try {
                 int size = Integer.parseInt(value);
-                if (size >= 1)
+                // zero is valid value
+                if (size >= 0)
                     return size;
             } catch (NumberFormatException x) {
             }
@@ -212,13 +169,14 @@
         return -1;
     }
 
-    private static int getMaximumPoolSizePropValue() {
+    private static int getMaximumPoolSizeFromProperty() {
         String value = AccessController.doPrivileged(new
-            GetPropertyAction(PROP_PREFIX + MAXIMUM_POOL_SIZE));
+            GetPropertyAction(PROP_PREFIX + MAX_POOL_SIZE));
         if (value != null) {
             try {
                 int size = Integer.parseInt(value);
-                if (size >= 2)
+                // zero is not valid value
+                if (size > 0)
                     return size;
             } catch (NumberFormatException x) {
             }
@@ -226,7 +184,7 @@
         return -1;
     }
 
-    private static ThreadFactory getThreadFactoryPropValue() {
+    private static ThreadFactory getThreadFactoryFromProperty() {
         String prop = AccessController.doPrivileged(new
             GetPropertyAction(PROP_PREFIX + THREAD_FACTORY));
         if (prop != null) {
@@ -244,49 +202,4 @@
         }
         return null;
     }
-
-    private static boolean getPrestartAllHandlerThreadsPropValue() {
-        String value = AccessController.doPrivileged(new
-            GetPropertyAction(PROP_PREFIX + PRESTART_ALL_HANDLER_THREAD));
-        if (value != null) {
-            if (value.equals(""))
-                return true;
-            return Boolean.parseBoolean(value);
-        }
-        return false;
-    }
-
-    private static int getParamValueAsInt(Map<String,?> params,
-                                          String name,
-                                          int defaultValue)
-    {
-        if (!params.containsKey(name))
-            return defaultValue;
-        Object value = params.get(name);
-        if (value == null)
-            throw new NullPointerException("Value of " + name + " is null");
-        if (value instanceof Integer)
-            return (Integer)value;
-        if (value instanceof String)
-            return Integer.parseInt((String)value);
-        throw new IllegalArgumentException("Value of " + name +
-            " is not String or Integer");
-    }
-
-    private static boolean getParamValueAsBoolean(Map<String,?> params,
-                                                  String name,
-                                                  boolean defaultValue)
-    {
-        if (!params.containsKey(name))
-            return defaultValue;
-        Object value = params.get(name);
-        if (value == null)
-            throw new NullPointerException("Value of " + name + " is null");
-        if (value instanceof Boolean)
-            return (Boolean)value;
-        if (value instanceof String)
-            return Boolean.parseBoolean((String)value);
-        throw new IllegalArgumentException("Value of " + name + " is not String or Boolean");
-    }
-
 }
--- a/src/share/classes/sun/nio/ch/ThreadPoolManager.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/classes/sun/nio/ch/ThreadPoolManager.java	Tue Jun 24 20:05:07 2008 +0100
@@ -31,23 +31,7 @@
 import java.security.PrivilegedAction;
 
 /**
- * "Manages" a pool of worker threads that handle I/O events.
- *
- * A thread pool manager submits tasks that handle I/O events to an Executor.
- * The tasks are assumed to be looping/never-ending tasks that dequeue I/O
- * events, do any necessary I/O completion, and dispatch to the associated
- * completion handler. The tasks post status to the manager by invoking the
- * workerAvailable, workerUnavailble, and workerExit methods. The thread pool
- * manager is also notified of possible pending I/O events by channels invoking
- * the prepare method. This triggers the thread pool manager to submit a new
- * task when all running tasks are busy. All logic to keep track the status
- * of tasks is disabled once the maximum number of tasks is running.
- *
- * In addition to event handler tasks submitted to the Executor, the thread
- * manager may create one or more "hidden" threads that handle I/O events
- * but don't invoke completion handlers. These hidden threads are needed to
- * ensure that I/O operations complete in a timely manner when all normal
- * tasks are "busy" executing long running completion handlers.
+ * "Manages" a set of tasks that handle I/O events.
  */
 
 class ThreadPoolManager {
@@ -66,16 +50,8 @@
     // to completion handlers.
     private final int hiddenThreadCount;
 
-    // number of worker thread running (includes hidden threads)
-    private AtomicInteger workerCount = new AtomicInteger();
-
-    // true if all worker threads are running
-    private volatile boolean allRunning = false;
-
-    // number of worker threads available to handle I/O events. The value
-    // ceases to updated once all worker threads are running.
-    private AtomicInteger availableCount = new AtomicInteger();
-
+    // number of handler threads running (includes hidden threads)
+    private AtomicInteger handlerCount = new AtomicInteger();
 
     private ThreadPoolManager(ThreadPool pool,
                               HandlerFactory factory,
@@ -93,122 +69,67 @@
         return new ThreadPoolManager(pool, factory, hiddenThreads);
     }
 
-    static ThreadPoolManager create(ThreadPool pool, HandlerFactory factory) {
-        return create(pool, factory, 0);
-    }
-
-    void start(int minThreads) {
+    void start() {
         // start the hidden threads
-        if (hiddenThreadCount > 0) {
-            for (int i=0; i<hiddenThreadCount; i++ ) {
-                startHiddenThread();
-            }
-            workerCount.addAndGet(hiddenThreadCount);
+        for (int i=0; i<hiddenThreadCount; i++ ) {
+            startHiddenThread();
+            handlerCount.incrementAndGet();
         }
 
-        // pre-start all handler threads or the minimum number of threads
-        // requested by the caller.
-        int nThreads;
-        if (pool.prestartAllHandlerThreads()) {
-            nThreads = pool.handlerPoolSize();
-        } else {
-            nThreads = minThreads;
-        }
-        for (int i=0; i<nThreads; i++) {
-            addWorker();
+        // submits handler tasks to thread pool
+        try {
+            for (int i=0; i<pool.initialSize(); i++) {
+                submitHandlerTask();
+                handlerCount.incrementAndGet();
+            }
+        } catch (RejectedExecutionException  x) {
+            // nothing we can do
         }
     }
 
-    void start() {
-        start(0);
+    // starts hidden thread
+    private void startHiddenThread() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                Thread thr = new Thread(factory.create(true));
+                thr.setDaemon(true);
+                thr.start();
+                return null;
+            }
+         });
     }
 
-    private void startHiddenThread() {
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    Thread thr = new Thread(factory.create(false));
-                    thr.setDaemon(true);
-                    thr.start();
-                    return null;
-                }
-             });
-    }
-
-    // Add a new worker thread (no-op if the maximum number of workers is
-    // already running
-    private void addWorker() {
-        synchronized (this) {
-            if (!allRunning) {
-                try {
-                    pool.executor().execute(factory.create(true));
-                    int n = workerCount.incrementAndGet();
-                    if (n >= (pool.handlerPoolSize() + hiddenThreadCount)) {
-                        allRunning = true;
-                    }
-                } catch (RejectedExecutionException  x) {
-                    // nothing we can do
-                    return;
-                }
-            }
-        }
+    // submits task to thread pool
+    private void submitHandlerTask() {
+        pool.executor().execute(factory.create(false));
     }
 
     /**
-     * Invoked by a channel when an I/O event is expected.
+     * Returns the current number of handler threads (tasks + hidden threads)
      */
-    void prepare() {
-        if (!allRunning && (availableCount.get() == 0)) {
-            // no tasks available so add worker
-            addWorker();
-        }
+    int handlerCount() {
+        return handlerCount.get();
     }
 
     /**
-     * Returns the number of worker threads (including hidden threads)
+     * Invoked by tasks (and hidden threads) before the task completes.
      */
-    int workerCount() {
-        return workerCount.get();
-    }
-
-    /**
-     * Invoked by worker thread as it becomes unavailable to handle I/O events.
-     * This should not be invoked by hidden threads.
-     */
-    void workerAvailable() {
-        if (!allRunning) {
-            availableCount.incrementAndGet();
-        }
-    }
-
-    /**
-     * Invoked by worker thread as it becomes available again to handle I/O events
-     * This should not be invoked by hidden threads.
-     */
-    void workerUnavailable() {
-        if (!allRunning) {
-            availableCount.decrementAndGet();
-        }
-    }
-
-    /**
-     * Invoked by worker thread before it exits (including hidden threads).
-     */
-    int workerExit(boolean replaceMe, boolean isVisible) {
+    int handlerExit(boolean replaceMe, boolean isHidden) {
         if (replaceMe) {
             try {
-                if (isVisible) {
-                    // submit new task to replace this thread
-                    pool.executor().execute(factory.create(true));
-                } else {
+                if (isHidden) {
                     // replace hidden thread
                     startHiddenThread();
+                } else {
+                    // submit new task to replace this thread
+                    submitHandlerTask();
                 }
-                return workerCount.get();
+                return handlerCount.get();
             } catch (RejectedExecutionException x) {
-                // unable to replace worker
+                // unable to replace
             }
         }
-        return workerCount.decrementAndGet();
+        return handlerCount.decrementAndGet();
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/sample/nio/aio/EchoServer.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * -Redistribution of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ * -Redistribution in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
+ * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
+ * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
+ * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
+ * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
+ * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
+ * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed, licensed or intended
+ * for use in the design, construction, operation or maintenance of any
+ * nuclear facility.
+ */
+
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.net.InetSocketAddress;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class EchoServer {
+
+    // timeout for read and writes.
+    static final long READ_TIMEOUT_IN_SECONDS  = 30;
+    static final long WRITE_TIMEOUT_IN_SECONDS = 30;
+
+    // the connection count
+    static final AtomicInteger connectionCount = new AtomicInteger();
+
+    /**
+     * Encapsulates everything for a connection and is also the handler
+     * that is invoked when read/write operations complete.
+     */
+    static class Connection
+        implements CompletionHandler<Integer,Void>
+    {
+        private final AsynchronousSocketChannel channel;
+        private final ByteBuffer buf;
+
+        // true if reading; false if writing
+        private volatile boolean isReading;
+
+        private Connection(AsynchronousSocketChannel channel) {
+            this.channel = channel;
+            this.buf = ByteBuffer.allocateDirect(4096);
+            connectionCount.incrementAndGet();
+        }
+
+        static void handle(AsynchronousSocketChannel channel) {
+            new Connection(channel).startReading();
+        }
+
+        private void startReading() {
+            buf.rewind();
+            buf.limit(buf.capacity());
+            isReading = true;
+            channel.read(buf, READ_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS, null, this);
+        }
+
+        private void closeChannel() {
+            try {
+                channel.close();
+            } catch (IOException ignore) { }
+            connectionCount.decrementAndGet();
+        }
+
+        // invoked when a read or write completes
+        @Override
+        public void completed(Integer bytesTransferred, Void att) {
+            int n = bytesTransferred;
+            if (n < 0) {
+                // EOF
+                assert isReading;
+                closeChannel();
+                return;
+            }
+
+            // if read completed then flip buffer to write to client
+            if (isReading) {
+                buf.flip();
+                isReading = false;
+            }
+
+            // write any remaining bytes
+            if (!isReading && buf.hasRemaining()) {
+                channel.write(buf, WRITE_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS, null, this);
+            } else {
+                // nothing to write so switch back to reading
+                startReading();
+            }
+        }
+
+        // invoked if read or write fails
+        @Override
+        public void failed(Throwable exc, Void att) {
+            System.err.println(exc);
+            closeChannel();
+        }
+
+        @Override
+        public void cancelled(Void att) {
+            assert false;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        // single argument that is the port number
+        int port = Integer.parseInt(args[0]);
+
+        // create the listener
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(port));
+
+        // accept connections
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            @Override
+            public void completed(AsynchronousSocketChannel channel, Void att) {
+                // start accepting the next connection
+                listener.accept(null, this);
+
+                // handle the new connection
+                Connection.handle(channel);
+            }
+
+            @Override
+            public void failed(Throwable exc, Void att) {
+                System.err.println(exc);
+                System.exit(-1);
+            }
+
+            @Override
+            public void cancelled(Void att) {
+            }
+        });
+
+        // keep the main thread busy reporting the connection count
+        for (;;) {
+            Thread.sleep(2000);
+            System.out.println(connectionCount.get());
+        }
+    }
+}
--- a/src/share/sample/nio/multicast/Reader.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/share/sample/nio/multicast/Reader.java	Tue Jun 24 20:05:07 2008 +0100
@@ -62,8 +62,10 @@
         if (args.length == 0)
             usage();
 
-        // first parameter is the multicast address
+        // first parameter is the multicast address (interface required)
         MulticastAddress target = MulticastAddress.parse(args[0]);
+        if (target.interf() == null)
+            usage();
 
         // addition arguments are source addresses to include or exclude
         List<InetAddress> includeList = new ArrayList<InetAddress>();
@@ -131,6 +133,7 @@
                         buf.flip();
                         printDatagram(sa, buf);
                         buf.rewind();
+                        buf.limit(buf.capacity());
                     }
                 }
             }
--- a/src/solaris/classes/sun/nio/ch/EPollPort.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/EPollPort.java	Tue Jun 24 20:05:07 2008 +0100
@@ -83,7 +83,7 @@
     // address of the poll array passed to epoll_wait
     private final long address;
 
-    // increases worker threads on demand
+    // submits task to thread pool to handle I/O events
     private final ThreadPoolManager manager;
 
     // encapsulates an event for a channel
@@ -135,9 +135,7 @@
         this.queue = new ArrayBlockingQueue<Event>(MAX_EPOLL_EVENTS);
         this.queue.offer(NEED_TO_POLL);
 
-        // create the manager that starts handler threads on demand. We create
-        // one hidden thread that handles events but doesn't dispatch to
-        // completion handlers.
+        // create the manager that starts handler tasks
         this.manager = ThreadPoolManager.create(pool, this, 1);
     }
 
@@ -166,14 +164,12 @@
     }
 
     @Override
-    void shutdownWorkers() {
+    void shutdownHandlerTasks() {
         /*
-         * If no workers are running then just release resources; otherwise
+         * If no tasks are running then just release resources; otherwise
          * write to the one end of the socketpair to wakeup any polling threads.
-         * All channels are closed so there aren't any I/O operations that
-         * would cause new worker threads to be started.
          */
-        if (manager.workerCount() == 0) {
+        if (manager.handlerCount() == 0) {
             implClose();
         } else {
             try {
@@ -187,9 +183,6 @@
     // invoke by clients to register a file descriptor
     @Override
     void startPoll(int fd, int events) {
-        // notify manager that I/O event is expected
-        manager.prepare();
-
         // update events (or add to epoll on first usage)
         int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
         if (err == ENOENT)
@@ -200,8 +193,8 @@
 
     // invoked by thread pool manager to create handler tasks
     @Override
-    public Runnable create(boolean isVisible) {
-        return new EventHandlerTask(isVisible);
+    public Runnable create(boolean isHidden) {
+        return new EventHandlerTask(isHidden);
     }
 
     /*
@@ -209,15 +202,15 @@
      * onEvent handler.
      *
      * Events are retreived from epoll in batch and offered to a BlockingQueue
-     * where they are consumed by worker threads. A special "NEED_TO_POLL"
+     * where they are consumed by handler threads. A special "NEED_TO_POLL"
      * event is used to signal one consumer to re-poll when all events have
      * been consumed.
      */
     private class EventHandlerTask implements Runnable {
-        private final boolean isVisible;
+        private final boolean isHidden;
 
-        EventHandlerTask(boolean isVisible) {
-            this.isVisible = isVisible;
+        EventHandlerTask(boolean isHidden) {
+            this.isHidden = isHidden;
         }
 
         private Event poll() throws IOException {
@@ -227,7 +220,7 @@
                     /*
                      * 'n' events have been read. Here we map them to their
                      * corresponding channel in batch and queue n-1 so that
-                     * they can be handled by other worker threads. The last
+                     * they can be handled by other handler threads. The last
                      * event is handled by this thread (and so is not queued).
                      */
                     fdToChannelLock.readLock().lock();
@@ -268,11 +261,10 @@
 
         public void run() {
             boolean replaceMe = false;
+            final boolean allowToInvokeDirectly = !isHidden;
             Event ev;
             try {
                 for (;;) {
-                    // hidden threads are never available
-                    if (isVisible) manager.workerAvailable();
                     try {
                         ev = queue.take();
 
@@ -288,8 +280,6 @@
                         }
                     } catch (InterruptedException x) {
                         continue;
-                    } finally {
-                        if (isVisible) manager.workerUnavailable();
                     }
 
                     // shutdown detected
@@ -298,7 +288,7 @@
 
                     // process event
                     try {
-                        ev.channel().onEvent(ev.events(), isVisible);
+                        ev.channel().onEvent(ev.events(), allowToInvokeDirectly);
                     } catch (Error x) {
                         replaceMe = true; throw x;
                     } catch (RuntimeException x) {
@@ -306,8 +296,8 @@
                     }
                 }
             } finally {
-                // last worker to exit when shutdown releases resources
-                int remaining = manager.workerExit(replaceMe, isVisible);
+                // last handler to exit when shutdown releases resources
+                int remaining = manager.handlerExit(replaceMe, isHidden);
                 if (remaining == 0 && isShutdown()) {
                     implClose();
                 }
--- a/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,7 +27,8 @@
 
 import java.nio.channels.*;
 import java.nio.channels.spi.AsynchronousChannelProvider;
-import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.net.ProtocolFamily;
 import java.io.IOException;
 
@@ -51,10 +52,17 @@
     }
 
     @Override
-    public AsynchronousChannelGroup openAsynchronousChannelGroup(Map<String,?> params)
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor)
         throws IOException
     {
-        return new EPollPort(this, ThreadPool.create(params)).start();
+        return new EPollPort(this, ThreadPool.create(executor)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ThreadFactory factory, int initialSize)
+        throws IOException
+    {
+        return new EPollPort(this, ThreadPool.create(factory, initialSize)).start();
     }
 
     private Port toPort(AsynchronousChannelGroup group) throws IOException {
--- a/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,8 +27,9 @@
 
 import java.nio.channels.*;
 import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.net.ProtocolFamily;
-import java.util.Map;
 import java.io.IOException;
 
 public class SolarisAsynchronousChannelProvider
@@ -51,11 +52,19 @@
     public SolarisAsynchronousChannelProvider() {
     }
 
+
     @Override
-    public AsynchronousChannelGroup openAsynchronousChannelGroup(Map<String,?> params)
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor)
         throws IOException
     {
-        return new SolarisEventPort(this, ThreadPool.create(params)).start();
+        return new SolarisEventPort(this, ThreadPool.create(executor)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ThreadFactory factory, int initialSize)
+        throws IOException
+    {
+        return new SolarisEventPort(this, ThreadPool.create(factory, initialSize)).start();
     }
 
     private SolarisEventPort toEventPort(AsynchronousChannelGroup group)
--- a/src/solaris/classes/sun/nio/ch/SolarisEventPort.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/SolarisEventPort.java	Tue Jun 24 20:05:07 2008 +0100
@@ -69,7 +69,7 @@
     // true when port is closed
     private boolean closed;
 
-    // increases worker threads on demand
+    // submits task to thread pool to handle I/O events
     private final ThreadPoolManager manager;
 
     SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)
@@ -80,9 +80,7 @@
         // create event port
         this.port = portCreate();
 
-        // create the manager that starts handler threads on demand. We create
-        // one hidden thread that handles events but doesn't dispatch to
-        // completion handlers.
+        // create the manager that starts handler tasks
         this.manager = ThreadPoolManager.create(pool, this, 1);
     }
 
@@ -102,18 +100,16 @@
     }
 
     @Override
-    void shutdownWorkers() {
+    void shutdownHandlerTasks() {
        /*
-         * If no workers are running then just release resources; otherwise
-         * write to the one end of the socketpair to wakeup any polling threads.
-         * All channels are closed so there aren't any I/O operations that
-         * would cause new worker threads to be started.
+         * If no tasks are running then just release resources; otherwise
+         * write to the one end of the socketpair to wakeup any polling threads..
          */
-        int nThreads = manager.workerCount();
+        int nThreads = manager.handlerCount();
         if (nThreads == 0) {
             implClose();
         } else {
-            // send user event to each worker thread
+            // send user event to wakeup each thread
             while (nThreads-- > 0) {
                 try {
                     portSend(port, 0);
@@ -126,9 +122,6 @@
 
     @Override
     void startPoll(int fd, int events) {
-        // notify manager that I/O event is expected
-        manager.prepare();
-
         // (re-)associate file descriptor
         try {
             portAssociate(port, PORT_SOURCE_FD, fd, events);
@@ -139,8 +132,8 @@
 
     // invoked by thread pool manager to create handler tasks
     @Override
-    public Runnable create(boolean isVisible) {
-        return new EventHandlerTask(isVisible);
+    public Runnable create(boolean isHidden) {
+        return new EventHandlerTask(isHidden);
     }
 
     /*
@@ -148,26 +141,23 @@
      * channel's onEvent handler.
      */
     private class EventHandlerTask implements Runnable {
-        private final boolean isVisible;
+        private final boolean isHidden;
 
-        EventHandlerTask(boolean isVisible) {
-            this.isVisible = isVisible;
+        EventHandlerTask(boolean isHidden) {
+            this.isHidden = isHidden;
         }
 
         public void run() {
             boolean replaceMe = false;
+            final boolean allowToInvokeDirectly = !isHidden;
             long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
             try {
                 for (;;) {
-                    // hidden threads are never available
-                    if (isVisible) manager.workerAvailable();
                     try {
                         portGet(port, address);
                     } catch (IOException x) {
                         x.printStackTrace();
                         return;
-                    } finally {
-                         if (isVisible) manager.workerUnavailable();
                     }
 
                     // event source
@@ -198,7 +188,7 @@
                     // notify channel
                     if (ch != null) {
                         try {
-                            ch.onEvent(events, isVisible);
+                            ch.onEvent(events, allowToInvokeDirectly);
                         } catch (Error x) {
                             replaceMe = true; throw x;
                         } catch (RuntimeException x) {
@@ -209,16 +199,14 @@
             } finally {
                 // free per-thread resources
                 unsafe.freeMemory(address);
-                // last worker to exit when shutdown release resources
-                int remaining = manager.workerExit(replaceMe, isVisible);
+                // last task to exit when shutdown release resources
+                int remaining = manager.handlerExit(replaceMe, isHidden);
                 if (remaining == 0 && isShutdown())
                     implClose();
             }
         }
     }
 
-
-
     // -- Native methods --
 
     private static native void init();
--- a/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -41,18 +41,18 @@
  */
 
 class UnixAsynchronousServerSocketChannelImpl
-    extends AsynchronousServerSocketChannelImpl implements Port.PollableChannel
+    extends AsynchronousServerSocketChannelImpl
+    implements Port.PollableChannel
 {
     private final static NativeDispatcher nd = new SocketDispatcher();
 
-    private final Executor executor;
     private final Port port;
     private final int fdVal;
 
     UnixAsynchronousServerSocketChannelImpl(Port port)
         throws IOException
     {
-        super(port.provider());
+        super(port.provider(), port.executor());
 
         try {
             IOUtil.configureBlocking(fd, false);
@@ -60,7 +60,6 @@
             nd.close(fd);  // prevent leak
             throw x;
         }
-        this.executor = port.executor();
         this.port = port;
         this.fdVal = IOUtil.fdVal(fd);
 
@@ -77,7 +76,7 @@
         nd.close(fd);
 
         // if there is a pending accept then complete it
-        final PendingIoFuture<AsynchronousSocketChannel,Object> result =
+        final PendingFuture<AsynchronousSocketChannel,Object> result =
             grabPendingAccept();
         if (result != null) {
             // discard the stack trace as otherwise it may appear that implClose
@@ -87,7 +86,7 @@
             result.setFailure(x);
 
             // invoke by submitting task rather than directly
-            Invoker.invoke(result.handler(), result, executor, false, false);
+            Invoker.invoke(result.handler(), result, executor(), false, false);
         }
     }
 
@@ -98,9 +97,9 @@
     }
 
     // the pending result
-    private AtomicReference<PendingIoFuture<AsynchronousSocketChannel,Object>>
-        pendingAccept = new AtomicReference<PendingIoFuture<AsynchronousSocketChannel,Object>>();
-    private PendingIoFuture<AsynchronousSocketChannel,Object> grabPendingAccept() {
+    private AtomicReference<PendingFuture<AsynchronousSocketChannel,Object>>
+        pendingAccept = new AtomicReference<PendingFuture<AsynchronousSocketChannel,Object>>();
+    private PendingFuture<AsynchronousSocketChannel,Object> grabPendingAccept() {
         return pendingAccept.getAndSet(null);
     }
 
@@ -112,7 +111,7 @@
      */
     @Override
     public void onEvent(int events, boolean allowToInvokeDirectly) {
-        PendingIoFuture<AsynchronousSocketChannel,Object> result =
+        PendingFuture<AsynchronousSocketChannel,Object> result =
             grabPendingAccept();
         if (result == null) {
             // may have been grabbed by asynchronous close
@@ -127,7 +126,7 @@
             begin();
             int n = accept0(this.fd, newfd, isaa);
 
-            // spurious wakeup?
+            // spurious wakeup, is this possible?
             if (n == IOStatus.UNAVAILABLE) {
                 pendingAccept.set(result);
                 port.startPoll(fdVal, Port.POLLIN);
@@ -140,28 +139,37 @@
         } catch (IOException x) {
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
+            enableAccept();
             result.setFailure(x);
         } finally {
             end();
         }
 
         // Connection accepted so finish it when not holding locks.
+        AsynchronousSocketChannel child = null;
         if (accepted) {
             try {
-                result.setResult(finishAccept(newfd, isaa[0], acc));
-            } catch (IOException x) {
-                result.setFailure(x);
-            } catch (SecurityException x) {
+                child = finishAccept(newfd, isaa[0], acc);
+                enableAccept();
+                result.setResult(child);
+            } catch (Throwable x) {
+                enableAccept();
+                if (!(x instanceof IOException) && !(x instanceof SecurityException))
+                    x = new IOException(x);
                 result.setFailure(x);
             }
         }
 
-        // clear reference to access control context and re-enable accepting
-        acc = null;
-        enableAccept();
+        // if an async cancel has already cancelled the operation then
+        // close the new channel so as to free resources
+        if (child != null && result.isCancelled()) {
+            try {
+                child.close();
+            } catch (IOException ignore) { }
+        }
 
         // invoke as special to ensure it completes as soon as possible
-        Invoker.invoke(result.handler(), result, executor, true, allowToInvokeDirectly);
+        Invoker.invoke(result.handler(), result, executor(), true, allowToInvokeDirectly);
     }
 
     /**
@@ -212,25 +220,30 @@
 
     @Override
     @SuppressWarnings("unchecked")
-    public <A> IoFuture<AsynchronousSocketChannel,A> accept(A attachment,
+    public <A> Future<AsynchronousSocketChannel> accept(A attachment,
         final CompletionHandler<AsynchronousSocketChannel,? super A> handler)
     {
         // complete immediately if channel is closed
         if (!isOpen()) {
-            IoFuture<AsynchronousSocketChannel,A> result = CompletedIoFuture
+            CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
         if (getLocalAddress() == null)
             throw new NotYetBoundException();
 
+        // cancel was invoked with pending accept so connection may have been
+        // dropped.
+        if (isAcceptKilled())
+            throw new RuntimeException("Accept not allowed due cancellation");
+
         // check and set flag to prevent concurrent accepting
         if (!accepting.compareAndSet(false, true))
             throw new AcceptPendingException();
 
         // attempt accept
-        IoFuture<AsynchronousSocketChannel,A> result = null;
+        AbstractFuture<AsynchronousSocketChannel,A> result = null;
         FileDescriptor newfd = new FileDescriptor();
         InetSocketAddress[] isaa = new InetSocketAddress[1];
         try {
@@ -239,14 +252,14 @@
             int n = accept0(this.fd, newfd, isaa);
             if (n == IOStatus.UNAVAILABLE) {
                 // no connection to accept
-                result = new PendingIoFuture(this, handler, attachment);
+                result = new PendingFuture(this, handler, attachment);
 
                 // need calling context when there is security manager as
                 // permission check may be done in a different thread without
                 // any application call frames on the stack
                 this.acc = (System.getSecurityManager() == null) ?
                     null : AccessController.getContext();
-                this.pendingAccept.set((PendingIoFuture)result);
+                this.pendingAccept.set((PendingFuture)result);
 
                 // register for connections
                 port.startPoll(fdVal, Port.POLLIN);
@@ -256,7 +269,7 @@
             // accept failed
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
-            result = CompletedIoFuture.withFailure(this, x, attachment);
+            result = CompletedFuture.withFailure(this, x, attachment);
         } finally {
             end();
         }
@@ -265,17 +278,17 @@
         if (result == null) {
             try {
                 AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null);
-                result = CompletedIoFuture.withResult(this, ch, attachment);
+                result = CompletedFuture.withResult(this, ch, attachment);
             } catch (IOException x) {
-                result = CompletedIoFuture.withFailure(this, x, attachment);
+                result = CompletedFuture.withFailure(this, x, attachment);
             } catch (SecurityException x) {
-                result = CompletedIoFuture.withFailure(this, x, attachment);
+                result = CompletedFuture.withFailure(this, x, attachment);
             }
         }
 
         // re-enale accepting and invoke handler
         enableAccept();
-        Invoker.invoke(handler, result, executor, true, true);
+        Invoker.invoke(handler, result, executor(), true, true);
         return result;
     }
 
--- a/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -42,6 +42,7 @@
     extends AsynchronousSocketChannelImpl implements Port.PollableChannel
 {
     private final static NativeDispatcher nd = new SocketDispatcher();
+    private static enum OpType { CONNECT, READ, WRITE };
 
     private final Port port;
     private final int fdVal;
@@ -92,9 +93,9 @@
     private final Object updateLock = new Object();
 
     // pending results for each operation type.
-    private PendingIoFuture<Void,Object> pendingConnect;
-    private PendingIoFuture<Number,Object> pendingRead;
-    private PendingIoFuture<Number,Object> pendingWrite;
+    private PendingFuture<Void,Object> pendingConnect;
+    private PendingFuture<Number,Object> pendingRead;
+    private PendingFuture<Number,Object> pendingWrite;
 
     private void updateEvents() {
         synchronized (updateLock) {
@@ -120,9 +121,9 @@
             writable = true;
         }
 
-        PendingIoFuture<Void,Object> connectResult = null;
-        PendingIoFuture<Number,Object> readResult = null;
-        PendingIoFuture<Number,Object> writeResult = null;
+        PendingFuture<Void,Object> connectResult = null;
+        PendingFuture<Number,Object> readResult = null;
+        PendingFuture<Number,Object> writeResult = null;
 
         // map event to pending result
         synchronized (updateLock) {
@@ -161,7 +162,7 @@
     }
 
     // invoked by connect when connection could not be established immediately
-    void setPendingConnect(PendingIoFuture<Void,Object> result)
+    void setPendingConnect(PendingFuture<Void,Object> result)
         throws IOException
     {
         synchronized (updateLock) {
@@ -171,7 +172,7 @@
     }
 
     // invoked by read when there is no data to read
-    void setPendingRead(PendingIoFuture<Number,Object> result)
+    void setPendingRead(PendingFuture<Number,Object> result)
         throws IOException
     {
         synchronized (updateLock) {
@@ -182,7 +183,7 @@
 
     // invoked by write when socket buffer is full and write cannot complete
     // immediately
-    void setPendingWrite(PendingIoFuture<Number,Object> result)
+    void setPendingWrite(PendingFuture<Number,Object> result)
         throws IOException
     {
         synchronized (updateLock) {
@@ -192,18 +193,18 @@
     }
 
     // returns and clears the result of a pending read
-    PendingIoFuture<Number,Object> grabPendingRead() {
+    PendingFuture<Number,Object> grabPendingRead() {
         synchronized (updateLock) {
-            PendingIoFuture<Number,Object> result = pendingRead;
+            PendingFuture<Number,Object> result = pendingRead;
             pendingRead = null;
             return result;
         }
     }
 
     // returns and clears the result of a pending write
-    PendingIoFuture<Number,Object> grabPendingWrite() {
+    PendingFuture<Number,Object> grabPendingWrite() {
         synchronized (updateLock) {
-            PendingIoFuture<Number,Object> result = pendingWrite;
+            PendingFuture<Number,Object> result = pendingWrite;
             pendingWrite = null;
             return result;
         }
@@ -218,9 +219,9 @@
         nd.close(fd);
 
         // All outstanding I/O operations are required to fail
-        final PendingIoFuture<Void,Object> readyToConnect;
-        final PendingIoFuture<Number,Object> readyToRead;
-        final PendingIoFuture<Number,Object> readyToWrite;
+        final PendingFuture<Void,Object> readyToConnect;
+        final PendingFuture<Number,Object> readyToRead;
+        final PendingFuture<Number,Object> readyToWrite;
         synchronized (updateLock) {
             readyToConnect = pendingConnect;
             pendingConnect = null;
@@ -252,6 +253,16 @@
         }
     }
 
+    @Override
+    public void onCancel(PendingFuture<?,?> task) {
+        if (task.getContext() == OpType.CONNECT)
+            killConnect();
+        if (task.getContext() == OpType.READ)
+            killConnect();
+        if (task.getContext() == OpType.WRITE)
+            killConnect();
+    }
+
     // -- connect --
 
     // need stateLock to access
@@ -265,7 +276,7 @@
         }
     }
 
-    private void finishConnect(PendingIoFuture<Void,Object> result,
+    private void finishConnect(PendingFuture<Void,Object> result,
                                boolean allowToInvokeDirectly)
     {
         IOException ioe = null;
@@ -294,12 +305,12 @@
 
     @Override
     @SuppressWarnings("unchecked")
-    public <A> IoFuture<Void,A> connect(SocketAddress remote,
-                                        A attachment,
-                                        CompletionHandler<Void,? super A> handler)
+    public <A> Future<Void> connect(SocketAddress remote,
+                                    A attachment,
+                                    CompletionHandler<Void,? super A> handler)
     {
         if (!isOpen()) {
-            IoFuture<Void,A> result = CompletedIoFuture
+            CompletedFuture<Void,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
@@ -322,19 +333,19 @@
             pendingRemote = remote;
         }
 
-        IoFuture<Void,A> result = null;
+        AbstractFuture<Void,A> result = null;
         IOException ioe = null;
         try {
             begin();
             int n = Net.connect(fd, isa.getAddress(), isa.getPort());
             if (n == IOStatus.UNAVAILABLE) {
                 // connection could not be established immediately
-                result = new PendingIoFuture<Void,A>(this, handler, attachment);
-                setPendingConnect((PendingIoFuture)result);
+                result = new PendingFuture<Void,A>(this, handler, attachment, OpType.CONNECT);
+                setPendingConnect((PendingFuture)result);
                 return result;
             }
             setConnected();
-            result = CompletedIoFuture.withResult(this, null, attachment);
+            result = CompletedFuture.withResult(this, null, attachment);
         } catch (IOException x) {
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
@@ -348,7 +359,7 @@
             try {
                 close();
             } catch (IOException ignore) { }
-            result = CompletedIoFuture.withFailure(this, ioe, attachment);
+            result = CompletedFuture.withFailure(this, ioe, attachment);
         }
 
         Invoker.invoke(handler, result, executor(), false, true);
@@ -363,7 +374,7 @@
     private volatile boolean scatteringRead;
 
     @SuppressWarnings("unchecked")
-    private void finishRead(PendingIoFuture<Number,Object> result,
+    private void finishRead(PendingFuture<Number,Object> result,
                             boolean allowToInvokeDirectly)
     {
         int n = -1;
@@ -377,7 +388,7 @@
                 n = (int)IOUtil.read(fd, dsts, nd);
             }
             if (n == IOStatus.UNAVAILABLE) {
-                // spurious wakeup?
+                // spurious wakeup, is this possible?
                 setPendingRead(result);
                 return;
             }
@@ -411,7 +422,7 @@
 
     private Runnable readTimeoutTask = new Runnable() {
         public void run() {
-            PendingIoFuture<Number,Object> result = grabPendingRead();
+            PendingFuture<Number,Object> result = grabPendingRead();
             if (result == null)
                 return;     // already completed
 
@@ -429,14 +440,14 @@
      */
     @Override
     @SuppressWarnings("unchecked")
-    <R extends Number,A> IoFuture<R,A> readImpl(ByteBuffer[] dsts,
-                                                boolean isScatteringRead,
-                                                long timeout,
-                                                TimeUnit unit,
-                                                A attachment,
-                                                CompletionHandler<R,? super A> handler)
+    <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts,
+                                            boolean isScatteringRead,
+                                            long timeout,
+                                            TimeUnit unit,
+                                            A attachment,
+                                            CompletionHandler<V,? super A> handler)
     {
-        IoFuture<R,A> result;
+        AbstractFuture<V,A> result;
         try {
             begin();
 
@@ -460,14 +471,14 @@
             if (n == IOStatus.UNAVAILABLE) {
                 this.readBuffers = dsts;
                 this.scatteringRead = isScatteringRead;
-                result = new PendingIoFuture<R,A>(this, handler, attachment);
-                setPendingRead((PendingIoFuture)result);
+                result = new PendingFuture<V,A>(this, handler, attachment, OpType.READ);
+                setPendingRead((PendingFuture)result);
 
                 // schedule timeout
                 if (timeout > 0L) {
                     Future<?> timeoutTask =
                         port.schedule(readTimeoutTask, timeout, unit);
-                    ((PendingIoFuture)result).setTimeoutTask(timeoutTask);
+                    ((PendingFuture)result).setTimeoutTask(timeoutTask);
                 }
                 return result;
             }
@@ -477,17 +488,17 @@
 
             // result type is Long or Integer
             if (isScatteringRead) {
-                result = CompletedIoFuture
+                result = CompletedFuture
                     .withResult(this, Long.valueOf(n), attachment);
             } else {
-                result = CompletedIoFuture
+                result = CompletedFuture
                     .withResult(this, Integer.valueOf(n), attachment);
             }
         } catch (IOException x) {
             enableReading();
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
-            result = CompletedIoFuture.withFailure(this, x, attachment);
+            result = CompletedFuture.withFailure(this, x, attachment);
         } finally {
             end();
         }
@@ -501,7 +512,7 @@
     private volatile ByteBuffer[] writeBuffers;
     private volatile boolean gatheringWrite;
 
-    private void finishWrite(PendingIoFuture<Number,Object> result,
+    private void finishWrite(PendingFuture<Number,Object> result,
                              boolean allowToInvokeDirectly)
     {
         try {
@@ -515,7 +526,7 @@
                 n = (int)IOUtil.write(fd, srcs, nd);
             }
             if (n == IOStatus.UNAVAILABLE) {
-                // spurious wakeup?
+                // spurious wakeup, is this possible?
                 setPendingWrite(result);
                 return;
             }
@@ -549,7 +560,7 @@
 
     private Runnable writeTimeoutTask = new Runnable() {
         public void run() {
-            PendingIoFuture<Number,Object> result = grabPendingWrite();
+            PendingFuture<Number,Object> result = grabPendingWrite();
             if (result == null)
                 return;     // already completed
 
@@ -568,14 +579,14 @@
      */
     @Override
     @SuppressWarnings("unchecked")
-    <R extends Number,A> IoFuture<R,A> writeImpl(ByteBuffer[] srcs,
-                                                 boolean isGatheringWrite,
-                                                 long timeout,
-                                                 TimeUnit unit,
-                                                 A attachment,
-                                                 CompletionHandler<R,? super A> handler)
+    <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs,
+                                             boolean isGatheringWrite,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<V,? super A> handler)
     {
-        IoFuture<R,A> result;
+        AbstractFuture<V,A> result;
         try {
             begin();
 
@@ -597,31 +608,31 @@
             if (n == IOStatus.UNAVAILABLE) {
                 this.writeBuffers = srcs;
                 this.gatheringWrite = isGatheringWrite;
-                result = new PendingIoFuture<R,A>(this, handler, attachment);
-                setPendingWrite((PendingIoFuture)result);
+                result = new PendingFuture<V,A>(this, handler, attachment, OpType.WRITE);
+                setPendingWrite((PendingFuture)result);
 
                 // schedule timeout
                 if (timeout > 0L) {
                     Future<?> timeoutTask =
                         port.schedule(writeTimeoutTask, timeout, unit);
-                    ((PendingIoFuture)result).setTimeoutTask(timeoutTask);
+                    ((PendingFuture)result).setTimeoutTask(timeoutTask);
                 }
                 return result;
             }
             // data available
             enableWriting();
             if (isGatheringWrite) {
-                result = CompletedIoFuture
+                result = CompletedFuture
                     .withResult(this, Long.valueOf(n), attachment);
             } else {
-                result = CompletedIoFuture
+                result = CompletedFuture
                     .withResult(this, Integer.valueOf(n), attachment);
             }
         } catch (IOException x) {
             enableWriting();
             if (x instanceof ClosedChannelException)
                 x = new AsynchronousCloseException();
-            result = CompletedIoFuture.withFailure(this, x, attachment);
+            result = CompletedFuture.withFailure(this, x, attachment);
         } finally {
             end();
         }
--- a/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java	Tue Jun 24 20:05:07 2008 +0100
@@ -105,7 +105,7 @@
     }
 
     @Override
-    void copyExtendedAttributes(int ofd, int nfd) {
+    void copyNonPosixAttributes(int ofd, int nfd) {
         LinuxNamedAttributeView.copyExtendedAttributes(ofd, nfd);
     }
 
--- a/src/solaris/classes/sun/nio/fs/LinuxNamedAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/LinuxNamedAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -45,6 +45,18 @@
 {
     private static final Unsafe unsafe = Unsafe.getUnsafe();
 
+    // maximum bytes in extended attribute name
+    private static final int XATTR_NAME_MAX = 255;
+
+    private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
+        byte[] bytes = name.getBytes();
+        if (bytes.length > XATTR_NAME_MAX) {
+            throw new FileSystemException(file.getPathForExecptionMessage(),
+                null, "'" + name + "' is too big");
+        }
+        return bytes;
+    }
+
     // Parses buffer as array of NULL-terminated C strings.
     private List<String> asList(long address, int size) {
         final List<String> list = new ArrayList<String>();
@@ -125,7 +137,7 @@
         int fd = file.openForAttributeAccess(info.followLinks());
         try {
             // fgetxattr returns size if called with size==0
-            return fgetxattr(fd, name.getBytes(), 0L, 0);
+            return fgetxattr(fd, nameAsBytes(file,name), 0L, 0);
         } catch (UnixException x) {
             throw new FileSystemException(file.getPathForExecptionMessage(),
                 null, "Unable to get size of named attribute '" + name +
@@ -142,9 +154,13 @@
         if (System.getSecurityManager() != null)
             checkAccess(file.getPathForPermissionCheck(), true, false);
 
-        int fd = file.openForAttributeAccess(info.followLinks());
-        int rem = dst.remaining();
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
         int pos = dst.position();
+        int lim = dst.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+
         NativeBuffer nb;
         long address;
         if (dst instanceof sun.nio.ch.DirectBuffer) {
@@ -155,24 +171,37 @@
             nb = NativeBuffers.getNativeBuffer(rem);
             address = nb.address();
         }
+
+        int fd = file.openForAttributeAccess(info.followLinks());
         try {
-            int n = fgetxattr(fd, name.getBytes(), address, rem);
-            if (nb != null) {
-                // copy from buffer into backing array
-                int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
-                unsafe.copyMemory(null, address, dst.array(), off, n);
+            try {
+                int n = fgetxattr(fd, nameAsBytes(file,name), address, rem);
+
+                // if remaining is zero then fgetxattr returns the size
+                if (rem == 0) {
+                    if (n > 0)
+                        throw new UnixException(ERANGE);
+                    return 0;
+                }
+
+                // copy from buffer into backing array if necessary
+                if (nb != null) {
+                    int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                    unsafe.copyMemory(null, address, dst.array(), off, n);
+                }
+                dst.position(pos + n);
+                return n;
+            } catch (UnixException x) {
+                String msg = (x.errno() == ERANGE) ?
+                    "Insufficient space in buffer" : x.getMessage();
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Error reading named attribute '" + name + "': " + msg);
+            } finally {
+                close(fd);
             }
-            dst.position(pos + n);
-            return n;
-        } catch (UnixException x) {
-            String msg = (x.errno() == ERANGE) ?
-                "Insufficient space in buffer" : x.getMessage();
-            throw new FileSystemException(file.getPathForExecptionMessage(),
-                null, "Error reading named attribute '" + name + "': " + msg);
         } finally {
             if (nb != null)
                 nb.release();
-            close(fd);
         }
     }
 
@@ -183,10 +212,11 @@
         if (System.getSecurityManager() != null)
             checkAccess(file.getPathForPermissionCheck(), false, true);
 
-        int fd = file.openForAttributeAccess(info.followLinks());
+        int pos = src.position();
+        int lim = src.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
 
-        int rem = src.remaining();
-        int pos = src.position();
         NativeBuffer nb;
         long address;
         if (src instanceof sun.nio.ch.DirectBuffer) {
@@ -197,22 +227,36 @@
             nb = NativeBuffers.getNativeBuffer(rem);
             address = nb.address();
 
-            // copy from backing array into buffer
-            int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
-            unsafe.copyMemory(src.array(), off, null, address, rem);
+            if (src.hasArray()) {
+                // copy from backing array into buffer
+                int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                unsafe.copyMemory(src.array(), off, null, address, rem);
+            } else {
+                // backing array not accessible so transfer via temporary array
+                byte[] tmp = new byte[rem];
+                src.get(tmp);
+                src.position(pos);  // reset position as write may fail
+                unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
+                    address, rem);
+            }
         }
+
+        int fd = file.openForAttributeAccess(info.followLinks());
         try {
-            fsetxattr(fd, name.getBytes(), address, rem);
-            src.position(pos + rem);
-            return rem;
-        } catch (UnixException x) {
-            throw new FileSystemException(file.getPathForExecptionMessage(),
-                null, "Error writing named attribute '" + name + "': " +
-                x.getMessage());
+            try {
+                fsetxattr(fd, nameAsBytes(file,name), address, rem);
+                src.position(pos + rem);
+                return rem;
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Error writing named attribute '" + name + "': " +
+                    x.getMessage());
+            } finally {
+                close(fd);
+            }
         } finally {
             if (nb != null)
                 nb.release();
-            close(fd);
         }
     }
 
@@ -224,7 +268,7 @@
 
         int fd = file.openForAttributeAccess(info.followLinks());
         try {
-            fremovexattr(fd, name.getBytes());
+            fremovexattr(fd, nameAsBytes(file,name));
         } catch (UnixException x) {
             throw new FileSystemException(file.getPathForExecptionMessage(),
                 null, "Unable to delete named attribute '" + name + "': " + x.getMessage());
--- a/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -324,6 +324,17 @@
         return acl;
     }
 
+    // Retrns true if NFSv4 ACLs not enabled on file system
+    private static boolean isAclsEnabled(int fd) {
+        try {
+            long enabled = fpathconf(fd, _PC_ACL_ENABLED);
+            if (enabled == _ACL_ACE_ENABLED)
+                return true;
+        } catch (UnixException x) {
+        }
+        return false;
+    }
+
     @Override
     public List<AclEntry> getAcl()
         throws IOException
@@ -344,9 +355,9 @@
                 assert n >= 0;
                 return decode(address, n);
             } catch (UnixException x) {
-                if (x.errno() == ENOSYS) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
                     throw new FileSystemException(file.getPathForExecptionMessage(),
-                        null, "File system does not support ACLs");
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
                 }
                 x.rethrowAsIOException(file);
                 return null;    // keep compiler happy
@@ -380,9 +391,9 @@
                 encode(acl, address);
                 facl(fd, ACE_SETACL, n, address);
             } catch (UnixException x) {
-                if (x.errno() == ENOSYS) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
                     throw new FileSystemException(file.getPathForExecptionMessage(),
-                        null, "File system does not support ACLs");
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
                 }
                 if (x.errno() == EINVAL && (n < 3))
                     throw new IOException("ACL must contain at least 3 entries");
--- a/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Tue Jun 24 20:05:07 2008 +0100
@@ -116,8 +116,9 @@
     }
 
     @Override
-    void copyExtendedAttributes(int ofd, int nfd) {
+    void copyNonPosixAttributes(int ofd, int nfd) {
         SolarisNamedAttributeView.copyExtendedAttributes(ofd, nfd);
+        // TDB: copy ACL from source to target
     }
 
     @Override
--- a/src/solaris/classes/sun/nio/fs/SolarisNamedAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisNamedAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -43,6 +43,20 @@
 class SolarisNamedAttributeView
     extends AbstractNamedAttributeView
 {
+    private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
+        byte[] result = name.getBytes();
+        //  "", "." and ".." not allowed
+        if (result.length == 0 || result[0] == '.') {
+            if (result.length <= 1 ||
+                (result.length == 2 && result[1] == '.'))
+            {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "'" + name + "' is not a valid name");
+            }
+        }
+        return result;
+    }
+
     @Override
     public NamedAttributeView bind(FileRef file, boolean followLinks) {
         if (file != null && !(file instanceof UnixPath))
@@ -110,13 +124,13 @@
         try {
             try {
                 // open attribute file
-                int afd = openat(fd, name.getBytes(), (O_RDONLY|O_XATTR), 0);
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
                 try {
                     // read attribute's attributes
                     UnixFileAttributes attrs = UnixFileAttributes.get(afd);
                     long size = attrs.size();
                     if (size > Integer.MAX_VALUE)
-                        throw new ArithmeticException("Attribute value too large");
+                        throw new ArithmeticException("Extended attribute value too large");
                     return (int)size;
                 } finally {
                     close(afd);
@@ -142,7 +156,7 @@
         try {
             try {
                 // open attribute file
-                int afd = openat(fd, name.getBytes(), (O_RDONLY|O_XATTR), 0);
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
 
                 // wrap with channel
                 FileChannel fc = UnixChannelFactory.newFileChannel(afd, true, false);
@@ -164,7 +178,7 @@
                 }
             } catch (UnixException x) {
                 throw new FileSystemException(file.getPathForExecptionMessage(),
-                    null, "Unable to get read extended attribute '" + name +
+                    null, "Unable to read extended attribute '" + name +
                     "': " + x.getMessage());
             }
         } finally {
@@ -183,7 +197,7 @@
         try {
             try {
                 // open/create attribute file
-                int afd = openat(fd, name.getBytes(),
+                int afd = openat(fd, nameAsBytes(file,name),
                                  (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
                                  UnixFileModeAttribute.ALL_PERMISSIONS);
 
@@ -202,7 +216,7 @@
                 }
             } catch (UnixException x) {
                 throw new FileSystemException(file.getPathForExecptionMessage(),
-                    null, "Unable to get write extended attribute '" + name +
+                    null, "Unable to write extended attribute '" + name +
                     "': " + x.getMessage());
             }
         } finally {
@@ -220,13 +234,14 @@
         try {
             int dfd = openat(fd, ".".getBytes(), (O_RDONLY|O_XATTR), 0);
             try {
-                unlinkat(dfd, name.getBytes(), 0);
+                unlinkat(dfd, nameAsBytes(file,name), 0);
             } finally {
                 close(dfd);
             }
         } catch (UnixException x) {
             throw new FileSystemException(file.getPathForExecptionMessage(),
-                null, "Unable to delete named attribute '" + name + "': " + x.getMessage());
+                null, "Unable to delete extended attribute '" + name +
+                "': " + x.getMessage());
         } finally {
             close(fd);
         }
--- a/src/solaris/classes/sun/nio/fs/UnixCopyFile.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixCopyFile.java	Tue Jun 24 20:05:07 2008 +0100
@@ -43,12 +43,15 @@
     private UnixCopyFile() {  }
 
     // copy directory from source to target
-    private static void copyDirectory(UnixFileAttributes attrs,
+    private static void copyDirectory(UnixPath source,
+                                      UnixFileAttributes attrs,
                                       UnixPath target,
                                       boolean copyBasicAttributes,
                                       boolean failIfUnableToCopyBasic,
                                       boolean copyPosixAttributes,
-                                      boolean failIfUnableToCopyPosix)
+                                      boolean failIfUnableToCopyPosix,
+                                      boolean copyNonPosixAttributes,
+                                      boolean failIfUnableToCopyNonPosix)
         throws IOException
     {
         byte[] path = target.getPathForSysCalls();
@@ -57,20 +60,66 @@
         } catch (UnixException x) {
             x.rethrowAsIOException(target);
         }
+
+        // no attributes to copy
+        if (!copyBasicAttributes && !copyPosixAttributes && !copyNonPosixAttributes)
+            return;
+
+        // open target directory if possible (this can fail when copying a
+        // directory for which we don't have read access).
+        int dfd = -1;
+        try {
+            dfd = open(path, O_RDONLY, 0);
+        } catch (UnixException x) {
+            // access to target directory required to copy named attributes
+            if (copyNonPosixAttributes && failIfUnableToCopyNonPosix) {
+                try { rmdir(path); } catch (UnixException ignore) { }
+                x.rethrowAsIOException(target);
+            }
+        }
+
         boolean done = false;
         try {
+            // copy owner/group/permissions
             if (copyPosixAttributes){
                 try {
-                    chown(path, attrs.uid(), attrs.gid());
+                    if (dfd >= 0) {
+                        fchown(dfd, attrs.uid(), attrs.gid());
+                        fchmod(dfd, attrs.mode());
+                    } else {
+                        chown(path, attrs.uid(), attrs.gid());
+                        chmod(path, attrs.mode());
+                    }
                 } catch (UnixException x) {
                     // unable to set owner/group
                     if (failIfUnableToCopyPosix)
                         x.rethrowAsIOException(target);
                 }
             }
+            // copy other attributes
+            if (copyNonPosixAttributes && (dfd >= 0)) {
+                int sfd = -1;
+                try {
+                    sfd = open(source.getPathForSysCalls(), O_RDONLY, 0);
+                } catch (UnixException x) {
+                    if (failIfUnableToCopyNonPosix)
+                        x.rethrowAsIOException(source);
+                }
+                if (sfd >= 0) {
+                    source.getFileSystem().copyNonPosixAttributes(sfd, dfd);
+                    close(sfd);
+                }
+            }
+            // copy time stamps last
             if (copyBasicAttributes) {
                 try {
-                    utimes(path, attrs.lastAccessTime(), attrs.lastModifiedTime());
+                    if (dfd >= 0) {
+                        futimes(dfd, attrs.lastAccessTime(),
+                            attrs.lastModifiedTime());
+                    } else {
+                        utimes(path, attrs.lastAccessTime(),
+                            attrs.lastModifiedTime());
+                    }
                 } catch (UnixException x) {
                     // unable to set times
                     if (failIfUnableToCopyBasic)
@@ -79,6 +128,8 @@
             }
             done = true;
         } finally {
+            if (dfd >= 0)
+                close(dfd);
             if (!done) {
                 // rollback
                 try { rmdir(path); } catch (UnixException ignore) { }
@@ -94,8 +145,8 @@
                                  boolean failIfUnableToCopyBasic,
                                  boolean copyPosixAttributes,
                                  boolean failIfUnableToCopyPosix,
-                                 boolean copyExtendedAttributes,
-                                 boolean failIfUnableToCopyEA)
+                                 boolean copyNonPosixAttributes,
+                                 boolean failIfUnableToCopyNonPosix)
         throws IOException
     {
         int fi = -1;
@@ -137,9 +188,9 @@
                             x.rethrowAsIOException(target);
                     }
                 }
-                // copy extended attributes (depends on file system)
-                if (copyExtendedAttributes) {
-                    source.getFileSystem().copyExtendedAttributes(fi, fo);
+                // copy non POSIX attributes (depends on file system)
+                if (copyNonPosixAttributes) {
+                    source.getFileSystem().copyNonPosixAttributes(fi, fo);
                 }
                 // copy time attributes
                 if (copyBasicAttributes) {
@@ -216,6 +267,7 @@
             if (copyPosixAttributes) {
                 try {
                     chown(path, attrs.uid(), attrs.gid());
+                    chmod(path, attrs.mode());
                 } catch (UnixException x) {
                     if (failIfUnableToCopyPosix)
                         x.rethrowAsIOException(target);
@@ -345,7 +397,10 @@
 
         // copy source to target
         if (sourceAttrs.isDirectory()) {
-            copyDirectory(sourceAttrs, target, true, true, true, false);
+            copyDirectory(source, sourceAttrs, target,
+                          true, true,     // copy basic attributes
+                          true, false,    // copy posix attributes
+                          true, false);   // copy non-posix attributes
         } else {
             if (sourceAttrs.isSymbolicLink()) {
                 copyLink(source, sourceAttrs, target, true);
@@ -353,8 +408,10 @@
                 if (sourceAttrs.isDevice()) {
                     copySpecial(source, sourceAttrs, target, true, true, true, false);
                 } else {
-                    copyFile(source, sourceAttrs, target, true, true,
-                        true, false, true, false);
+                    copyFile(source, sourceAttrs, target,
+                          true, true,     // copy basic attributes
+                          true, false,    // copy posix attributes
+                          true, false);   // copy non-posix attributes
                 }
             }
         }
@@ -487,8 +544,10 @@
 
         // do the copy
         if (sourceAttrs.isDirectory()) {
-            copyDirectory(sourceAttrs, target, copyBasicAttributes, failIfUnableToCopyBasic,
-                copyPosixAttributes, failIfUnableToCopyPosix);
+            copyDirectory(source, sourceAttrs, target,
+                copyBasicAttributes, failIfUnableToCopyBasic,
+                copyPosixAttributes, failIfUnableToCopyPosix,
+                copyNamedAttributes, failIfUnableToCopyNamed);
         } else {
             if (sourceAttrs.isSymbolicLink()) {
                 copyLink(source, sourceAttrs, target, copyPosixAttributes);
--- a/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Tue Jun 24 20:05:07 2008 +0100
@@ -106,14 +106,20 @@
     }
 
     /**
-     * Copies extended attributes from the source to target file.
+     * Copies non-POSIX attributes from the source to target file.
+     *
+     * Copying a file preserving attributes, or moving a file, will preserve
+     * the file owner/group/permissions/timestamps but it does not preserve
+     * other non-POSIX attributes. This method is invoked by the
+     * copy or move operation to preserve these attributes. It should copy
+     * extended attributes, ACLs, or other attributes.
      *
      * @param   sfd
      *          Open file descriptor to source file
      * @param   tfd
      *          Open file descriptor to target file
      */
-    abstract void copyExtendedAttributes(int sfd, int tfd);
+    abstract void copyNonPosixAttributes(int sfd, int tfd);
 
     /**
      * Tells if directory relative system calls (openat, etc.) are available
--- a/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,6 +30,7 @@
 import java.nio.file.spi.FileSystemProvider;
 import java.nio.channels.*;
 import java.net.URI;
+import java.util.concurrent.ExecutorService;
 import java.io.IOException;
 import java.util.*;
 
@@ -124,13 +125,13 @@
     @Override
     public final AsynchronousFileChannel newAsynchronousFileChannel(Path obj,
                                                                     Set<? extends OpenOption> options,
-                                                                    Map<String,?> params,
+                                                                    ExecutorService executor,
                                                                     Attribute<?>... attrs) throws IOException
     {
         UnixPath file = checkPath(obj);
         int mode = UnixFileModeAttribute
             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
-        ThreadPool pool = (params == null) ? null : ThreadPool.create(params);
+        ThreadPool pool = (executor == null) ? null : ThreadPool.create(executor);
         try {
             return UnixChannelFactory
                 .newAsynchronousFileChannel(file.getPathForSysCalls(),
--- a/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java	Tue Jun 24 20:05:07 2008 +0100
@@ -511,6 +511,11 @@
         throws UnixException;
 
     /**
+     * long fpathconf(int fildes, int name);
+     */
+    static native long fpathconf(int filedes, int name) throws UnixException;
+
+    /**
      * char* strerror(int errnum)
      */
     static native byte[] strerror(int errnum);
--- a/src/solaris/classes/sun/nio/fs/UnixPath.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixPath.java	Tue Jun 24 20:05:07 2008 +0100
@@ -595,8 +595,8 @@
                 x.setError(ELOOP);
 
             if (x.errno() == ELOOP)
-                throw new UnsupportedOperationException(x.getMessage() +
-                    " (not following links)");
+                throw new FileSystemException(getPathForExecptionMessage(), null,
+                    x.getMessage() + " or unable to access attributes of symbolic link");
 
             x.rethrowAsIOException(this);
             return -1; // keep compile happy
--- a/src/solaris/native/sun/nio/ch/Net.c	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/native/sun/nio/ch/Net.c	Tue Jun 24 20:05:07 2008 +0100
@@ -172,8 +172,24 @@
             JNU_ThrowByNameWithLastError(env,
                                          JNU_JAVANETPKG "SocketException",
                                          "sun.nio.ch.Net.setIntOption");
+            close(fd);
+            return -1;
         }
     }
+#ifdef __linux__
+    /* By default, Linux uses the route default */
+    if (domain == AF_INET6 && type == SOCK_DGRAM) {
+        int arg = 1;
+        if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &arg,
+                       sizeof(arg)) < 0) {
+            JNU_ThrowByNameWithLastError(env,
+                                         JNU_JAVANETPKG "SocketException",
+                                         "sun.nio.ch.Net.setIntOption");
+            close(fd);
+            return -1;
+        }
+    }
+#endif
     return fd;
 }
 
--- a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c	Tue Jun 24 20:05:07 2008 +0100
@@ -790,6 +790,19 @@
     return (jlong)err;
 }
 
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this,
+    jint fd, jint name)
+{
+    long err;
+
+    err = fpathconf((int)fd, (int)name);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jlong)err;
+}
+
 JNIEXPORT void JNICALL
 Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this,
     jlong pathAddress, jint mode, jlong dev)
--- a/src/solaris/native/sun/nio/fs/genSolarisConstants.c	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/solaris/native/sun/nio/fs/genSolarisConstants.c	Tue Jun 24 20:05:07 2008 +0100
@@ -58,9 +58,15 @@
     emitX("O_XATTR", 0x4000);
     emit("_PC_XATTR_ENABLED", 100);
 
-    // ACLs
+    // ACL configuration
+    emit("_PC_ACL_ENABLED", 20);
+    emitX("_ACL_ACE_ENABLED", 0x2);
+
+    // ACL commands
     emitX("ACE_GETACL",                         4);
     emitX("ACE_SETACL",                         5);
+
+    // ACL mask/flags/types
     emitX("ACE_ACCESS_ALLOWED_ACE_TYPE",        0x0000);
     emitX("ACE_ACCESS_DENIED_ACE_TYPE",         0x0001);
     emitX("ACE_SYSTEM_AUDIT_ACE_TYPE",          0x0002);
--- a/src/windows/classes/sun/nio/ch/Iocp.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/Iocp.java	Tue Jun 24 20:05:07 2008 +0100
@@ -50,7 +50,7 @@
         /**
          * Returns a reference to the pending I/O result.
          */
-        <R,A> PendingIoFuture<R,A> getByOverlapped(long overlapped);
+        <V,A> PendingFuture<V,A> getByOverlapped(long overlapped);
     }
 
     // maps completion key to channel
@@ -65,7 +65,7 @@
     // true if port has been closed
     private boolean closed;
 
-    // increases worker threads on demand
+    // submits task to thread pool to handle I/O events
     private final ThreadPoolManager manager;
 
 
@@ -74,17 +74,18 @@
     {
         super(provider, pool);
 
+        // maximum number of threads that the operating system can allow to
+        // concurrently process I/O completion events.
+        int hiddenThreadCount = 1;
+        int concurrentThreadCount = pool.initialSize() + hiddenThreadCount;
+
+        this.port = createIoCompletionPort(-1L, 0, 0, concurrentThreadCount);
+        this.manager = ThreadPoolManager.create(pool, this, hiddenThreadCount);
         this.nextCompletionKey = 1;
-        this.port = createIoCompletionPort(-1L, 0, 0, pool.handlerPoolSize());
-        this.manager = ThreadPoolManager.create(pool, this);
-
     }
 
     Iocp start() {
-        // When an I/O operation completes immediately it is handled by the
-        // initiating thread but there is also an event posted to the port. We
-        // need at least one worker running to process these.
-        manager.start(1);
+        manager.start();
         return this;
     }
 
@@ -149,9 +150,9 @@
     }
 
     @Override
-    void shutdownWorkers() {
-        // shutdown all worker threads
-        int nThreads = manager.workerCount();
+    void shutdownHandlerTasks() {
+        // shutdown all handler threads
+        int nThreads = manager.handlerCount();
         while (nThreads-- > 0) {
             try {
                 postQueuedCompletionStatus(port, 0);
@@ -222,12 +223,12 @@
         /**
          * Invoked if the I/O operation completes successfully.
          */
-        public void completed(int bytesTransferred);
+        public void completed(int bytesTransferred, boolean allowedToInvokeHandler);
 
         /**
          * Invoked if the I/O operation fails.
          */
-        public void failed(int error, IOException ioe);
+        public void failed(int error, IOException ioe, boolean allowedToInvokeHandler);
     }
 
     // Creates IOException for the given I/O error.
@@ -240,31 +241,33 @@
 
     // invoked by thread pool manager to create handler tasks
     @Override
-    public Runnable create(boolean isVisible) {
-        if (!isVisible)
-            throw new AssertionError("Should not get here");
-        return new EventHandlerTask();
+    public Runnable create(boolean isHidden) {
+        return new EventHandlerTask(isHidden);
     }
 
     /**
      * Long-running task servicing system-wide or per-file completion port
      */
     private class EventHandlerTask implements Runnable {
+        private final boolean isHidden;
+
+        EventHandlerTask(boolean isHidden) {
+            this.isHidden = isHidden;
+        }
+
         public void run() {
             boolean replaceMe = false;
+            final boolean allowToInvokeDirectly = !isHidden;
             CompletionStatus ioResult = new CompletionStatus();
             try {
                 for (;;) {
                     // wait for I/O completion
-                    manager.workerAvailable();
                     try {
                         getQueuedCompletionStatus(port, ioResult);
                     } catch (IOException x) {
                         // should not happen
                         x.printStackTrace();
                         return;
-                    } finally {
-                        manager.workerUnavailable();
                     }
 
                     // handle shutdown
@@ -287,7 +290,7 @@
                     }
 
                     // lookup I/O request
-                    PendingIoFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped());
+                    PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped());
                     if (result == null) {
                         // ignore (this can happen with tryLock as it doesn't
                         // put OVERLAPPED structures in the pending I/O cache)
@@ -307,9 +310,11 @@
                     ResultHandler rh = (ResultHandler)result.getContext();
                     try {
                         if (error == 0) {
-                            rh.completed(ioResult.bytesTransferred());
+                            rh.completed(ioResult.bytesTransferred(),
+                                allowToInvokeDirectly);
                         } else {
-                            rh.failed(error, translateErrorToIOException(error));
+                            rh.failed(error, translateErrorToIOException(error),
+                                allowToInvokeDirectly);
                         }
                     } catch (Error x) {
                         replaceMe = true; throw x;
@@ -318,8 +323,8 @@
                     }
                 }
             } finally {
-                // last worker to exit when shutdown release resources
-                int remaining = manager.workerExit(replaceMe, true);
+                // last handler to exit when shutdown release resources
+                int remaining = manager.handlerExit(replaceMe, isHidden);
                 if (remaining == 0 && isShutdown()) {
                     implClose();
                 }
--- a/src/windows/classes/sun/nio/ch/PendingIoCache.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/PendingIoCache.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,7 +30,7 @@
 
 /**
  * Maintains a mapping of pending I/O requests (identified by the address of
- * an OVERLAPPED structure) to IoFutures.
+ * an OVERLAPPED structure) to Futures.
  */
 
 class PendingIoCache {
@@ -58,9 +58,9 @@
     // set to true when close pending (waiting for all remaining I/O to finish)
     private boolean closePending;
 
-    // maps OVERLAPPED to PendingIoFuture
-    private final Map<Long,PendingIoFuture> pendingIoMap =
-        new HashMap<Long,PendingIoFuture>();
+    // maps OVERLAPPED to PendingFuture
+    private final Map<Long,PendingFuture> pendingIoMap =
+        new HashMap<Long,PendingFuture>();
 
     // per-channel cache of OVERLAPPED structures
     private long[] overlappedCache = new long[4];
@@ -69,7 +69,7 @@
     PendingIoCache() {
     }
 
-    long add(PendingIoFuture<?,?> result) {
+    long add(PendingFuture<?,?> result) {
         synchronized (pendingIoMap) {
             if (closed)
                 throw new AssertionError("Should not get here");
@@ -85,12 +85,12 @@
     }
 
     @SuppressWarnings("unchecked")
-    <R,A> PendingIoFuture<R,A> remove(long overlapped) {
+    <V,A> PendingFuture<V,A> remove(long overlapped) {
         synchronized (pendingIoMap) {
             if (closed) {
                 throw new AssertionError("Should not get here");
             }
-            PendingIoFuture<R,A> res = pendingIoMap.remove(overlapped);
+            PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
             if (res != null) {
                 if (overlappedCacheCount < overlappedCache.length) {
                     overlappedCache[overlappedCacheCount++] = overlapped;
@@ -104,7 +104,6 @@
             if (closePending) {
                 pendingIoMap.notifyAll();
             }
-
             return res;
         }
     }
--- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -27,6 +27,8 @@
 
 import java.nio.channels.*;
 import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
 import java.util.Map;
 import java.net.ProtocolFamily;
 import java.io.IOException;
@@ -53,10 +55,17 @@
     }
 
     @Override
-    public AsynchronousChannelGroup openAsynchronousChannelGroup(Map<String,?> params)
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor)
         throws IOException
     {
-        return new Iocp(this, ThreadPool.create(params)).start();
+        return new Iocp(this, ThreadPool.create(executor)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ThreadFactory factory, int initialSize)
+        throws IOException
+    {
+        return new Iocp(this, ThreadPool.create(factory, initialSize)).start();
     }
 
     private Iocp toIocp(AsynchronousChannelGroup group) throws IOException {
--- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -85,9 +85,6 @@
     // I/O completion port (group)
     private final Iocp iocp;
 
-    //
-    private final Executor executor;
-
     // Caches OVERLAPPED structure for each outstanding I/O operation
     private final PendingIoCache ioCache;
 
@@ -98,12 +95,12 @@
                                                Iocp iocp)
         throws IOException
     {
+        super(iocp.executor());
         this.reading = reading;
         this.writing = writing;
         this.fdObj = fdObj;
         this.handle = fdAccess.getHandle(fdObj);
         this.iocp = iocp;
-        this.executor = iocp.executor();
         this.ioCache = new PendingIoCache();
         this.completionKey = iocp.associate(this, handle);
     }
@@ -132,7 +129,7 @@
     }
 
     @Override
-    public <R,A> PendingIoFuture<R,A> getByOverlapped(long overlapped) {
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
         return ioCache.remove(overlapped);
     }
 
@@ -262,11 +259,11 @@
     private class LockTask<A> implements Runnable, Iocp.ResultHandler {
         private final long position;
         private final FileLockImpl fli;
-        private final PendingIoFuture<FileLock,A> result;
+        private final PendingFuture<FileLock,A> result;
 
         LockTask(long position,
                  FileLockImpl fli,
-                 PendingIoFuture<FileLock,A> result)
+                 PendingFuture<FileLock,A> result)
         {
             this.position = position;
             this.fli = fli;
@@ -289,7 +286,6 @@
                                      overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // I/O is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
                     // acquired lock immediately
@@ -307,18 +303,18 @@
             }
 
             // invoke completion handler
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, true);
         }
 
         @Override
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             // release waiters and invoke completion handler
             result.setResult(fli);
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             // lock not acquired so remove from lock table
             fileLockTable.remove(fli);
 
@@ -328,17 +324,17 @@
             } else {
                 result.setFailure(new AsynchronousCloseException());
             }
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, allowToInvokeDirectly);
         }
     }
 
 
     @Override
-    public <A> IoFuture<FileLock,A> lock(long position,
-                                         long size,
-                                         boolean shared,
-                                         A attachment,
-                                         CompletionHandler<FileLock,? super A> handler)
+    public <A> Future<FileLock> lock(long position,
+                                     long size,
+                                     boolean shared,
+                                     A attachment,
+                                     CompletionHandler<FileLock,? super A> handler)
     {
         if (shared && !reading)
             throw new NonReadableChannelException();
@@ -369,20 +365,20 @@
         }
 
         if (closed) {
-            IoFuture<FileLock,A> result = CompletedIoFuture
+            CompletedFuture<FileLock,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
         // create Future and task that will be invoked to acquire lock
-        PendingIoFuture<FileLock,A> result =
-            new PendingIoFuture<FileLock,A>(this, handler, attachment);
+        PendingFuture<FileLock,A> result =
+            new PendingFuture<FileLock,A>(this, handler, attachment);
         LockTask lockTask = new LockTask<A>(position, fli, result);
         result.setContext(lockTask);
 
         // initiate I/O (can only be done from thread in thread pool)
-        Invoker.invokeOnThreadInThreadPool(executor, lockTask);
+        Invoker.invokeOnThreadInThreadPool(executor(), lockTask);
         return result;
     }
 
@@ -448,7 +444,7 @@
         private final ByteBuffer dst;
         private final int pos, rem;     // buffer position/remaining
         private final long position;    // file position
-        private final PendingIoFuture<Integer,A> result;
+        private final PendingFuture<Integer,A> result;
 
         // set to dst if direct; otherwise set to substituted direct buffer
         private volatile ByteBuffer buf;
@@ -457,7 +453,7 @@
                  int pos,
                  int rem,
                  long position,
-                 PendingIoFuture<Integer,A> result)
+                 PendingFuture<Integer,A> result)
         {
             this.dst = dst;
             this.pos = pos;
@@ -519,7 +515,6 @@
                     n = readFile(handle, address, rem, position, overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // I/O is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
                     // read completed immediately:
@@ -544,14 +539,14 @@
             releaseBufferIfSubstituted();
 
             // invoke completion handler
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, true);
         }
 
         /**
          * Executed when the I/O has completed
          */
         @Override
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             updatePosition(bytesTransferred);
 
             // return direct buffer to cache if substituted
@@ -559,14 +554,15 @@
 
             // release waiters and invoke completion handler
             result.setResult(bytesTransferred);
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             // if EOF detected asynchronously then it is reported as error
             if (error == ERROR_HANDLE_EOF) {
-                completed(-1);
+                completed(-1, allowToInvokeDirectly);
             } else {
                 // return direct buffer to cache if substituted
                 releaseBufferIfSubstituted();
@@ -577,16 +573,17 @@
                 } else {
                     result.setFailure(new AsynchronousCloseException());
                 }
-                Invoker.invoke(result.handler(), result, executor, false, true);
+                Invoker.invoke(result.handler(), result, executor(), false,
+                    allowToInvokeDirectly);
             }
         }
     }
 
     @Override
-    public <A> IoFuture<Integer,A> read(ByteBuffer dst,
-                                        long position,
-                                        A attachment,
-                                        CompletionHandler<Integer,? super A> handler)
+    public <A> Future<Integer> read(ByteBuffer dst,
+                                    long position,
+                                    A attachment,
+                                    CompletionHandler<Integer,? super A> handler)
     {
         if (!reading)
             throw new NonReadableChannelException();
@@ -597,9 +594,9 @@
 
         // check if channel is closed
         if (!isOpen()) {
-            IoFuture<Integer,A> result = CompletedIoFuture
+            CompletedFuture<Integer,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
@@ -610,20 +607,20 @@
 
         // no space remaining
         if (rem == 0) {
-            IoFuture<Integer,A> result =
-                CompletedIoFuture.withResult(this, 0, attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            CompletedFuture<Integer,A> result =
+                CompletedFuture.withResult(this, 0, attachment);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
         // create Future and task that initiates read
-        PendingIoFuture<Integer,A> result =
-            new PendingIoFuture<Integer,A>(this, handler, attachment);
+        PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
         ReadTask readTask = new ReadTask<A>(dst, pos, rem, position, result);
         result.setContext(readTask);
 
         // initiate I/O (can only be done from thread in thread pool)
-        Invoker.invokeOnThreadInThreadPool(executor, readTask);
+        Invoker.invokeOnThreadInThreadPool(executor(), readTask);
         return result;
     }
 
@@ -634,7 +631,7 @@
         private final ByteBuffer src;
         private final int pos, rem;     // buffer position/remaining
         private final long position;    // file position
-        private final PendingIoFuture<Integer,A> result;
+        private final PendingFuture<Integer,A> result;
 
         // set to src if direct; otherwise set to substituted direct buffer
         private volatile ByteBuffer buf;
@@ -643,7 +640,7 @@
                   int pos,
                   int rem,
                   long position,
-                  PendingIoFuture<Integer,A> result)
+                  PendingFuture<Integer,A> result)
         {
             this.src = src;
             this.pos = pos;
@@ -700,7 +697,6 @@
                     n = writeFile(handle, address, rem, position, overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // I/O is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
                     // read completed immediately:
@@ -723,14 +719,14 @@
             }
 
             // invoke completion handler
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, true);
         }
 
         /**
          * Executed when the I/O has completed
          */
         @Override
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             updatePosition(bytesTransferred);
 
             // return direct buffer to cache if substituted
@@ -738,11 +734,12 @@
 
             // release waiters and invoke completion handler
             result.setResult(bytesTransferred);
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             // return direct buffer to cache if substituted
             releaseBufferIfSubstituted();
 
@@ -752,15 +749,16 @@
             } else {
                 result.setFailure(new AsynchronousCloseException());
             }
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
     }
 
     @Override
-    public <A> IoFuture<Integer,A> write(ByteBuffer src,
-                                         long position,
-                                         A attachment,
-                                         CompletionHandler<Integer,? super A> handler)
+    public <A> Future<Integer> write(ByteBuffer src,
+                                     long position,
+                                     A attachment,
+                                     CompletionHandler<Integer,? super A> handler)
     {
         if (!writing)
             throw new NonWritableChannelException();
@@ -769,9 +767,9 @@
 
         // check if channel is closed
         if (!isOpen()) {
-            IoFuture<Integer,A> result = CompletedIoFuture
+            CompletedFuture<Integer,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
@@ -782,20 +780,20 @@
 
         // nothing to write
         if (rem == 0) {
-            IoFuture<Integer,A> result =
-                CompletedIoFuture.withResult(this, 0, attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            CompletedFuture<Integer,A> result =
+                CompletedFuture.withResult(this, 0, attachment);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
         // create Future and task to initiate write
-        PendingIoFuture<Integer,A> result =
-            new PendingIoFuture<Integer,A>(this, handler, attachment);
+        PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
         WriteTask writeTask = new WriteTask<A>(src, pos, rem, position, result);
         result.setContext(writeTask);
 
         // initiate I/O (can only be done from thread in thread pool)
-        Invoker.invokeOnThreadInThreadPool(executor, writeTask);
+        Invoker.invokeOnThreadInThreadPool(executor(), writeTask);
         return result;
     }
 
--- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -28,6 +28,7 @@
 import java.nio.channels.*;
 import java.net.InetSocketAddress;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.io.IOException;
 import java.security.AccessControlContext;
@@ -50,7 +51,6 @@
     private final long handle;
     private final int completionKey;
     private final Iocp iocp;
-    private final Executor executor;
 
     // typically there will be zero, or one I/O operations pending. In rare
     // cases there may be more. These rare cases arise when a sequence of accept
@@ -67,7 +67,7 @@
 
 
     WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
-        super(iocp.provider());
+        super(iocp.provider(), iocp.executor());
 
         // associate socket with given completion port
         long h = IOUtil.fdVal(fd);
@@ -82,13 +82,12 @@
         this.handle = h;
         this.completionKey = key;
         this.iocp = iocp;
-        this.executor = iocp.executor();
         this.ioCache = new PendingIoCache();
         this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);
     }
 
     @Override
-    public <R,A> PendingIoFuture<R,A> getByOverlapped(long overlapped) {
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
         return ioCache.remove(overlapped);
     }
 
@@ -113,11 +112,11 @@
     private class AcceptTask<A> implements Runnable, Iocp.ResultHandler {
         private final WindowsAsynchronousSocketChannelImpl channel;
         private final AccessControlContext acc;
-        private final PendingIoFuture<AsynchronousSocketChannel,A> result;
+        private final PendingFuture<AsynchronousSocketChannel,A> result;
 
         AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
                    AccessControlContext acc,
-                   PendingIoFuture<AsynchronousSocketChannel,A> result)
+                   PendingFuture<AsynchronousSocketChannel,A> result)
         {
             this.channel = channel;
             this.acc = acc;
@@ -181,8 +180,6 @@
 
                         int n = accept0(handle, channel.handle(), overlapped, dataBuffer);
                         if (n == IOStatus.UNAVAILABLE) {
-                            // accept is pending
-                            iocp.threadPoolManager().prepare();
                             return;
                         }
 
@@ -213,15 +210,22 @@
                 end();
             }
 
+            // accept completed immediately but may not have executed on
+            // initiating thread in which case the operation may have been
+            // cancelled.
+            if (result.isCancelled()) {
+                closeChildChannel();
+            }
+
             // invoke completion handler
-            Invoker.invoke(result.handler(), result, executor, true, true);
+            Invoker.invoke(result.handler(), result, executor(), true, true);
         }
 
         /**
          * Executed when the I/O has completed
          */
         @Override
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             try {
                 // connection accept after group has shutdown
                 if (iocp.isShutdown()) {
@@ -253,12 +257,19 @@
                     x = new IOException(x);
                 result.setFailure(x);
             }
+
+            // if an async cancel has already cancelled the operation then
+            // close the new channel so as to free resources
+            if (result.isCancelled()) {
+                closeChildChannel();
+            }
+
             // invoke non-reentrant
-            Invoker.invoke(result.handler(), result, executor, true, true);
+            Invoker.invoke(result.handler(), result, executor(), true, allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             enableAccept();
             closeChildChannel();
 
@@ -268,20 +279,22 @@
             } else {
                 result.setFailure(new AsynchronousCloseException());
             }
-            Invoker.invoke(result.handler(), result, executor, false, true);
+            Invoker.invoke(result.handler(), result, executor(), false, allowToInvokeDirectly);
         }
     }
 
     @Override
-    public <A> IoFuture<AsynchronousSocketChannel,A> accept(A attachment,
+    public <A> Future<AsynchronousSocketChannel> accept(A attachment,
         final CompletionHandler<AsynchronousSocketChannel,? super A> handler)
     {
         if (!isOpen()) {
-            IoFuture<AsynchronousSocketChannel,A> result = CompletedIoFuture
+            CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
+        if (isAcceptKilled())
+            throw new RuntimeException("Accept not allowed due to cancellation");
 
         // ensure channel is bound to local address
         if (getLocalAddress() == null)
@@ -302,9 +315,9 @@
             end();
         }
         if (ioe != null) {
-            CompletedIoFuture<AsynchronousSocketChannel,A> result =
-                CompletedIoFuture.withFailure(this, ioe, attachment);
-            Invoker.invoke(handler, result, executor, false, true);
+            CompletedFuture<AsynchronousSocketChannel,A> result =
+                CompletedFuture.withFailure(this, ioe, attachment);
+            Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
@@ -314,8 +327,8 @@
         AccessControlContext acc = (System.getSecurityManager() == null) ?
             null : AccessController.getContext();
 
-        PendingIoFuture<AsynchronousSocketChannel,A> result =
-            new PendingIoFuture<AsynchronousSocketChannel,A>(this, handler, attachment);
+        PendingFuture<AsynchronousSocketChannel,A> result =
+            new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment);
         AcceptTask task = new AcceptTask<A>(ch, acc, result);
         result.setContext(task);
 
@@ -327,7 +340,7 @@
         // then it will only be invoked direcly if this thread is in the thread
         // pool. If this thread is not in the thread pool when a task is
         // submitted to initiate the accept.
-        Invoker.invokeOnThreadInThreadPool(executor, task);
+        Invoker.invokeOnThreadInThreadPool(executor(), task);
         return result;
     }
 
--- a/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java	Tue Jun 24 20:05:07 2008 +0100
@@ -123,7 +123,7 @@
      * Invoked by Iocp when an I/O operation competes.
      */
     @Override
-    public <R,A> PendingIoFuture<R,A> getByOverlapped(long overlapped) {
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
         return ioCache.remove(overlapped);
     }
 
@@ -160,15 +160,25 @@
             iocp.disassociate(completionKey);
     }
 
+    @Override
+    public void onCancel(PendingFuture<?,?> task) {
+        if (task.getContext() instanceof ConnectTask)
+            killConnect();
+        if (task.getContext() instanceof ReadTask)
+            killReading();
+        if (task.getContext() instanceof WriteTask)
+            killWriting();
+    }
+
     /**
      * Implements the task to initiate a connection and the handler to
      * consume the result when the connection is established (or fails).
      */
     private class ConnectTask<A> implements Runnable, Iocp.ResultHandler {
         private final InetSocketAddress remote;
-        private final PendingIoFuture<Void,A> result;
+        private final PendingFuture<Void,A> result;
 
-        ConnectTask(InetSocketAddress remote, PendingIoFuture<Void,A> result) {
+        ConnectTask(InetSocketAddress remote, PendingFuture<Void,A> result) {
             this.remote = remote;
             this.result = result;
         }
@@ -218,7 +228,6 @@
                                      remote.getPort(), overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // connection is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
 
@@ -245,7 +254,7 @@
          * Invoked by handler thread when connection established.
          */
         @Override
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             Throwable exc = null;
             try {
                 begin();
@@ -264,31 +273,33 @@
                 result.setFailure(toIOException(exc));
             }
 
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         /**
          * Invoked by handler thread when failed to establish connection.
          */
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             if (isOpen()) {
                 closeChannel();
                 result.setFailure(x);
             } else {
                 result.setFailure(new AsynchronousCloseException());
             }
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
     }
 
     @Override
-    public <A> IoFuture<Void,A> connect(SocketAddress remote,
-                                        A attachment,
-                                        CompletionHandler<Void,? super A> handler)
+    public <A> Future<Void> connect(SocketAddress remote,
+                                    A attachment,
+                                    CompletionHandler<Void,? super A> handler)
     {
         if (!isOpen()) {
-            IoFuture<Void,A> result = CompletedIoFuture
+            CompletedFuture<Void,A> result = CompletedFuture
                 .withFailure(this, new ClosedChannelException(), attachment);
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
@@ -325,15 +336,15 @@
             try {
                 close();
             } catch (IOException ignore) { }
-            IoFuture<Void,A> result = CompletedIoFuture
+            CompletedFuture<Void,A> result = CompletedFuture
                 .withFailure(this, bindException, attachment);
             Invoker.invoke(handler, result, executor(), false, true);
             return result;
         }
 
         // setup task
-        PendingIoFuture<Void,A> result =
-            new PendingIoFuture<Void,A>(this, handler, attachment);
+        PendingFuture<Void,A> result =
+            new PendingFuture<Void,A>(this, handler, attachment);
         ConnectTask task = new ConnectTask<A>(isa, result);
         result.setContext(task);
 
@@ -346,18 +357,18 @@
      * Implements the task to initiate a read and the handler to consume the
      * result when the read completes.
      */
-    private class ReadTask<R,A> implements Runnable, Iocp.ResultHandler {
+    private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler {
         private final ByteBuffer[] bufs;
         private final int numBufs;
         private final boolean scatteringRead;
-        private final PendingIoFuture<R,A> result;
+        private final PendingFuture<V,A> result;
 
         // set by run method
         private ByteBuffer[] shadow;
 
         ReadTask(ByteBuffer[] bufs,
                  boolean scatteringRead,
-                 PendingIoFuture<R,A> result)
+                 PendingFuture<V,A> result)
         {
             this.bufs = bufs;
             this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
@@ -456,7 +467,6 @@
                     int n = read0(handle, numBufs, readBufferArray, overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // I/O is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
                     // read completed immediately:
@@ -471,9 +481,9 @@
                     enableReading();
 
                     if (scatteringRead) {
-                        result.setResult((R)Long.valueOf(n));
+                        result.setResult((V)Long.valueOf(n));
                     } else {
-                        result.setResult((R)Integer.valueOf(n));
+                        result.setResult((V)Integer.valueOf(n));
                     }
                 }
             } catch (Throwable x) {
@@ -505,7 +515,7 @@
          */
         @Override
         @SuppressWarnings("unchecked")
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             if (bytesTransferred == 0) {
                 bytesTransferred = -1;  // EOF
             } else {
@@ -521,16 +531,17 @@
                     return;
                 enableReading();
                 if (scatteringRead) {
-                    result.setResult((R)Long.valueOf(bytesTransferred));
+                    result.setResult((V)Long.valueOf(bytesTransferred));
                 } else {
-                    result.setResult((R)Integer.valueOf(bytesTransferred));
+                    result.setResult((V)Integer.valueOf(bytesTransferred));
                 }
             }
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
             // return direct buffer to cache if substituted
             releaseBuffers();
 
@@ -544,7 +555,8 @@
                 enableReading();
                 result.setFailure(x);
             }
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         /**
@@ -567,17 +579,17 @@
     }
 
     @Override
-    <R extends Number,A> IoFuture<R,A> readImpl(ByteBuffer[] bufs,
-                                                boolean scatteringRead,
-                                                long timeout,
-                                                TimeUnit unit,
-                                                A attachment,
-                                                CompletionHandler<R,? super A> handler)
+    <V extends Number,A> Future<V> readImpl(ByteBuffer[] bufs,
+                                            boolean scatteringRead,
+                                            long timeout,
+                                            TimeUnit unit,
+                                            A attachment,
+                                            CompletionHandler<V,? super A> handler)
     {
         // setup task
-        PendingIoFuture<R,A> result =
-            new PendingIoFuture<R,A>(this, handler, attachment);
-        final ReadTask readTask = new ReadTask<R,A>(bufs, scatteringRead, result);
+        PendingFuture<V,A> result =
+            new PendingFuture<V,A>(this, handler, attachment);
+        final ReadTask readTask = new ReadTask<V,A>(bufs, scatteringRead, result);
         result.setContext(readTask);
 
         // schedule timeout
@@ -599,18 +611,18 @@
      * Implements the task to initiate a write and the handler to consume the
      * result when the write completes.
      */
-    private class WriteTask<R,A> implements Runnable, Iocp.ResultHandler {
+    private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler {
         private final ByteBuffer[] bufs;
         private final int numBufs;
         private final boolean gatheringWrite;
-        private final PendingIoFuture<R,A> result;
+        private final PendingFuture<V,A> result;
 
         // set by run method
         private ByteBuffer[] shadow;
 
         WriteTask(ByteBuffer[] bufs,
                   boolean gatheringWrite,
-                  PendingIoFuture<R,A> result)
+                  PendingFuture<V,A> result)
         {
             this.bufs = bufs;
             this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
@@ -708,7 +720,6 @@
                     n = write0(handle, numBufs, writeBufferArray, overlapped);
                     if (n == IOStatus.UNAVAILABLE) {
                         // I/O is pending
-                        iocp.threadPoolManager().prepare();
                         return;
                     }
                     if (n == IOStatus.EOF) {
@@ -726,9 +737,9 @@
 
                     // result is a Long or Integer
                     if (gatheringWrite) {
-                        result.setResult((R)Long.valueOf(n));
+                        result.setResult((V)Long.valueOf(n));
                     } else {
-                        result.setResult((R)Integer.valueOf((int)n));
+                        result.setResult((V)Integer.valueOf((int)n));
                     }
                 }
             } catch (Throwable x) {
@@ -759,7 +770,7 @@
          */
         @Override
         @SuppressWarnings("unchecked")
-        public void completed(int bytesTransferred) {
+        public void completed(int bytesTransferred, boolean allowToInvokeDirectly) {
             updateBuffers(bytesTransferred);
 
             // return direct buffer to cache if substituted
@@ -771,16 +782,17 @@
                     return;
                 enableWriting();
                 if (gatheringWrite) {
-                    result.setResult((R)Long.valueOf(bytesTransferred));
+                    result.setResult((V)Long.valueOf(bytesTransferred));
                 } else {
-                    result.setResult((R)Integer.valueOf(bytesTransferred));
+                    result.setResult((V)Integer.valueOf(bytesTransferred));
                 }
             }
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         @Override
-        public void failed(int error, IOException x) {
+        public void failed(int error, IOException x, boolean allowToInvokeDirectly) {
 
 
             // return direct buffer to cache if substituted
@@ -796,7 +808,8 @@
                 enableWriting();
                 result.setFailure(x);
             }
-            Invoker.invoke(result.handler(), result, executor(), false, true);
+            Invoker.invoke(result.handler(), result, executor(), false,
+                allowToInvokeDirectly);
         }
 
         /**
@@ -819,17 +832,17 @@
     }
 
     @Override
-    <R extends Number,A> IoFuture<R,A> writeImpl(ByteBuffer[] bufs,
-                                                 boolean gatheringWrite,
-                                                 long timeout,
-                                                 TimeUnit unit,
-                                                 A attachment,
-                                                 CompletionHandler<R,? super A> handler)
+    <V extends Number,A> Future<V> writeImpl(ByteBuffer[] bufs,
+                                             boolean gatheringWrite,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<V,? super A> handler)
     {
         // setup task
-        PendingIoFuture<R,A> result =
-            new PendingIoFuture<R,A>(this, handler, attachment);
-        final WriteTask writeTask = new WriteTask<R,A>(bufs, gatheringWrite, result);
+        PendingFuture<V,A> result =
+            new PendingFuture<V,A>(this, handler, attachment);
+        final WriteTask writeTask = new WriteTask<V,A>(bufs, gatheringWrite, result);
         result.setContext(writeTask);
 
         // schedule timeout
--- a/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -404,7 +404,16 @@
             try {
                 InitializeSecurityDescriptor(buffer.address());
                 SetSecurityDescriptorOwner(buffer.address(), pOwner);
-                SetFileSecurity(path, OWNER_SECURITY_INFORMATION, buffer.address());
+                // may need SeRestorePrivilege to set the owner
+                WindowsSecurity.Privilege priv =
+                    WindowsSecurity.enablePrivilege("SeRestorePrivilege");
+                try {
+                    SetFileSecurity(path,
+                                    OWNER_SECURITY_INFORMATION,
+                                    buffer.address());
+                } finally {
+                    priv.drop();
+                }
             } catch (WindowsException x) {
                 x.rethrowAsIOException(file);
             } finally {
--- a/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,7 +30,6 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.Set;
-import static java.nio.file.OpenOption.*;
 
 import sun.nio.ch.FileChannelImpl;
 import sun.nio.ch.ThreadPool;
@@ -52,6 +51,12 @@
     private WindowsChannelFactory() { }
 
     /**
+     * Do not follow reparse points when opening an existing file. Do not fail
+     * if the file is a reparse point.
+     */
+    static final OpenOption NOFOLLOW_REPARSEPOINT = new OpenOption() { };
+
+    /**
      * Open/creates file, returning FileChannel to access the file
      *
      * @param   pathForWindows
@@ -87,8 +92,13 @@
             }
             if (flag == null)
                 throw new NullPointerException();
-            if (!(flag instanceof StandardOpenOption))
+            if (!(flag instanceof StandardOpenOption)) {
+                // non-standard options
+                if (flag == NOFOLLOW_REPARSEPOINT)
+                    continue;
+
                 throw new IllegalArgumentException();
+            }
         }
 
         // default is reading
@@ -183,6 +193,9 @@
                                        Set<? extends OpenOption> options)
         throws WindowsException
     {
+        // set to true if file must be truncated after open
+        boolean truncateAfterOpen = false;
+
         // map options
         int dwDesiredAccess = 0;
         if (reading)
@@ -196,16 +209,22 @@
 
         int dwCreationDisposition = OPEN_EXISTING;
         if (writing) {
-            if (options.contains(StandardOpenOption.TRUNCATE_EXISTING))
-                dwCreationDisposition = TRUNCATE_EXISTING;
-
             if (options.contains(StandardOpenOption.CREATE_NEW)) {
                 dwCreationDisposition = CREATE_NEW;
                 // force create to fail if file is orphaned reparse point
                 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
             } else {
-                if (options.contains(StandardOpenOption.CREATE)) {
+                if (options.contains(StandardOpenOption.CREATE))
                     dwCreationDisposition = OPEN_ALWAYS;
+                if (options.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
+                    // Windows doesn't have a creation disposition that exactly
+                    // corresponds to CREATE + TRUNCATE_EXISTING so we use
+                    // the OPEN_ALWAYS mode and then truncate the file.
+                    if (dwCreationDisposition == OPEN_ALWAYS) {
+                        truncateAfterOpen = true;
+                    } else {
+                        dwCreationDisposition = TRUNCATE_EXISTING;
+                    }
                 }
             }
         }
@@ -215,12 +234,15 @@
         if (overlapped)
             dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
 
-        // NOFOLLOW_LINKS prevents us from following links when opening existing file
+        // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT present using following
+        // reparse points.
         boolean okayToFollowLinks = true;
         if (dwCreationDisposition != CREATE_NEW &&
-            options.contains(StandardOpenOption.NOFOLLOW_LINKS))
+            (options.contains(StandardOpenOption.NOFOLLOW_LINKS) ||
+             options.contains(NOFOLLOW_REPARSEPOINT)))
         {
-            okayToFollowLinks = false;
+            if (options.contains(StandardOpenOption.NOFOLLOW_LINKS))
+                okayToFollowLinks = false;
             dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
         }
 
@@ -248,8 +270,20 @@
                 // for security reasons we can only test here the file is a
                 // reparse point. To read the reparse point tag would require
                 // re-opening the file and this method is required to be atomic.
-                if (WindowsFileAttributes.readAttributes(handle).isReparsePoint())
+                if (WindowsFileAttributes.readAttributes(handle).isReparsePoint()) {
                     throw new WindowsException("File is reparse point");
+                }
+
+            } catch (WindowsException x) {
+                CloseHandle(handle);
+                throw x;
+            }
+        }
+
+        // truncate file (for CREATE + TRUNCATE_EXISTING case)
+        if (truncateAfterOpen) {
+            try {
+                SetEndOfFile(handle);
             } catch (WindowsException x) {
                 CloseHandle(handle);
                 throw x;
--- a/src/windows/classes/sun/nio/fs/WindowsConstants.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsConstants.java	Tue Jun 24 20:05:07 2008 +0100
@@ -176,7 +176,13 @@
     public static final int FILE_WRITE_ATTRIBUTES       = 0x0100;
 
     // operating system security
+    public static final int TOKEN_DUPLICATE             = 0x0002;
+    public static final int TOKEN_IMPERSONATE           = 0x0004;
     public static final int TOKEN_QUERY                 = 0x0008;
+    public static final int TOKEN_ADJUST_PRIVILEGES     = 0x0020;
+
+    public static final int SE_PRIVILEGE_ENABLED        = 0x00000002;
+
     public static final int TokenUser                   = 1;
     public static final int PROCESS_QUERY_INFORMATION   = 0x0400;
 }
--- a/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Tue Jun 24 20:05:07 2008 +0100
@@ -49,7 +49,6 @@
         // map options
         boolean replaceExisting = false;
         boolean copyAttributes = false;
-        boolean failIfUnableToCopyAttributes = false;
         boolean followLinks = true;
         for (CopyOption option: options) {
             if (option == StandardCopyOption.REPLACE_EXISTING) {
@@ -62,7 +61,6 @@
             }
             if (option == StandardCopyOption.COPY_ATTRIBUTES) {
                 copyAttributes = true;
-                failIfUnableToCopyAttributes = true;
                 continue;
             }
             if (option == null)
@@ -174,36 +172,51 @@
             } catch (WindowsException x) {
                 x.rethrowAsIOException(source, target);
             }
-        } else {
-            // create new directory or directory junction
-            try {
-                if (sourceAttrs.isDirectory()) {
-                    CreateDirectory(targetPath);
-                } else {
-                    String linkTarget = WindowsLinkSupport.readLink(source);
-                    int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
-                    CreateSymbolicLink(targetPath,
-                                       addPrefixIfNeeded(linkTarget),
-                                       flags);
-                }
-            } catch (WindowsException x) {
-                x.rethrowAsIOException(target);
-            }
             if (copyAttributes) {
-                WindowsFileAttributeView view = new WindowsFileAttributeView();
-                view.bind(target, false);
+                // CopyFileEx does not copy security attributes
                 try {
-                    view.setAttributes(sourceAttrs);
+                    copySecurityAttributes(source, target, followLinks);
                 } catch (IOException x) {
-                    if (sourceAttrs.isDirectory() && failIfUnableToCopyAttributes) {
-                        try {
-                            RemoveDirectory(targetPath);
-                        } catch (WindowsException ignore) { }
-                        throw x;
-                    }
+                    // ignore
                 }
             }
+            return;
         }
+
+        // copy directory or directory junction
+        try {
+            if (sourceAttrs.isDirectory()) {
+                CreateDirectory(targetPath);
+            } else {
+                String linkTarget = WindowsLinkSupport.readLink(source);
+                int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
+                CreateSymbolicLink(targetPath,
+                                   addPrefixIfNeeded(linkTarget),
+                                   flags);
+            }
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(target);
+        }
+        if (copyAttributes) {
+            // copy DOS/timestamps attributes
+            WindowsFileAttributeView view = new WindowsFileAttributeView();
+            view.bind(target, false);
+            try {
+                view.setAttributes(sourceAttrs);
+            } catch (IOException x) {
+                if (sourceAttrs.isDirectory()) {
+                    try {
+                        RemoveDirectory(targetPath);
+                    } catch (WindowsException ignore) { }
+                }
+            }
+
+            // copy security attributes. If this fail it doesn't cause the move
+            // to fail.
+            try {
+                copySecurityAttributes(source, target, followLinks);
+            } catch (IOException ignore) { }
+            }
     }
 
     /**
@@ -331,17 +344,34 @@
             }
         }
 
-        // first try MoveFileEx
+        // first try MoveFileEx (no options). If target is on same voluem then
+        // all attributes (including security attributes) are preserved.
         try {
-            MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
+            MoveFileEx(sourcePath, targetPath, 0);
             return;
         } catch (WindowsException x) {
-            // MoveFileEx cannot copy directories across file systems
-            if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink())
+            if (x.lastError() != ERROR_NOT_SAME_DEVICE)
                 x.rethrowAsIOException(source, target);
         }
 
-        // moving diretcory or diretcory-link to another file system
+        // target is on different volume so use MoveFileEx with copy option
+        if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
+            try {
+                MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(source, target);
+            }
+            // MoveFileEx does not copy security attributes when moving
+            // across volumes.
+            try {
+                copySecurityAttributes(source, target, false);
+            } catch (IOException x) {
+                // ignore
+            }
+            return;
+        }
+
+        // moving directory or directory-link to another file system
         assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();
 
         // create new directory or directory junction
@@ -358,7 +388,7 @@
             x.rethrowAsIOException(target);
         }
 
-        // copy attributes
+        // copy timestamps/DOS attributes
         WindowsFileAttributeView view = new WindowsFileAttributeView();
         view.bind(target, false);
         try {
@@ -371,6 +401,12 @@
             throw x;
         }
 
+        // copy security attributes. If this fail it doesn't cause the move
+        // to fail.
+        try {
+            copySecurityAttributes(source, target, false);
+        } catch (IOException ignore) { }
+
         // delete source
         try {
             RemoveDirectory(sourcePath);
@@ -392,6 +428,40 @@
     }
 
     /**
+     * Copy DACL/owner/group from source to target
+     */
+    private static void copySecurityAttributes(WindowsPath source,
+                                               WindowsPath target,
+                                               boolean followLinks)
+        throws IOException
+    {
+        String path = followLinks ?
+            WindowsLinkSupport.getFinalPath(source) : source.getPathForWin32Calls();
+
+        // may need SeRestorePrivilege to set file owner
+        WindowsSecurity.Privilege priv =
+            WindowsSecurity.enablePrivilege("SeRestorePrivilege");
+        try {
+            int request = (DACL_SECURITY_INFORMATION |
+                OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
+            NativeBuffer buffer =
+                WindowsAclFileAttributeView.getFileSecurity(path, request);
+            try {
+                try {
+                    SetFileSecurity(target.getPathForWin32Calls(), request,
+                        buffer.address());
+                } catch (WindowsException x) {
+                    x.rethrowAsIOException(target);
+                }
+            } finally {
+                buffer.release();
+            }
+        } finally {
+            priv.drop();
+        }
+    }
+
+    /**
      * Add long path prefix to path if required
      */
     private static String addPrefixIfNeeded(String path) {
--- a/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Tue Jun 24 20:05:07 2008 +0100
@@ -30,6 +30,7 @@
 import java.nio.file.attribute.*;
 import java.nio.channels.*;
 import java.net.URI;
+import java.util.concurrent.ExecutorService;
 import java.io.IOException;
 import java.util.*;
 import static java.nio.file.OpenOption.*;
@@ -126,13 +127,13 @@
     @Override
     public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
                                                               Set<? extends OpenOption> options,
-                                                              Map<String,?> params,
+                                                              ExecutorService executor,
                                                               Attribute<?>... attrs)
         throws IOException
     {
         WindowsPath file = checkPathAndAttribtues(path, attrs);
 
-        ThreadPool pool = (params == null) ? null : ThreadPool.create(params);
+        ThreadPool pool = (executor == null) ? null : ThreadPool.create(executor);
 
         return WindowsChannelFactory
             .newAsynchronousFileChannel(file.getPathForWin32Calls(),
--- a/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java	Tue Jun 24 20:05:07 2008 +0100
@@ -47,11 +47,13 @@
     private static final Unsafe unsafe = Unsafe.getUnsafe();
 
     // syntax to address named streams
+    private String join(String file, String name) {
+        if (name == null)
+            throw new NullPointerException("'name' is null");
+        return file + ":" + name;
+    }
     private String join(WindowsPath file, String name) {
-        return file.getPathForWin32Calls() + ":" + name;
-    }
-    private String join(String file, String name) {
-        return file + ":" + name;
+        return join(file.getPathForWin32Calls(), name);
     }
 
     @Override
@@ -187,11 +189,10 @@
         // wrap with channel
         FileChannel fc = null;
         try {
-            Set<StandardOpenOption> opts = new HashSet<StandardOpenOption>();
+            Set<OpenOption> opts = new HashSet<OpenOption>();
             opts.add(READ);
             if (!info.followLinks())
-                opts.add(NOFOLLOW_LINKS);
-
+                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
             fc = WindowsChannelFactory
                 .newFileChannel(join(file, name), null, opts);
         } catch (WindowsException x) {
@@ -217,10 +218,10 @@
         // wrap with channel
         FileChannel fc = null;
         try {
-            Set<StandardOpenOption> opts = new HashSet<StandardOpenOption>();
+            Set<OpenOption> opts = new HashSet<OpenOption>();
             opts.add(READ);
             if (!info.followLinks())
-                opts.add(NOFOLLOW_LINKS);
+                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
             fc = WindowsChannelFactory
                 .newFileChannel(join(file, name), null, opts);
         } catch (WindowsException x) {
@@ -259,26 +260,31 @@
          * may cause sharing violations with other programs that are accessing
          * the unnamed stream.
          */
-        Set<StandardOpenOption> opts = new HashSet<StandardOpenOption>();
-        if (!info.followLinks())
-            opts.add(NOFOLLOW_LINKS);
-        opts.add(READ);
-        FileChannel unnamed = null;
+        long handle = -1L;
         try {
-            unnamed = WindowsChannelFactory
-                .newFileChannel(file.getPathForWin32Calls(), null, opts);
+            int flags = FILE_FLAG_BACKUP_SEMANTICS;
+            if (!info.followLinks())
+                flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+
+            handle = CreateFile(file.getPathForWin32Calls(),
+                                GENERIC_READ,
+                                (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                                OPEN_EXISTING,
+                                flags);
         } catch (WindowsException x) {
             x.rethrowAsIOException(file);
         }
         try {
-            opts.remove(READ);
+            Set<OpenOption> opts = new HashSet<OpenOption>();
+            if (!info.followLinks())
+                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
             opts.add(CREATE);
             opts.add(WRITE);
             opts.add(StandardOpenOption.TRUNCATE_EXISTING);
             FileChannel named = null;
             try {
                 named = WindowsChannelFactory
-                .newFileChannel(join(file, name), null, opts);
+                    .newFileChannel(join(file, name), null, opts);
             } catch (WindowsException x) {
                 x.rethrowAsIOException(join(file, name));
             }
@@ -293,7 +299,7 @@
                 named.close();
             }
         } finally {
-            unnamed.close();
+            CloseHandle(handle);
         }
     }
 
--- a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Tue Jun 24 20:05:07 2008 +0100
@@ -297,6 +297,13 @@
         long lastAccessTime, long lastWriteTime) throws WindowsException;
 
     /**
+     * SetEndOfFile(
+     *   HANDLE hFile
+     * )
+     */
+    static native void SetEndOfFile(long handle) throws WindowsException;
+
+    /**
      * DWORD GetLogicalDrives(VOID)
      */
     static native int GetLogicalDrives() throws WindowsException;
@@ -681,19 +688,15 @@
         throws WindowsException;
 
     /**
-     * DWORD GetCurrentProcessId(VOID)
+     * HANDLE GetCurrentProcess(VOID)
      */
-    static native int GetCurrentProcessId();
+    static native long GetCurrentProcess();
 
     /**
-     * HANDLE OpenProcess(
-     *   DWORD dwDesiredAccess
-     *   BOOL bInheritHandle,
-     *   DWORD dwProcessId
-     * )
+     * HANDLE GetCurrentThread(VOID)
      */
-    static native long OpenProcess(int access, int processId)
-        throws WindowsException;
+    static native long GetCurrentThread();
+
 
     /**
      * OpenProcessToken(
@@ -706,6 +709,31 @@
         throws WindowsException;
 
     /**
+     * OpenThreadToken(
+     *   HANDLE ThreadHandle,
+     *   DWORD DesiredAccess,
+     *   BOOL OpenAsSelf,
+     *   PHANDLE TokenHandle
+     * )
+     */
+    static native long OpenThreadToken(long hThread, int desiredAccess,
+        boolean openAsSelf) throws WindowsException;
+
+    /**
+     */
+    static native long DuplicateTokenEx(long hThread, int desiredAccess)
+        throws WindowsException;
+
+    /**
+     * SetThreadToken(
+     *   PHANDLE Thread,
+     *   HANDLE Token
+     * )
+     */
+    static native void SetThreadToken(long thread, long hToken)
+        throws WindowsException;
+
+    /**
      * GetTokenInformation(
      *   HANDLE TokenHandle,
      *   TOKEN_INFORMATION_CLASS TokenInformationClass,
@@ -718,6 +746,32 @@
         long pTokenInfo, int tokenInfoLength) throws WindowsException;
 
     /**
+     * AdjustTokenPrivileges(
+     *   HANDLE TokenHandle,
+     *   BOOL DisableAllPrivileges
+     *   PTOKEN_PRIVILEGES NewState
+     *   DWORD BufferLength
+     *   PTOKEN_PRIVILEGES
+     *   PDWORD ReturnLength
+     * )
+     */
+    static native void AdjustTokenPrivileges(long token, long luid, int attributes)
+        throws WindowsException;
+
+    /**
+     */
+    static long LookupPrivilegeValue(String name) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(name);
+        try {
+            return LookupPrivilegeValue0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long LookupPrivilegeValue0(long lpName)
+        throws WindowsException;
+
+    /**
      * BuildTrusteeWithSid(
      *   PTRUSTEE pTrustee,
      *   PSID pSid
@@ -739,7 +793,6 @@
     static native int GetEffectiveRightsFromAcl(long pAcl, long pTrustee)
         throws WindowsException;
 
-
     /**
      * CreateSymbolicLink(
      *   LPCWSTR lpSymlinkFileName,
--- a/src/windows/classes/sun/nio/fs/WindowsPath.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsPath.java	Tue Jun 24 20:05:07 2008 +0100
@@ -608,43 +608,26 @@
     }
 
     /**
-     * Process ID (set lazily).
-     */
-    static volatile int currentProcessId;
-
-    /**
      * Returns buffer with SID_AND_ATTRIBUTES structure representing the user
-     * associated with the current process access token.
+     * associated with the current thread access token.
+     * FIXME - this should be cached.
      */
     private NativeBuffer getUserInfo() throws IOException {
-        if (currentProcessId == 0)
-            currentProcessId = GetCurrentProcessId();
+        try {
+            long hToken = WindowsSecurity.processTokenWithQueryAccess;
+            int size = GetTokenInformation(hToken, TokenUser, 0L, 0);
+            assert size > 0;
 
-        // can't cache token as access may change in a running system
-        try {
-            long hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, currentProcessId);
+            NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
             try {
-                long hToken = OpenProcessToken(hProcess, TOKEN_QUERY);
-                try {
-                    int size = GetTokenInformation(hToken, TokenUser, 0L, 0);
-                    assert size > 0;
-
-                    NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
-                    try {
-                        int newsize = GetTokenInformation(hToken, TokenUser,
-                                                          buffer.address(), size);
-                        if (newsize != size)
-                            throw new AssertionError();
-                        return buffer;
-                    } catch (WindowsException x) {
-                        buffer.release();
-                        throw x;
-                    }
-                } finally {
-                    CloseHandle(hToken);
-                }
-            } finally {
-                CloseHandle(hProcess);
+                int newsize = GetTokenInformation(hToken, TokenUser,
+                                                  buffer.address(), size);
+                if (newsize != size)
+                    throw new AssertionError();
+                return buffer;
+            } catch (WindowsException x) {
+                buffer.release();
+                throw x;
             }
         } catch (WindowsException x) {
             throw new IOException(x.getMessage());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/sun/nio/fs/WindowsSecurity.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Security related utility methods.
+ */
+
+class WindowsSecurity {
+    private WindowsSecurity() { }
+
+    // opens process token for given access
+    private static long openProcessToken(int access) {
+        try {
+            return OpenProcessToken(GetCurrentProcess(), access);
+        } catch (WindowsException x) {
+            return 0L;
+        }
+    }
+
+    /**
+     * Returns the access token for this process with TOKEN_DUPLICATE access
+     */
+    static final long processTokenWithDuplicateAccess =
+        openProcessToken(TOKEN_DUPLICATE);
+
+    /**
+     * Returns the access token for this process with TOKEN_QUERY access
+     */
+    static final long processTokenWithQueryAccess =
+        openProcessToken(TOKEN_QUERY);
+
+    /**
+     * Returned by enablePrivilege when code may require a given privilege.
+     * The drop method should be invoked after the operation completes so as
+     * to revert the privilege.
+     */
+    static interface Privilege {
+        void drop();
+    }
+
+    /**
+     * Attempts to enable the given privilege for this method.
+     */
+    static Privilege enablePrivilege(String priv) {
+        final long pLuid;
+        try {
+            pLuid = LookupPrivilegeValue(priv);
+        } catch (WindowsException x) {
+            // indicates bug in caller
+            throw new AssertionError(x);
+        }
+
+        long hToken = 0L;
+        boolean impersontating = false;
+        boolean evalated = false;
+        try {
+            hToken = OpenThreadToken(GetCurrentThread(),
+                                     TOKEN_ADJUST_PRIVILEGES, false);
+            if (hToken == 0L && processTokenWithDuplicateAccess != 0L) {
+                hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
+                    (TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE));
+                SetThreadToken(0L, hToken);
+                impersontating = true;
+            }
+
+            if (hToken != 0L) {
+                AdjustTokenPrivileges(hToken, pLuid, SE_PRIVILEGE_ENABLED);
+                evalated = true;
+            }
+        } catch (WindowsException x) {
+            // nothing to do, privilege not enabled
+        }
+
+        final long token = hToken;
+        final boolean stopImpersontating = impersontating;
+        final boolean needToRevert = evalated;
+
+        return new Privilege() {
+            @Override
+            public void drop() {
+                try {
+                    if (stopImpersontating) {
+                        SetThreadToken(0L, 0L);
+                    } else {
+                        if (needToRevert) {
+                            AdjustTokenPrivileges(token, pLuid, 0);
+                        }
+                    }
+                } catch (WindowsException x) {
+                    // should not happen
+                    throw new AssertionError(x);
+                }
+            }
+        };
+    }
+}
--- a/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Tue Jun 24 18:30:03 2008 +0100
+++ b/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Tue Jun 24 20:05:07 2008 +0100
@@ -433,6 +433,16 @@
     }
 }
 
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetEndOfFile(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+
+    if (SetEndOfFile(h) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
 
 JNIEXPORT void JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumeInformation0(JNIEnv* env, jclass this,
@@ -799,7 +809,7 @@
 Java_sun_nio_fs_WindowsNativeDispatcher_ConvertStringSidToSid0(JNIEnv* env,
     jclass this, jlong address)
 {
-    LPCWSTR lpStringSid = jlong_to_ptr(address);
+    LPWSTR lpStringSid = jlong_to_ptr(address);
     PSID pSid;
 
     if (ConvertStringSidToSid_func == NULL) {
@@ -813,23 +823,18 @@
     return ptr_to_jlong(pSid);
 }
 
-JNIEXPORT jint JNICALL
-Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentProcessId(JNIEnv* env, jclass this) {
-    return (jint)GetCurrentProcessId();
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentProcess(JNIEnv* env, jclass this) {
+    HANDLE hProcess = GetCurrentProcess();
+    return ptr_to_jlong(hProcess);
 }
 
 JNIEXPORT jlong JNICALL
-Java_sun_nio_fs_WindowsNativeDispatcher_OpenProcess(JNIEnv* env,
-    jclass this, jint desiredAccess, jint processId)
-{
-    HANDLE hProcess = OpenProcess((DWORD)desiredAccess, FALSE, (DWORD)processId);
-    if (hProcess == NULL) {
-        throwWindowsException(env, GetLastError());
-    }
-    return ptr_to_jlong(hProcess);
+Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentThread(JNIEnv* env, jclass this) {
+    HANDLE hThread = GetCurrentThread();
+    return ptr_to_jlong(hThread);
 }
 
-
 JNIEXPORT jlong JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_OpenProcessToken(JNIEnv* env,
     jclass this, jlong process, jint desiredAccess)
@@ -837,12 +842,57 @@
     HANDLE hProcess = (HANDLE)jlong_to_ptr(process);
     HANDLE hToken;
 
-    if (OpenProcessToken(hProcess, (DWORD)desiredAccess, &hToken) == 0) {
+    if (OpenProcessToken(hProcess, (DWORD)desiredAccess, &hToken) == 0)
+        throwWindowsException(env, GetLastError());
+    return ptr_to_jlong(hToken);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_OpenThreadToken(JNIEnv* env,
+    jclass this, jlong thread, jint desiredAccess, jboolean openAsSelf)
+{
+    HANDLE hThread = (HANDLE)jlong_to_ptr(thread);
+    HANDLE hToken;
+    BOOL bOpenAsSelf = (openAsSelf == JNI_TRUE) ? TRUE : FALSE;
+
+    if (OpenThreadToken(hThread, (DWORD)desiredAccess, bOpenAsSelf, &hToken) == 0) {
+        if (GetLastError() == ERROR_NO_TOKEN)
+            return (jlong)0;
         throwWindowsException(env, GetLastError());
     }
     return ptr_to_jlong(hToken);
 }
 
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_DuplicateTokenEx(JNIEnv* env,
+    jclass this, jlong token, jint desiredAccess)
+{
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+    HANDLE resultToken;
+    BOOL res;
+
+    res = DuplicateTokenEx(hToken,
+                           (DWORD)desiredAccess,
+                           NULL,
+                           SecurityImpersonation,
+                           TokenImpersonation,
+                           &resultToken);
+    if (res == 0)
+        throwWindowsException(env, GetLastError());
+    return ptr_to_jlong(resultToken);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetThreadToken(JNIEnv* env,
+    jclass this, jlong thread, jlong token)
+{
+    HANDLE hThread = (HANDLE)jlong_to_ptr(thread);
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+
+    if (SetThreadToken(hThread, hToken) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_fs_WindowsNativeDispatcher_GetTokenInformation(JNIEnv* env,
     jclass this, jlong token, jint tokenInfoClass, jlong tokenInfo, jint tokenInfoLength)
@@ -864,7 +914,38 @@
     } else {
         return tokenInfoLength;
     }
+}
 
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_AdjustTokenPrivileges(JNIEnv* env,
+    jclass this, jlong token, jlong luid, jint attributes)
+{
+    TOKEN_PRIVILEGES privs[1];
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+    PLUID pLuid = (PLUID)jlong_to_ptr(luid);
+
+    privs[0].PrivilegeCount = 1;
+    privs[0].Privileges[0].Luid = *pLuid;
+    privs[0].Privileges[0].Attributes = (DWORD)attributes;
+
+    if (AdjustTokenPrivileges(hToken, FALSE, &privs[0], 1, NULL, NULL) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_LookupPrivilegeValue0(JNIEnv* env,
+    jclass this, jlong name)
+{
+    LPCWSTR lpName = (LPCWSTR)jlong_to_ptr(name);
+    PLUID pLuid = LocalAlloc(0, sizeof(LUID));
+
+    if (pLuid == NULL) {
+        JNU_ThrowInternalError(env, "Unable to allocate LUID structure");
+    } else {
+        if (LookupPrivilegeValueW(NULL, lpName, pLuid) == 0)
+            throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(pLuid);
 }
 
 JNIEXPORT jlong JNICALL
--- a/test/java/nio/channels/AsynchronousChannelGroup/Basic.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousChannelGroup/Basic.java	Tue Jun 24 20:05:07 2008 +0100
@@ -24,6 +24,8 @@
 /* @test
  * @bug 4607272
  * @summary Unit test for AsynchronousChannelGroup
+ * @build Basic
+ * @run main/othervm -XX:-UseVMInterruptibleIO Basic
  */
 
 import java.nio.channels.*;
@@ -33,21 +35,37 @@
 import java.io.IOException;
 
 public class Basic {
+    static final Random rand = new Random();
+
+    static final ThreadFactory threadFactory = new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(r);
+            return t;
+        }
+    };
 
     public static void main(String[] args) throws Exception {
-        test1();
-        test2();
-        test3();
-        test4();
+        shutdownTests();
+        shutdownNowTests();
+        afterShutdownTests();
+        miscTests();
     }
 
-    // exercise shutdown method
-    static void test1() throws Exception {
-        System.out.println("-- test1 --");
+    static void shutdownTests() throws Exception {
+        System.out.println("-- test shutdown --");
 
-         for (int i=0; i<500; i++) {
-            Map<String,?> params = Collections.emptyMap();
-            AsynchronousChannelGroup group = AsynchronousChannelGroup.open(params);
+        // test shutdown with no channels in groups
+        for (int i=0; i<500; i++) {
+            ExecutorService executor;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                executor = null;
+                group = AsynchronousChannelGroup.open(threadFactory, rand.nextInt(10));
+            } else {
+                executor = Executors.newFixedThreadPool(1 + rand.nextInt(9));
+                group = AsynchronousChannelGroup.open(executor);
+            }
             group.shutdown();
             if (!group.isShutdown())
                 throw new RuntimeException("Group should be shutdown");
@@ -55,11 +73,21 @@
             boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
             if (!terminated)
                 throw new RuntimeException("Group should have terminated");
+            if (executor != null && !executor.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
         }
 
+        // shutdown with channel in group
         for (int i=0; i<500; i++) {
-            Map<String,?> params = Collections.emptyMap();
-            AsynchronousChannelGroup group = AsynchronousChannelGroup.open(params);
+            ExecutorService executor;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                executor = null;
+                group = AsynchronousChannelGroup.open(threadFactory, rand.nextInt(10));
+            } else {
+                executor = Executors.newFixedThreadPool(1 + rand.nextInt(9));
+                group = AsynchronousChannelGroup.open(executor);
+            }
             // create channel that is bound to group
             AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
             group.shutdown();
@@ -73,22 +101,58 @@
             boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
             if (!terminated)
                 throw new RuntimeException("Group should have terminated");
+            if (executor != null && !executor.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
         }
+    }
 
+    static void shutdownNowTests() throws Exception {
+        System.out.println("-- test shutdownNow --");
+
+        for (int i=0; i< 10; i++) {
+            ExecutorService executor;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                executor = null;
+                group = AsynchronousChannelGroup.open(threadFactory, rand.nextInt(10));
+            } else {
+                executor = Executors.newFixedThreadPool(1 + rand.nextInt(9));
+                group = AsynchronousChannelGroup.open(executor);
+            }
+
+            // I/O in progress
+            AsynchronousServerSocketChannel listener =
+                AsynchronousServerSocketChannel.open(group)
+                    .bind(new InetSocketAddress(0));
+            listener.accept();
+
+            // forceful shutdown
+            group.shutdownNow();
+
+            // shutdownNow is required to close all channels
+            if (listener.isOpen())
+                throw new RuntimeException("Channel should be closed");
+
+            boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+            if (!terminated)
+                throw new RuntimeException("Group should have terminated");
+            if (executor != null && !executor.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
+        }
     }
 
     // test creating channels in group after group is shutdown
-    static void test2() throws Exception {
-        System.out.println("-- test2 --");
-        Map<String,?> params = Collections.emptyMap();
-        AsynchronousChannelGroup group = AsynchronousChannelGroup.open(params);
+    static void afterShutdownTests() throws Exception {
+        System.out.println("-- test operations after group is shutdown  --");
+        ExecutorService executor = Executors.newFixedThreadPool(1);
+        AsynchronousChannelGroup group = AsynchronousChannelGroup.open(executor);
 
         AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
         AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group);
 
         // initiate accept
         listener.bind(new InetSocketAddress(0));
-        IoFuture<AsynchronousSocketChannel,Void> result = listener.accept();
+        Future<AsynchronousSocketChannel> result = listener.accept();
 
         // shutdown group
         group.shutdown();
@@ -159,69 +223,17 @@
             throw new RuntimeException("Group should have terminated");
     }
 
-    // shutdownNow tests
-    static void test3() throws Exception {
-        System.out.println("-- test3 --");
-        Map<String,?> params = Collections.emptyMap();
-        AsynchronousChannelGroup group = AsynchronousChannelGroup.open(params);
-
-        // I/O in progress
-        AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group)
-            .bind(new InetSocketAddress(0));
-        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
-            public void completed(IoFuture<AsynchronousSocketChannel,Void> result) {
-                try {
-                    result.getNow();
-                } catch (Exception x) {
-                }
-            }
-        });
-
-        // forceful shutdown
-        group.shutdownNow();
-
-        // shutdownNow is required to close all channels
-        if (listener.isOpen())
-            throw new RuntimeException("Channel should be closed");
-
-        boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
-        if (!terminated)
-            throw new RuntimeException("Group should have terminated");
-    }
-
-    // custom thread pool
-    static void test4() throws Exception {
-        System.out.println("-- test4 --");
-
-        Map<String,Object> params = new HashMap<String,Object>();
-
-        // defaults
-        params.clear();
-        params.put("handlerPoolSize", -1);
-        params.put("maximumPoolSize", -1);
-        AsynchronousChannelGroup.open(params).shutdown();
-
-        // ThreadFactory + mix of Integer and String
-        params.clear();
-        ThreadFactory factory = new ThreadFactory() {
-            public Thread newThread(Runnable r) {
-                Thread t = new Thread(r);
-                t.setDaemon(true);
-                return t;
-            }
-        };
-        params.put("threadFactory", factory);
-        params.put("handlerPoolSize", 4);
-        params.put("maximumPoolSize", "8");
-        AsynchronousChannelGroup.open(params).shutdown();
-
-        // Invalid case
-        params.clear();
-        params.put("threadFactory", "rubbish");
+    static void miscTests() throws Exception {
+        System.out.println("-- miscellenous tests --");
         try {
-            AsynchronousChannelGroup.open(params);
-            throw new RuntimeException("IllegalArgumentException expected");
-        } catch (IllegalArgumentException x) {
+            AsynchronousChannelGroup.open(null);
+            throw new RuntimeException("NPE expected");
+        } catch (NullPointerException x) {
+        }
+        try {
+            AsynchronousChannelGroup.open(null, 100);
+            throw new RuntimeException("NPE expected");
+        } catch (NullPointerException x) {
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/channels/AsynchronousChannelGroup/Restart.java	Tue Jun 24 20:05:07 2008 +0100
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ * @build Restart
+ * @run main/othervm -XX:-UseVMInterruptibleIO Restart
+ */
+
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+import java.io.IOException;
+
+/**
+ * Exercise replacement of threads in the thread pool when completion handlers
+ * terminate due to errors or runtime exceptions.
+ */
+
+public class Restart {
+    static final Random rand = new Random();
+
+    public static void main(String[] args) throws Exception {
+        // thread group for thread pools
+        final ThreadGroup tg = new ThreadGroup("test");
+
+        // keep track of the number of threads that terminate
+        final AtomicInteger exceptionCount = new AtomicInteger(0);
+        final Thread.UncaughtExceptionHandler ueh =
+            new Thread.UncaughtExceptionHandler() {
+                public void uncaughtException(Thread t, Throwable e) {
+                    exceptionCount.incrementAndGet();
+                }
+            };
+        ThreadFactory factory = new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(tg, r);
+                t.setUncaughtExceptionHandler(ueh);
+                return t;
+            }
+        };
+
+        // group with user supplied thread pool
+        ExecutorService executor = Executors
+            .newFixedThreadPool(1 + rand.nextInt(4), factory);
+        AsynchronousChannelGroup group = AsynchronousChannelGroup.open(executor);
+        testRestart(group, 100);
+        group.shutdown();
+
+        // group with thread pool created automatically
+        group = AsynchronousChannelGroup.open(factory, rand.nextInt(5));
+        testRestart(group, 100);
+        group.shutdown();
+
+        // give time for threads to terminate
+        Thread.sleep(3000);
+        int actual = exceptionCount.get();
+        if (actual != 200)
+            throw new RuntimeException(actual + " exceptions, expected: " + 200);
+    }
+
+    static void testRestart(AsynchronousChannelGroup group, int count)
+        throws Exception
+    {
+        AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open(group)
+                .bind(new InetSocketAddress(0));
+
+        for (int i=0; i<count; i++) {
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+                public void completed(AsynchronousSocketChannel ch, Void att) {
+                    try {
+                        ch.close();
+                    } catch (IOException ignore) { }
+
+                    latch.countDown();
+
+                    // throw error or runtime exception
+                    if (rand.nextBoolean()) {
+                        throw new Error();
+                    } else {
+                        throw new RuntimeException();
+                    }
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
+            });
+
+            // establish loopback connection which should cause completion
+            // handler to be invoked.
+            int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+            InetAddress lh = InetAddress.getLocalHost();
+            ch.connect(new InetSocketAddress(lh, port)).get();
+            ch.close();
+
+            // wait for handler to be invoked
+            latch.await();
+        }
+
+        // clean-up
+        listener.close();
+    }
+}
--- a/test/java/nio/channels/AsynchronousFileChannel/Basic.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousFileChannel/Basic.java	Tue Jun 24 20:05:07 2008 +0100
@@ -98,10 +98,10 @@
 
     /*
      * Generate buffer with random contents
-     * Writes buffer to file, invoking the IoFuture's get method to wait for
+     * Writes buffer to file, invoking the Future's get method to wait for
      *    each write operation to complete
-     * Reads file to EOF to a new buffer, invoking the IoFuture's get method to
-          wait for each write operation to complete
+     * Reads file to EOF to a new buffer, invoking the Future's get method to
+     *    wait for each write operation to complete
      * Compares buffer contents
      */
     static void testUsingWaitOnResult(AsynchronousFileChannel ch)
@@ -117,7 +117,7 @@
         // write buffer completely to file
         long position = 0L;
         while (src.hasRemaining()) {
-            IoFuture<Integer,Void> result = ch.write(src, position);
+            Future<Integer> result = ch.write(src, position);
             try {
                 int n = result.get();
                 // update position
@@ -136,7 +136,7 @@
         position = 0L;
         int n;
         do {
-            IoFuture<Integer,Void> result = ch.read(dst, position);
+            Future<Integer> result = ch.read(dst, position);
             try {
                 n = result.get();
 
@@ -188,7 +188,11 @@
             throw new RuntimeException("Unable to acquire lock");
         try {
             ch.lock(null, new CompletionHandler<FileLock,Void> () {
-                public void completed(IoFuture<FileLock,Void> result) {
+                public void completed(FileLock result, Void att) {
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
                 }
             });
             throw new RuntimeException("OverlappingFileLockException expected");
@@ -205,9 +209,8 @@
         final CountDownLatch latch = new CountDownLatch(1);
 
         ch.read(buf, 0L, null, new CompletionHandler<Integer,Void>() {
-            public void completed(IoFuture<Integer,Void> result) {
+            public void completed(Integer result, Void att) {
                 try {
-                    int n = result.getNow();
                     Thread.currentThread().interrupt();
                     long size = ch.size();
                     latch.countDown();
@@ -215,6 +218,10 @@
                     x.printStackTrace();
                 }
             }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
         });
 
         // wait for handler to complete
@@ -280,23 +287,24 @@
                  return t;
              }
         };
+        ExecutorService executor = Executors.newFixedThreadPool(2, threadFactory);
 
         Set<StandardOpenOption> opts = EnumSet.of(WRITE);
-
-        Map<String,Object> params = new HashMap<String,Object>();
-        params.put("threadFactory", threadFactory);
-
-        AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, params);
+        AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, executor);
 
         // do I/O operation to see which thread invokes the completion handler
         final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
         final CountDownLatch latch = new CountDownLatch(1);
 
         ch.write(genBuffer(), 0L, null, new CompletionHandler<Integer,Void>() {
-            public void completed(IoFuture<Integer,Void> result) {
+            public void completed(Integer result, Void att) {
                 invoker.set(Thread.currentThread());
                 latch.countDown();
             }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
         });
         await(latch);
 
@@ -346,7 +354,7 @@
         }
 
         // initiate I/O
-        IoFuture[] result = new IoFuture[nwriters];
+        Future[] result = new Future[nwriters];
         for (int i=0; i<nwriters; i++) {
             result[i] = ch.write(buf[i], position[i]);
         }
@@ -395,20 +403,19 @@
 
         // use position as attachment
         ch.write(src, position, position, new CompletionHandler<Integer,Long>() {
-            public void completed(IoFuture<Integer,Long> result) {
-                try {
-                    int n = result.getNow();
-                    if (src.hasRemaining()) {
-                        long p = result.attachment() + n;
-                        ch.write(src, p, p, this);
-                    } else {
-                        latch.countDown();
-                    }
-                } catch (IOException x) {
+            public void completed(Integer result, Long position) {
+                int n = result;
+                if (src.hasRemaining()) {
+                    long p = position + n;
+                    ch.write(src, p, p, this);
+                } else {
                     latch.countDown();
-                    throw new Error(x);
                 }
             }
+            public void failed(Throwable exc, Long position) {
+            }
+            public void cancelled(Long position) {
+            }
         });
 
         // wait for writes to complete
@@ -423,20 +430,19 @@
 
         // use position as attachment
         ch.read(dst, position, position, new CompletionHandler<Integer,Long>() {
-            public void completed(IoFuture<Integer,Long> result) {
-                try {
-                    int n = result.getNow();
-                    if (n > 0) {
-                        long p = result.attachment() + n;
-                        ch.read(dst, p, p, this);
-                    } else {
-                        latch.countDown();
-                    }
-                } catch (IOException x) {
+            public void completed(Integer result, Long position) {
+                int n = result;
+                if (n > 0) {
+                    long p = position + n;
+                    ch.read(dst, p, p, this);
+                } else {
                     latch.countDown();
-                    throw new Error(x);
                 }
             }
+            public void failed(Throwable exc, Long position) {
+            }
+            public void cancelled(Long position) {
+            }
         });
 
         // wait for reads to complete
--- a/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java	Tue Jun 24 20:05:07 2008 +0100
@@ -29,7 +29,6 @@
  */
 
 import java.io.File;
-import java.nio.file.StandardOpenOption;
 import static java.nio.file.StandardOpenOption.*;
 import java.nio.ByteBuffer;
 import java.nio.channels.*;
@@ -47,8 +46,12 @@
         final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
         ch.write(src, 0, invoker,
             new CompletionHandler<Integer,AtomicReference<Thread>>() {
-                public void completed(IoFuture<Integer,AtomicReference<Thread>> result) {
-                    result.attachment().set(Thread.currentThread());
+                public void completed(Integer result, AtomicReference<Thread> invoker) {
+                    invoker.set(Thread.currentThread());
+                }
+                public void failed(Throwable exc, AtomicReference<Thread> invoker) {
+                }
+                public void cancelled(AtomicReference<Thread> invoker) {
                 }
             });
         Thread t;
--- a/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Tue Jun 24 20:05:07 2008 +0100
@@ -31,6 +31,7 @@
 import java.net.*;
 import java.io.IOException;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicReference;
 
 public class Basic {
@@ -95,13 +96,15 @@
 
         // start accepting
         listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
-            public void completed(IoFuture<AsynchronousSocketChannel,Void> result) {
+            public void completed(AsynchronousSocketChannel ch, Void att) {
                 try {
-                    AsynchronousSocketChannel ch = result.getNow();
                     ch.close();
-                } catch (IOException x) {
-                    exception.set(x);
-                }
+                } catch (IOException ignore) { }
+            }
+            public void failed(Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
             }
         });
 
--- a/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java	Tue Jun 24 20:05:07 2008 +0100
@@ -32,7 +32,7 @@
 import java.nio.file.Path;
 import java.nio.channels.*;
 import java.net.*;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.*;
 
 public class WithSecurityManager {
     public static void main(String[] args) throws Exception {
@@ -56,7 +56,7 @@
 
         // establish and accept connection
         SocketChannel sc = SocketChannel.open(new InetSocketAddress(lh, port));
-        IoFuture<AsynchronousSocketChannel,Void> result = listener.accept();
+        Future<AsynchronousSocketChannel> result = listener.accept();
 
         if (allow) {
             // no security exception
--- a/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Tue Jun 24 20:05:07 2008 +0100
@@ -262,19 +262,18 @@
         ch = AsynchronousSocketChannel.open();
         ch.connect(server.address()).get();
 
-        final AtomicReference<Exception> writeException =
-            new AtomicReference<Exception>();
+        final AtomicReference<Throwable> writeException =
+            new AtomicReference<Throwable>();
 
         // write bytes to fill socket buffer
         ch.write(genBuffer(), ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() {
-            public void completed(IoFuture<Integer,AsynchronousSocketChannel> result) {
-                try {
-                    int n = result.getNow();
-                    AsynchronousSocketChannel ch = result.attachment();
-                    ch.write(genBuffer(), ch, this);
-                } catch (Exception x) {
-                    writeException.set(x);
-                }
+            public void completed(Integer result, AsynchronousSocketChannel ch) {
+                ch.write(genBuffer(), ch, this);
+            }
+            public void failed(Throwable x, AsynchronousSocketChannel ch) {
+                writeException.set(x);
+            }
+            public void cancelled(AsynchronousSocketChannel ch) {
             }
         });
 
@@ -317,9 +316,13 @@
             // start read operation
             final CountDownLatch latch = new CountDownLatch(1);
             ByteBuffer buf = ByteBuffer.allocate(1);
-            IoFuture<Integer,Void> res = ch.read(buf, null,
+            Future<Integer> res = ch.read(buf, null,
                 new CompletionHandler<Integer,Void>() {
-                    public void completed(IoFuture<Integer,Void> result) {
+                    public void completed(Integer result, Void att) {
+                    }
+                    public void failed(Throwable exc, Void att) {
+                    }
+                    public void cancelled(Void att) {
                         latch.countDown();
                     }
             });
@@ -342,20 +345,12 @@
                 throw new RuntimeException("CancellationException expected");
             } catch (CancellationException x) {
             }
-            try {
-                res.getNow();
-                throw new RuntimeException("CancellationException expected");
-            } catch (CancellationException x) {
-            }
+
+            // check that completion handler executed.
+            latch.await();
 
             ch.close();
             peer.close();
-
-            // check that completion handler didn't execute. We check after
-            // the connection is closed to ensure that closing the channel
-            // doesn't cause the handler to execute.
-            if (latch.await(2, TimeUnit.SECONDS))
-                throw new RuntimeException("Completion handler executed");
         }
 
         server.close();
@@ -387,18 +382,18 @@
         final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
         final CountDownLatch latch = new CountDownLatch(1);
         ch.read(dst, null, new CompletionHandler<Integer,Void>() {
-            public void completed(IoFuture<Integer,Void> result) {
-                try {
-                    int n = result.getNow();
-                    if (n > 0) {
-                        ch.read(dst, null, this);
-                    } else {
-                        latch.countDown();
-                    }
-                } catch (IOException x) {
-                    x.printStackTrace();
+            public void completed(Integer result, Void att) {
+                int n = result;
+                if (n > 0) {
+                    ch.read(dst, null, this);
+                } else {
+                    latch.countDown();
                 }
             }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
         });
 
         latch.await();
@@ -440,18 +435,17 @@
         final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity());
         final CountDownLatch latch = new CountDownLatch(1);
         ch.read(dst, null, new CompletionHandler<Integer,Void>() {
-            public void completed(IoFuture<Integer,Void> result) {
-                try {
-                    int n = result.getNow();
-                    if (dst.hasRemaining()) {
-                        ch.read(dst, null, this);
-                    } else {
-                        latch.countDown();
-                    }
-                } catch (IOException x) {
-                    x.printStackTrace();
+            public void completed(Integer result, Void att) {
+                if (dst.hasRemaining()) {
+                    ch.read(dst, null, this);
+                } else {
+                    latch.countDown();
                 }
             }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
         });
 
         // trickle the writing
@@ -500,15 +494,15 @@
         final CountDownLatch latch = new CountDownLatch(1);
         ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null,
             new CompletionHandler<Long,Void>() {
-                public void completed(IoFuture<Long,Void> result) {
-                    try {
-                        long n = result.getNow();
-                        if (n <= 0)
-                            throw new RuntimeException("No bytes read");
-                        latch.countDown();
-                    } catch (IOException x) {
-                        x.printStackTrace();
-                    }
+                public void completed(Long result, Void att) {
+                    long n = result;
+                    if (n <= 0)
+                        throw new RuntimeException("No bytes read");
+                    latch.countDown();
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
                 }
         });
 
@@ -553,18 +547,19 @@
         // write all bytes and close connection when done
         final ByteBuffer src = genBuffer();
         ch.write(src, null, new CompletionHandler<Integer,Void>() {
-            public void completed(IoFuture<Integer,Void> result) {
-                try {
-                    int n = result.getNow();
-                    if (src.hasRemaining()) {
-                        ch.write(src, null, this);
-                    } else {
+            public void completed(Integer result, Void att) {
+                if (src.hasRemaining()) {
+                    ch.write(src, null, this);
+                } else {
+                    try {
                         ch.close();
-                    }
-                } catch (Exception x) {
-                    x.printStackTrace();
+                    } catch (IOException ignore) { }
                 }
             }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
         });
 
         // read to EOF or buffer full
@@ -620,21 +615,21 @@
         srcs = genBuffers(1);
         ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null,
             new CompletionHandler<Long,Void>() {
-                public void completed(IoFuture<Long,Void> result) {
-                    try {
-                        long n = result.getNow();
-                        if (n <= 0)
-                            throw new RuntimeException("No bytes written");
-                        bytesWritten.addAndGet(n);
-                        if (continueWriting.get()) {
-                            ByteBuffer[] srcs = genBuffers(8);
-                            ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS,
-                                null, this);
-                        }
-                    } catch (IOException x) {
-                        x.printStackTrace();
+                public void completed(Long result, Void att) {
+                    long n = result;
+                    if (n <= 0)
+                        throw new RuntimeException("No bytes written");
+                    bytesWritten.addAndGet(n);
+                    if (continueWriting.get()) {
+                        ByteBuffer[] srcs = genBuffers(8);
+                        ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS,
+                            null, this);
                     }
                 }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
         });
 
         // give time for socket buffer to fill up.
@@ -726,7 +721,7 @@
 
         System.out.println("-- timeout when writing --");
 
-        final AtomicReference<Exception> writeException = new AtomicReference<Exception>();
+        final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
 
         final long timeout = 5;
         final TimeUnit unit = TimeUnit.SECONDS;
@@ -735,14 +730,13 @@
         ch.write(genBuffer(), timeout, unit, ch,
             new CompletionHandler<Integer,AsynchronousSocketChannel>()
         {
-            public void completed(IoFuture<Integer,AsynchronousSocketChannel> result) {
-                try {
-                    int n = result.getNow();
-                    AsynchronousSocketChannel ch = result.attachment();
-                    ch.write(genBuffer(), timeout, unit, ch, this);
-                } catch (IOException x) {
-                    writeException.set(x);
-                }
+            public void completed(Integer result, AsynchronousSocketChannel ch) {
+                ch.write(genBuffer(), timeout, unit, ch, this);
+            }
+            public void failed(Throwable exc, AsynchronousSocketChannel ch) {
+                writeException.set(exc);
+            }
+            public void cancelled(AsynchronousSocketChannel ch) {
             }
         });
 
--- a/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java	Tue Jun 24 20:05:07 2008 +0100
@@ -24,7 +24,8 @@
 import java.nio.channels.spi.AsynchronousChannelProvider;
 import java.nio.channels.*;
 import java.net.ProtocolFamily;
-import java.util.Map;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ExecutorService;
 import java.io.IOException;
 
 public class Provider1 extends AsynchronousChannelProvider {
@@ -33,7 +34,14 @@
 
     @Override
     public AsynchronousChannelGroup openAsynchronousChannelGroup
-        (Map<String,?> params) throws IOException
+        (ThreadFactory factory, int initialPoolSize) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup
+        (ExecutorService executor) throws IOException
     {
         throw new RuntimeException();
     }
--- a/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java	Tue Jun 24 20:05:07 2008 +0100
@@ -24,7 +24,8 @@
 import java.nio.channels.spi.AsynchronousChannelProvider;
 import java.nio.channels.*;
 import java.net.ProtocolFamily;
-import java.util.Map;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ExecutorService;
 import java.io.IOException;
 
 public class Provider2 extends AsynchronousChannelProvider {
@@ -33,7 +34,14 @@
 
     @Override
     public AsynchronousChannelGroup openAsynchronousChannelGroup
-        (Map<String,?> params) throws IOException
+        (ThreadFactory factory, int initialPoolSize) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup
+        (ExecutorService executor) throws IOException
     {
         throw new RuntimeException();
     }
--- a/test/java/nio/file/DirectoryStream/SecureDS.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/file/DirectoryStream/SecureDS.java	Tue Jun 24 20:05:07 2008 +0100
@@ -35,6 +35,7 @@
 import java.util.*;
 
 public class SecureDS {
+    static boolean supportsLinks;
 
     public static void main(String[] args) throws IOException {
         Path dir = TestUtil.createTemporaryDirectory();
@@ -46,6 +47,8 @@
                 return;
             }
 
+            supportsLinks = TestUtil.supportsLinks(dir);
+
             // run tests
             doBasicTests(dir);
             doMoveTests(dir);
@@ -68,10 +71,12 @@
         dir1.resolve(dirEntry).createDirectory();
         // myfilelink -> myfile
         Path link1Entry = Path.get("myfilelink");
-        dir1.resolve(link1Entry).createSymbolicLink(fileEntry);
+        if (supportsLinks)
+            dir1.resolve(link1Entry).createSymbolicLink(fileEntry);
         // mydirlink -> mydir
         Path link2Entry = Path.get("mydirlink");
-        dir1.resolve(link2Entry).createSymbolicLink(dirEntry);
+        if (supportsLinks)
+            dir1.resolve(link2Entry).createSymbolicLink(dirEntry);
 
         // open directory and then move it so that it is no longer accessible
         // via its original path.
@@ -82,7 +87,7 @@
         // Test: iterate over all entries
         int count = 0;
         for (DirectoryEntry entry: stream) { count++; }
-        assertTrue(count == 4);
+        assertTrue(count == (supportsLinks ? 4 : 2));
 
         // Test: newFileAttributeView to access directory's attributes
         assertTrue(stream
@@ -107,22 +112,24 @@
             .newFileAttributeView(dirEntry, BasicFileAttributeView.class, false)
                 .readAttributes()
                     .isDirectory());
-        assertTrue(stream
-            .newFileAttributeView(link1Entry, BasicFileAttributeView.class, true)
-                .readAttributes()
-                    .isRegularFile());
-        assertTrue(stream
-            .newFileAttributeView(link1Entry, BasicFileAttributeView.class, false)
-                .readAttributes()
-                    .isSymbolicLink());
-        assertTrue(stream
-            .newFileAttributeView(link2Entry, BasicFileAttributeView.class, true)
-                .readAttributes()
-                    .isDirectory());
-        assertTrue(stream
-            .newFileAttributeView(link2Entry, BasicFileAttributeView.class, false)
-                .readAttributes()
-                    .isSymbolicLink());
+        if (supportsLinks) {
+            assertTrue(stream
+                .newFileAttributeView(link1Entry, BasicFileAttributeView.class, true)
+                    .readAttributes()
+                        .isRegularFile());
+            assertTrue(stream
+                .newFileAttributeView(link1Entry, BasicFileAttributeView.class, false)
+                    .readAttributes()
+                        .isSymbolicLink());
+            assertTrue(stream
+                .newFileAttributeView(link2Entry, BasicFileAttributeView.class, true)
+                    .readAttributes()
+                        .isDirectory());
+            assertTrue(stream
+                .newFileAttributeView(link2Entry, BasicFileAttributeView.class, false)
+                    .readAttributes()
+                        .isSymbolicLink());
+        }
 
         // Test: re-binding FileAttributeView to another object
         assertTrue(stream
@@ -134,25 +141,31 @@
         // Test: newSeekableByteChannel
         Set<StandardOpenOption> opts = Collections.emptySet();
         stream.newSeekableByteChannel(fileEntry, opts).close();
-        stream.newSeekableByteChannel(link1Entry, opts).close();
-        try {
-            stream.newSeekableByteChannel(link1Entry,
-                EnumSet.of(READ, NOFOLLOW_LINKS)).close();
-            shouldNotGetHere();
-        } catch (IOException x) { }
+        if (supportsLinks) {
+            stream.newSeekableByteChannel(link1Entry, opts).close();
+            try {
+                stream.newSeekableByteChannel(link1Entry,
+                    EnumSet.of(READ, NOFOLLOW_LINKS)).close();
+                shouldNotGetHere();
+            } catch (IOException x) { }
+        }
 
         // Test: newDirectoryStream
         stream.newDirectoryStream(dirEntry, true, null).close();
         stream.newDirectoryStream(dirEntry, false, null).close();
-        stream.newDirectoryStream(link2Entry, true, null).close();
-        try {
-            stream.newDirectoryStream(link2Entry, false, null).close();
-            shouldNotGetHere();
-        } catch (IOException x) { }
+        if (supportsLinks) {
+            stream.newDirectoryStream(link2Entry, true, null).close();
+            try {
+                stream.newDirectoryStream(link2Entry, false, null).close();
+                shouldNotGetHere();
+            } catch (IOException x) { }
+        }
 
         // Test: delete
-        stream.delete(link1Entry);
-        stream.delete(link2Entry);
+        if (supportsLinks) {
+            stream.delete(link1Entry);
+            stream.delete(link2Entry);
+        }
         stream.delete(dirEntry);
         stream.delete(fileEntry);
 
@@ -188,7 +201,8 @@
         Path dirEntry = Path.get("mydir");
         dir1.resolve(dirEntry).createDirectory();
         Path linkEntry = Path.get("mylink");
-        dir1.resolve(linkEntry).createSymbolicLink(Path.get("missing"));
+        if (supportsLinks)
+            dir1.resolve(linkEntry).createSymbolicLink(Path.get("missing"));
 
         // target name
         Path target = Path.get("newfile");
@@ -212,12 +226,14 @@
         stream2.delete(target);
 
         // Test: move dir1/mylink -> dir2/newfile
-        stream1.move(linkEntry, stream2, target);
-        assertTrue(dir2.resolve(target)
-            .newFileAttributeView(BasicFileAttributeView.class, false)
-            .readAttributes()
-            .isSymbolicLink());
-        stream2.delete(target);
+        if (supportsLinks) {
+            stream1.move(linkEntry, stream2, target);
+            assertTrue(dir2.resolve(target)
+                .newFileAttributeView(BasicFileAttributeView.class, false)
+                .readAttributes()
+                .isSymbolicLink());
+            stream2.delete(target);
+        }
 
         // Test: move between devices
         String testDirAsString = System.getProperty("test.dir");
--- a/test/java/nio/file/Path/CopyAndMove.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/file/Path/CopyAndMove.java	Tue Jun 24 20:05:07 2008 +0100
@@ -37,10 +37,12 @@
 public class CopyAndMove {
     static final Random rand = new Random();
     static boolean heads() { return rand.nextBoolean(); }
+    static boolean supportsLinks;
 
     public static void main(String[] args) throws Exception {
         Path dir1 = TestUtil.createTemporaryDirectory();
         try {
+            supportsLinks = TestUtil.supportsLinks(dir1);
 
             // Exercise copyTo
             doCopyTests(dir1);
@@ -208,19 +210,7 @@
     static void doMoveTests(Path dir1, Path dir2) throws IOException {
         Path source, target, entry;
 
-        boolean supportsLinks;
-        boolean sameDevice;
-
-        // setup
-        try {
-            Path link = dir1.resolve("link");
-            link.createSymbolicLink(link);
-            link.delete(true);
-            supportsLinks = true;
-        } catch (UnsupportedOperationException x) {
-            supportsLinks = false;
-        }
-        sameDevice = dir1.getFileStore().equals(dir2.getFileStore());
+        boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore());
 
         // -- regular file --
 
@@ -318,7 +308,7 @@
         /*
          * Test: move empty directory, target does not exist
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1);
         moveAndVerify(source, target);
         target.delete(true);
@@ -326,7 +316,7 @@
         /**
          * Test: move empty directory, target exists
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1).createFile();
         try {
             moveAndVerify(source, target);
@@ -346,7 +336,7 @@
         /**
          * Test: move empty directory, target does not exist
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1);
         moveAndVerify(source, target, REPLACE_EXISTING);
         target.delete(true);
@@ -354,7 +344,7 @@
         /**
          * Test: move empty directory, target exists
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1).createFile();
         moveAndVerify(source, target, REPLACE_EXISTING);
         target.delete(true);
@@ -362,7 +352,7 @@
         /**
          * Test: move empty, target exists and is empty directory
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1).createDirectory();
         moveAndVerify(source, target, REPLACE_EXISTING);
         target.delete(true);
@@ -370,7 +360,7 @@
         /**
          * Test: move empty directory, target exists and is non-empty directory
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         target = getTargetFile(dir1).createDirectory();
         entry = target.resolve("foo").createFile();
         try {
@@ -385,7 +375,7 @@
         /**
          * Test: move non-empty directory (same file system)
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         source.resolve("foo").createFile();
         target = getTargetFile(dir1);
         moveAndVerify(source, target);
@@ -396,7 +386,7 @@
          * Test: move non-empty directory (different file store)
          */
         if (!sameDevice) {
-            source = dir1.resolve("mydir").createDirectory();
+            source = createSourceDirectory(dir1);
             source.resolve("foo").createFile();
             target = getTargetFile(dir2);
             try {
@@ -411,7 +401,7 @@
         /**
          * Test atomic move of directory (same file store)
          */
-        source = dir1.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir1);
         source.resolve("foo").createFile();
         target = getTargetFile(dir1);
         moveAndVerify(source, target, ATOMIC_MOVE);
@@ -689,7 +679,7 @@
         /*
          * Test: copy directory, target does not exist
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir);
         copyAndVerify(source, target);
         source.delete(true);
@@ -698,7 +688,7 @@
         /**
          * Test: copy directory, target exists
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir).createFile();
         try {
             copyAndVerify(source, target);
@@ -718,7 +708,7 @@
         /**
          * Test: copy directory, target does not exist
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir);
         copyAndVerify(source, target, REPLACE_EXISTING);
         source.delete(true);
@@ -727,7 +717,7 @@
         /**
          * Test: copy directory, target exists
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir).createFile();
         copyAndVerify(source, target, REPLACE_EXISTING);
         source.delete(true);
@@ -736,7 +726,7 @@
         /**
          * Test: copy directory, target exists and is empty directory
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir).createDirectory();
         copyAndVerify(source, target, REPLACE_EXISTING);
         source.delete(true);
@@ -745,7 +735,7 @@
         /**
          * Test: copy directory, target exists and is non-empty directory
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir).createDirectory();
         entry = target.resolve("foo").createFile();
         try {
@@ -760,7 +750,7 @@
         /*
          * Test: copy directory + attributes
          */
-        source = dir.resolve("mydir").createDirectory();
+        source = createSourceDirectory(dir);
         target = getTargetFile(dir);
         copyAndVerify(source, target, COPY_ATTRIBUTES);
         source.delete(true);
@@ -771,66 +761,61 @@
         /**
          * Test: Follow link
          */
-        source = createSourceFile(dir);
-        try {
+        if (supportsLinks) {
+            source = createSourceFile(dir);
             link = dir.resolve("link").createSymbolicLink(source);
             target = getTargetFile(dir);
             copyAndVerify(link, target);
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
+            source.delete(true);
         }
-        source.delete(true);
 
         /**
          * Test: Copy link (to file)
          */
-        source = createSourceFile(dir);
-        try {
+        if (supportsLinks) {
+            source = createSourceFile(dir);
             link = dir.resolve("link").createSymbolicLink(source);
             target = getTargetFile(dir);
             copyAndVerify(link, target, NOFOLLOW_LINKS);
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
+            source.delete(true);
         }
-        source.delete(true);
 
         /**
          * Test: Copy link (to directory)
          */
-        source = dir.resolve("mydir").createDirectory();
-        try {
+        if (supportsLinks) {
+            source = dir.resolve("mydir").createDirectory();
             link = dir.resolve("link").createSymbolicLink(source);
             target = getTargetFile(dir);
             copyAndVerify(link, target, NOFOLLOW_LINKS);
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
+            source.delete(true);
         }
-        source.delete(true);
 
         /**
          * Test: Copy broken link
          */
-        try {
+        if (supportsLinks) {
             assertTrue(source.notExists());
             link = dir.resolve("link").createSymbolicLink(source);
             target = getTargetFile(dir);
             copyAndVerify(link, target, NOFOLLOW_LINKS);
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
         }
 
         /**
          * Test: Copy link to UNC (Windows only)
          */
-        if (System.getProperty("os.name").startsWith("Windows")) {
+        if (supportsLinks &&
+            System.getProperty("os.name").startsWith("Windows"))
+        {
             Path unc = Path.get("\\\\rialto\\share\\file");
-            try {
-                link = dir.resolve("link").createSymbolicLink(unc);
-                target = getTargetFile(dir);
-                copyAndVerify(link, target, NOFOLLOW_LINKS);
-                link.delete(true);
-            } catch (UnsupportedOperationException x) {
-            }
+            link = dir.resolve("link").createSymbolicLink(unc);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target, NOFOLLOW_LINKS);
+            link.delete(true);
         }
 
         // -- misc. tests --
@@ -894,11 +879,27 @@
         } finally {
             out.close();
         }
+        randomizeAttributes(file);
+        return file;
+    }
 
-        // randomize its attributes
+    // create directory in the given directory
+    static Path createSourceDirectory(Path dir) throws IOException {
+        String name = "sourcedir" + Integer.toString(rand.nextInt());
+        Path subdir = dir.resolve(name).createDirectory();
+        randomizeAttributes(subdir);
+        return subdir;
+    }
 
+    // "randomize" the file attributes of the given file.
+    static void randomizeAttributes(Path file) throws IOException {
         String os = System.getProperty("os.name");
-        if (os.equals("SunOS") || os.equals("Linux")) {
+        boolean isWindows = os.startsWith("Windows");
+        boolean isUnix = os.equals("SunOS") || os.equals("Linux");
+        boolean isDirectory = Attributes.readBasicFileAttributes(file, false)
+            .isDirectory();
+
+        if (isUnix) {
             Set<PosixFilePermission> perms = Attributes
                 .readPosixFileAttributes(file, false).permissions();
             PosixFilePermission[] toChange = {
@@ -919,16 +920,20 @@
             Attributes.setPosixFilePermissions(file, perms);
         }
 
-        if (os.startsWith("Windows")) {
+        if (isWindows) {
             DosFileAttributeView view = file
                 .newFileAttributeView(DosFileAttributeView.class, false);
             // only set or unset the hidden attribute
             view.setHidden(heads());
         }
 
-        if (heads() &&
-            file.getFileStore().supportsFileAttributeView(NamedAttributeView.class))
-        {
+        boolean addNamedAttributes = heads() &&
+            file.getFileStore().supportsFileAttributeView(NamedAttributeView.class);
+
+        // remove this when copying a direcory copies its named streams
+        if (isWindows && isDirectory) addNamedAttributes = false;
+
+        if (addNamedAttributes) {
             NamedAttributeView view = file
                 .newFileAttributeView(NamedAttributeView.class, true);
             int n = rand.nextInt(16);
@@ -938,8 +943,6 @@
                 n--;
             }
         }
-
-        return file;
     }
 
     // create name for file in given directory
--- a/test/java/nio/file/Path/Misc.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/file/Path/Misc.java	Tue Jun 24 20:05:07 2008 +0100
@@ -36,10 +36,12 @@
 public class Misc {
     static final boolean isWindows =
         System.getProperty("os.name").startsWith("Windows");
+    static boolean supportsLinks;
 
     public static void main(String[] args) throws IOException {
         Path dir = TestUtil.createTemporaryDirectory();
         try {
+            supportsLinks = TestUtil.supportsLinks(dir);
 
             // equals and hashCode methods
             equalsAndHashCode();
@@ -202,22 +204,20 @@
         /**
          * Test: toRealPath(true) should resolve links
          */
-        try {
+        if (supportsLinks) {
             link.createSymbolicLink(file.toAbsolutePath());
             assertTrue(link.toRealPath(true).equals(file.toRealPath(true)));
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
         }
 
 
         /**
          * Test: toRealPath(false) should not resolve links
          */
-        try {
+        if (supportsLinks) {
             link.createSymbolicLink(file.toAbsolutePath());
             assertTrue(link.toRealPath(false).getName().equals(link.getName()));
             link.delete(true);
-        } catch (UnsupportedOperationException x) {
         }
 
         /**
@@ -297,18 +297,14 @@
             /**
              * Test: Symbolic links
              */
-            try {
+            if (supportsLinks) {
                 thatFile.createSymbolicLink(thisFile);
-            } catch (UnsupportedOperationException x) {
-                return;
-            } catch (IOException x) {
-                return;
-            }
-            try {
-                assertTrue(thisFile.isSameFile(thatFile));
-                assertTrue(thatFile.isSameFile(thisFile));
-            } finally {
-                thatFile.delete(false);
+                try {
+                    assertTrue(thisFile.isSameFile(thatFile));
+                    assertTrue(thatFile.isSameFile(thisFile));
+                } finally {
+                    thatFile.delete(false);
+                }
             }
 
         } finally {
--- a/test/java/nio/file/Path/SBC.java	Tue Jun 24 18:30:03 2008 +0100
+++ b/test/java/nio/file/Path/SBC.java	Tue Jun 24 20:05:07 2008 +0100
@@ -37,9 +37,13 @@
 
 public class SBC {
 
+    static boolean supportsLinks;
+
     public static void main(String[] args) throws Exception {
         Path dir = TestUtil.createTemporaryDirectory();
         try {
+            supportsLinks = TestUtil.supportsLinks(dir);
+
             // open options
             createTests(dir);
             appendTests(dir);
@@ -73,9 +77,8 @@
             file.newSeekableByteChannel(CREATE, WRITE).close();
 
             // create file where existing file is a sym link
-            Path link = dir.resolve("link");
-            try {
-                link.createSymbolicLink(file);
+            if (supportsLinks) {
+                Path link = dir.resolve("link").createSymbolicLink(file);
                 try {
                     // file already exists
                     link.newSeekableByteChannel(CREATE, WRITE).close();
@@ -89,7 +92,6 @@
                 } finally {