Merge
authorjwilhelm
Mon, 29 Feb 2016 15:42:34 +0000
changeset 36377 be8afc1274ff
parent 36375 d96a3220c7bb (current diff)
parent 36376 04e40b474cc5 (diff)
child 36378 d63bca5c1439
child 36379 0c596dc28ed7
child 36381 b9ed6bef9364
Merge
jdk/src/java.base/share/native/libjava/Bits.c
langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/LinePrefixFilterWriter.java
langtools/test/tools/javac/6521805/T6521805a.java
langtools/test/tools/javac/6521805/T6521805a_1.out
langtools/test/tools/javac/6521805/T6521805a_2.out
langtools/test/tools/javac/diags/examples/WarnSyntheticNameConflict.java
--- a/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 086c682bd8c5f195c324f61e2c61fbcd0226d63b jdk-9+104
 db483b34fa7148d257a429acddbde9c13687dcae jdk-9+105
 6c644cca3f3fc2763e2ff7d669849a75d34543ba jdk-9+106
+1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 jdk-9+107
--- a/.hgtags-top-repo	Fri Feb 26 16:28:42 2016 +0100
+++ b/.hgtags-top-repo	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 9a38f8b4ba220708db198d08d82fd2144a64777d jdk-9+104
 be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105
 54575d8783b3a39a2d710c28cda675d44261f9d9 jdk-9+106
+4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107
--- a/common/autoconf/flags.m4	Fri Feb 26 16:28:42 2016 +0100
+++ b/common/autoconf/flags.m4	Mon Feb 29 15:42:34 2016 +0000
@@ -123,12 +123,16 @@
 [
   # COMPILER_TARGET_BITS_FLAG  : option for selecting 32- or 64-bit output
   # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
+  # COMPILER_BINDCMD_FILE_FLAG : option for specifying a file which saves the binder
+  #                              commands produced by the link step (currently AIX only)
   if test "x$TOOLCHAIN_TYPE" = xxlc; then
     COMPILER_TARGET_BITS_FLAG="-q"
     COMPILER_COMMAND_FILE_FLAG="-f"
+    COMPILER_BINDCMD_FILE_FLAG="-bloadmap:"
   else
     COMPILER_TARGET_BITS_FLAG="-m"
     COMPILER_COMMAND_FILE_FLAG="@"
+    COMPILER_BINDCMD_FILE_FLAG=""
 
     # The solstudio linker does not support @-files.
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
@@ -152,6 +156,7 @@
   fi
   AC_SUBST(COMPILER_TARGET_BITS_FLAG)
   AC_SUBST(COMPILER_COMMAND_FILE_FLAG)
+  AC_SUBST(COMPILER_BINDCMD_FILE_FLAG)
 
   # FIXME: figure out if we should select AR flags depending on OS or toolchain.
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
@@ -294,10 +299,23 @@
     SET_SHARED_LIBRARY_NAME='-h [$]1'
     SET_SHARED_LIBRARY_MAPFILE='-M[$]1'
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    PICFLAG="-qpic=large"
+    # '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
+    # one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
+    # will have to patch this single instruction with a call to some out-of-order code which
+    # does the load from the TOC. This is of course slow. But in that case we also would have
+    # to use '-bbigtoc' for linking anyway so we could also change the PICFLAG to 'qpic=large'.
+    # With 'qpic=large' the compiler will by default generate a two-instruction sequence which
+    # can be patched directly by the linker and does not require a jump to out-of-order code.
+    # Another alternative instead of using 'qpic=large -bbigtoc' may be to use '-qminimaltoc'
+    # instead. This creates a distinct TOC for every compilation unit (and thus requires two
+    # loads for accessing a global variable). But there are rumors that this may be seen as a
+    # 'performance feature' because of improved code locality of the symbols used in a
+    # compilation unit.
+    PICFLAG="-qpic"
+    JVM_CFLAGS="$JVM_CFLAGS $PICFLAG"
     C_FLAG_REORDER=''
     CXX_FLAG_REORDER=''
-    SHARED_LIBRARY_FLAGS="-qmkshrobj"
+    SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
     SET_EXECUTABLE_ORIGIN=""
     SET_SHARED_LIBRARY_ORIGIN=''
     SET_SHARED_LIBRARY_NAME=''
@@ -835,7 +853,7 @@
     LDFLAGS_CXX_SOLSTUDIO="-norunpath"
     LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib"
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    LDFLAGS_XLC="-brtl -bnolibpath -bexpall -bernotok"
+    LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok"
     LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC"
   fi
 
@@ -891,6 +909,7 @@
   AC_SUBST(JDKLIB_LIBS)
   AC_SUBST(JDKEXE_LIBS)
   AC_SUBST(LDFLAGS_CXX_JDK)
+  AC_SUBST(LDFLAGS_HASH_STYLE)
 
   LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB"
   LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE"
--- a/common/autoconf/generated-configure.sh	Fri Feb 26 16:28:42 2016 +0100
+++ b/common/autoconf/generated-configure.sh	Mon Feb 29 15:42:34 2016 +0000
@@ -701,6 +701,7 @@
 ZERO_ARCHFLAG
 LDFLAGS_TESTEXE
 LDFLAGS_TESTLIB
+LDFLAGS_HASH_STYLE
 LDFLAGS_CXX_JDK
 JDKEXE_LIBS
 JDKLIB_LIBS
@@ -743,6 +744,7 @@
 CC_OUT_OPTION
 STRIPFLAGS
 ARFLAGS
+COMPILER_BINDCMD_FILE_FLAG
 COMPILER_COMMAND_FILE_FLAG
 COMPILER_TARGET_BITS_FLAG
 JT_HOME
@@ -4230,7 +4232,7 @@
 
 
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -4860,7 +4862,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1455271513
+DATE_WHEN_GENERATED=1456136781
 
 ###############################################################################
 #
@@ -45391,12 +45393,16 @@
 
   # COMPILER_TARGET_BITS_FLAG  : option for selecting 32- or 64-bit output
   # COMPILER_COMMAND_FILE_FLAG : option for passing a command file to the compiler
+  # COMPILER_BINDCMD_FILE_FLAG : option for specifying a file which saves the binder
+  #                              commands produced by the link step (currently AIX only)
   if test "x$TOOLCHAIN_TYPE" = xxlc; then
     COMPILER_TARGET_BITS_FLAG="-q"
     COMPILER_COMMAND_FILE_FLAG="-f"
+    COMPILER_BINDCMD_FILE_FLAG="-bloadmap:"
   else
     COMPILER_TARGET_BITS_FLAG="-m"
     COMPILER_COMMAND_FILE_FLAG="@"
+    COMPILER_BINDCMD_FILE_FLAG=""
 
     # The solstudio linker does not support @-files.
     if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
@@ -45424,6 +45430,7 @@
 
 
 
+
   # FIXME: figure out if we should select AR flags depending on OS or toolchain.
   if test "x$OPENJDK_TARGET_OS" = xmacosx; then
     ARFLAGS="-r"
@@ -46198,10 +46205,23 @@
     SET_SHARED_LIBRARY_NAME='-h $1'
     SET_SHARED_LIBRARY_MAPFILE='-M$1'
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    PICFLAG="-qpic=large"
+    # '-qpic' defaults to 'qpic=small'. This means that the compiler generates only
+    # one instruction for accessing the TOC. If the TOC grows larger than 64K, the linker
+    # will have to patch this single instruction with a call to some out-of-order code which
+    # does the load from the TOC. This is of course slow. But in that case we also would have
+    # to use '-bbigtoc' for linking anyway so we could also change the PICFLAG to 'qpic=large'.
+    # With 'qpic=large' the compiler will by default generate a two-instruction sequence which
+    # can be patched directly by the linker and does not require a jump to out-of-order code.
+    # Another alternative instead of using 'qpic=large -bbigtoc' may be to use '-qminimaltoc'
+    # instead. This creates a distinct TOC for every compilation unit (and thus requires two
+    # loads for accessing a global variable). But there are rumors that this may be seen as a
+    # 'performance feature' because of improved code locality of the symbols used in a
+    # compilation unit.
+    PICFLAG="-qpic"
+    JVM_CFLAGS="$JVM_CFLAGS $PICFLAG"
     C_FLAG_REORDER=''
     CXX_FLAG_REORDER=''
-    SHARED_LIBRARY_FLAGS="-qmkshrobj"
+    SHARED_LIBRARY_FLAGS="-qmkshrobj -bM:SRE -bnoentry"
     SET_EXECUTABLE_ORIGIN=""
     SET_SHARED_LIBRARY_ORIGIN=''
     SET_SHARED_LIBRARY_NAME=''
@@ -46824,7 +46844,7 @@
     LDFLAGS_CXX_SOLSTUDIO="-norunpath"
     LDFLAGS_CXX_JDK="$LDFLAGS_CXX_JDK $LDFLAGS_CXX_SOLSTUDIO -xnolib"
   elif test "x$TOOLCHAIN_TYPE" = xxlc; then
-    LDFLAGS_XLC="-brtl -bnolibpath -bexpall -bernotok"
+    LDFLAGS_XLC="-b64 -brtl -bnolibpath -bexpall -bernotok"
     LDFLAGS_JDK="${LDFLAGS_JDK} $LDFLAGS_XLC"
   fi
 
@@ -46881,6 +46901,7 @@
 
 
 
+
   LDFLAGS_TESTLIB="$LDFLAGS_JDKLIB"
   LDFLAGS_TESTEXE="$LDFLAGS_JDKEXE"
 
@@ -58630,7 +58651,8 @@
 
 
   # Setup libm (the maths library)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
+  if test "x$OPENJDK_TARGET_OS" != "xwindows"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
 $as_echo_n "checking for cos in -lm... " >&6; }
 if ${ac_cv_lib_m_cos+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -58675,12 +58697,15 @@
 
 else
 
-      { $as_echo "$as_me:${as_lineno-$LINENO}: Maths library was not found" >&5
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Maths library was not found" >&5
 $as_echo "$as_me: Maths library was not found" >&6;}
 
 fi
 
-  LIBM=-lm
+    LIBM="-lm"
+  else
+    LIBM=""
+  fi
 
 
   # Setup libdl (for dynamic library loading)
--- a/common/autoconf/libraries.m4	Fri Feb 26 16:28:42 2016 +0100
+++ b/common/autoconf/libraries.m4	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -160,10 +160,14 @@
 AC_DEFUN_ONCE([LIB_SETUP_MISC_LIBS],
 [
   # Setup libm (the maths library)
-  AC_CHECK_LIB(m, cos, [], [
-      AC_MSG_NOTICE([Maths library was not found])
-  ])
-  LIBM=-lm
+  if test "x$OPENJDK_TARGET_OS" != "xwindows"; then
+    AC_CHECK_LIB(m, cos, [], [
+        AC_MSG_NOTICE([Maths library was not found])
+    ])
+    LIBM="-lm"
+  else
+    LIBM=""
+  fi
   AC_SUBST(LIBM)
 
   # Setup libdl (for dynamic library loading)
--- a/common/autoconf/spec.gmk.in	Fri Feb 26 16:28:42 2016 +0100
+++ b/common/autoconf/spec.gmk.in	Mon Feb 29 15:42:34 2016 +0000
@@ -314,6 +314,10 @@
 # Option used to pass a command file to the compiler
 COMPILER_COMMAND_FILE_FLAG:=@COMPILER_COMMAND_FILE_FLAG@
 
+# Option for specifying a file which saves the binder commands
+# produced by the link step (for debugging, currently AIX only)
+COMPILER_BINDCMD_FILE_FLAG:=@COMPILER_BINDCMD_FILE_FLAG@
+
 CC_OUT_OPTION:=@CC_OUT_OPTION@
 EXE_OUT_OPTION:=@EXE_OUT_OPTION@
 LD_OUT_OPTION:=@LD_OUT_OPTION@
@@ -351,6 +355,8 @@
 CFLAGS_JDKEXE:=@CFLAGS_JDKEXE@
 CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
 
+LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
+
 CXX:=@FIXPATH@ @CCACHE@ @ICECC@ @CXX@
 
 CPP:=@FIXPATH@ @CPP@
--- a/corba/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/corba/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 e385e95e6101711d5c63e7b1a827e99b6ec7a1cc jdk-9+104
 64006ae915b3aa85ac7e6fac679024d2da7fe526 jdk-9+105
 8ec4f97943fe56f93e4621f622b56b7144c0181a jdk-9+106
+49202432b69445164a42be7cbdf74ed5fce98157 jdk-9+107
--- a/hotspot/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/hotspot/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -509,3 +509,4 @@
 534c50395957c6025fb6627e93b35756f8d48a08 jdk-9+104
 266fa9bb5297bf02cb2a7b038b10a109817d2b48 jdk-9+105
 7232de4c17c37f60aecec4f3191090bd3d41d334 jdk-9+106
+c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
--- a/hotspot/make/bsd/makefiles/arm.make	Fri Feb 26 16:28:42 2016 +0100
+++ b/hotspot/make/bsd/makefiles/arm.make	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,4 @@
 
 Obj_Files += bsd_arm.o
 
-ifneq ($(EXT_LIBS_PATH),)
-  LIBS += $(EXT_LIBS_PATH)/sflt_glibc.a 
-endif
-
 CFLAGS += -DVM_LITTLE_ENDIAN
--- a/hotspot/test/gc/g1/plab/TestPLABResize.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/hotspot/test/gc/g1/plab/TestPLABResize.java	Mon Feb 29 15:42:34 2016 +0000
@@ -35,6 +35,7 @@
  *        gc.g1.plab.lib.MemoryConsumer
  *        gc.g1.plab.lib.PLABUtils
  *        gc.g1.plab.lib.AppPLABResize
+ * @ignore 8150183
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  *                              sun.hotspot.WhiteBox$WhiteBoxPermission
  * @run main gc.g1.plab.TestPLABResize
--- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -38,6 +38,7 @@
  *          java.management
  *          jdk.jvmstat/sun.jvmstat.monitor
  * @build ClassFileInstaller jdk.test.lib.* SimpleJvmtiAgent
+ * @ignore 8150318
  * @run main ClassFileInstaller SimpleJvmtiAgent
  * @run testng LoadAgentDcmdTest
  */
--- a/jaxp/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 58448465334e1d8bf1cfc09052783937b1cc21c0 jdk-9+104
 5acf6071d4d610068a19c79e004ba8e59cf1b087 jdk-9+105
 65d615f71e81bae46dcb4d053e590582e5705879 jdk-9+106
+781b83dadcae89b8ae7545bb4044ddc62c6fa006 jdk-9+107
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -97,19 +97,9 @@
 public class XML11DTDScannerImpl
     extends XMLDTDScannerImpl {
 
-    /** Array of 3 strings. */
-    private String[] fStrings = new String[3];
-
-    /** String. */
-    private XMLString fString = new XMLString();
-
     /** String buffer. */
     private XMLStringBuffer fStringBuffer = new XMLStringBuffer();
 
-    /** String buffer. */
-    private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
-    private XMLStringBuffer fStringBuffer3 = new XMLStringBuffer();
-
     //
     // Constructors
     //
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -46,7 +46,6 @@
 import com.sun.org.apache.xerces.internal.impl.Constants;
 import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
-import com.sun.xml.internal.stream.Entity;
 
 /**
  * This class is responsible for scanning the declarations found
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -23,7 +23,6 @@
 
 import com.sun.xml.internal.stream.XMLBufferListener;
 import com.sun.xml.internal.stream.XMLEntityStorage;
-import com.sun.xml.internal.stream.XMLInputFactoryImpl;
 import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
 
 import java.io.EOFException;
@@ -50,17 +49,11 @@
 import com.sun.org.apache.xerces.internal.xni.Augmentations;
 import com.sun.org.apache.xerces.internal.impl.Constants;
 import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
-import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
-import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
-import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.State;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
-import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
-import javax.xml.XMLConstants;
 import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.events.XMLEvent;
 
 /**
  *
@@ -210,12 +203,12 @@
                 null,
                 null,
                 null,
-                EXTERNAL_ACCESS_DEFAULT
+                null
     };
 
     private static final char [] cdata = {'[','C','D','A','T','A','['};
     static final char [] xmlDecl = {'<','?','x','m','l'};
-    private static final char [] endTag = {'<','/'};
+    // private static final char [] endTag = {'<','/'};
     // debugging
 
     /** Debug scanner state. */
@@ -2066,7 +2059,7 @@
      */
     String checkAccess(String systemId, String allowedProtocols) throws IOException {
         String baseSystemId = fEntityScanner.getBaseSystemId();
-        String expandedSystemId = fEntityManager.expandSystemId(systemId, baseSystemId,fStrictURI);
+        String expandedSystemId = XMLEntityManager.expandSystemId(systemId, baseSystemId, fStrictURI);
         return SecuritySupport.checkAccess(expandedSystemId, allowedProtocols, Constants.ACCESS_EXTERNAL_ALL);
     }
 
@@ -2602,8 +2595,6 @@
         //
         // Driver methods
         //
-        private boolean fContinueDispatching = true;
-        private boolean fScanningForMarkup = true;
 
         /**
          *  decides the appropriate state of the parser
@@ -3266,7 +3257,7 @@
 
     protected XMLString getString(){
         if(fAttributeCacheUsedCount < initialCacheCount || fAttributeCacheUsedCount < attributeValueCache.size()){
-            return (XMLString)attributeValueCache.get(fAttributeCacheUsedCount++);
+            return attributeValueCache.get(fAttributeCacheUsedCount++);
         } else{
             XMLString str = new XMLString();
             fAttributeCacheUsedCount++;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -31,7 +31,6 @@
 import com.sun.org.apache.xerces.internal.xni.Augmentations;
 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
-import com.sun.org.apache.xerces.internal.xni.XMLString;
 import com.sun.org.apache.xerces.internal.xni.XNIException;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
@@ -224,9 +223,6 @@
     /** A DTD Description. */
     private final XMLDTDDescription fDTDDescription = new XMLDTDDescription(null, null, null, null, null);
 
-    /** String. */
-    private XMLString fString = new XMLString();
-
     private static final char [] DOCTYPE = {'D','O','C','T','Y','P','E'};
     private static final char [] COMMENTSTRING = {'-','-'};
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -370,7 +370,7 @@
     protected Map<String, Entity> fEntities = new HashMap<>();
 
     /** Entity stack. */
-    protected Stack fEntityStack = new Stack();
+    protected Stack<Entity> fEntityStack = new Stack<>();
 
     /** Current entity. */
     protected Entity.ScannedEntity fCurrentEntity = null;
@@ -633,10 +633,10 @@
                         final HTTPInputSource httpInputSource = (HTTPInputSource) xmlInputSource;
 
                         // set request properties
-                        Iterator propIter = httpInputSource.getHTTPRequestProperties();
+                        Iterator<Map.Entry<String, String>> propIter = httpInputSource.getHTTPRequestProperties();
                         while (propIter.hasNext()) {
-                            Map.Entry entry = (Map.Entry) propIter.next();
-                            urlConnection.setRequestProperty((String) entry.getKey(), (String) entry.getValue());
+                            Map.Entry<String, String> entry = propIter.next();
+                            urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
                         }
 
                         // set preference for redirection
@@ -1057,7 +1057,6 @@
         String literalSystemId = resourceIdentifier.getLiteralSystemId();
         String baseSystemId = resourceIdentifier.getBaseSystemId();
         String expandedSystemId = resourceIdentifier.getExpandedSystemId();
-        String namespace = resourceIdentifier.getNamespace();
 
         // if no base systemId given, assume that it's relative
         // to the systemId of the current scanned entity
@@ -2067,14 +2066,6 @@
 
         // system id has to be a valid URI
         if (strict) {
-
-
-            // check if there is a system id before
-            // trying to expand it.
-            if (systemId == null) {
-                return null;
-            }
-
             try {
                 // if it's already an absolute one, return it
                 new URI(systemId);
@@ -2968,7 +2959,7 @@
                     if (!fCurrentEntity.xmlDeclChunkRead)
                     {
                         fCurrentEntity.xmlDeclChunkRead = true;
-                        len = fCurrentEntity.DEFAULT_XMLDECL_BUFFER_SIZE;
+                        len = Entity.ScannedEntity.DEFAULT_XMLDECL_BUFFER_SIZE;
                     }
                     return fInputStream.read(b, off, len);
                 }
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -25,8 +25,6 @@
 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidatorFilter;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
-import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
-import com.sun.org.apache.xerces.internal.util.XMLStringBuffer;
 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
 import com.sun.org.apache.xerces.internal.xni.QName;
@@ -34,13 +32,9 @@
 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
-import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
-import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.events.XMLEvent;
 
 /**
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -25,7 +25,6 @@
 import com.sun.xml.internal.stream.XMLEntityStorage;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import javax.xml.stream.events.XMLEvent;
 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
@@ -120,8 +119,8 @@
     //we should have a feature when set to true computes this value
     private boolean fNeedNonNormalizedValue = false;
 
-    protected ArrayList attributeValueCache = new ArrayList();
-    protected ArrayList stringBufferCache = new ArrayList();
+    protected ArrayList<XMLString> attributeValueCache = new ArrayList<>();
+    protected ArrayList<XMLStringBuffer> stringBufferCache = new ArrayList<>();
     protected int fStringBufferIndex = 0;
     protected boolean fAttributeCacheInitDone = false;
     protected int fAttributeCacheUsedCount = 0;
@@ -1470,7 +1469,7 @@
 
     XMLStringBuffer getStringBuffer(){
         if((fStringBufferIndex < initialCacheCount )|| (fStringBufferIndex < stringBufferCache.size())){
-            return (XMLStringBuffer)stringBufferCache.get(fStringBufferIndex++);
+            return stringBufferCache.get(fStringBufferIndex++);
         }else{
             XMLStringBuffer tmpObj = new XMLStringBuffer();
             fStringBufferIndex++;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSAttributeChecker.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSAttributeChecker.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -1172,7 +1172,7 @@
             if (max != SchemaSymbols.OCCURRENCE_UNBOUNDED) {
 
                 // maxOccurLimit is only check in secure mode
-                if (fSchemaHandler.fSecureProcessing != null) {
+                if (fSchemaHandler.fSecurityManager != null) {
                     String localName = element.getLocalName();
 
                 // The maxOccurs restriction no longer applies to elements
@@ -1191,8 +1191,8 @@
                     if (!optimize) {
                     //Revisit :: IMO this is not right place to check
                     // maxOccurNodeLimit.
-                    int maxOccurNodeLimit = fSchemaHandler.fSecureProcessing.getLimit(XMLSecurityManager.Limit.MAX_OCCUR_NODE_LIMIT);
-                    if (max > maxOccurNodeLimit && !fSchemaHandler.fSecureProcessing.isNoLimit(maxOccurNodeLimit)) {
+                    int maxOccurNodeLimit = fSchemaHandler.fSecurityManager.getLimit(XMLSecurityManager.Limit.MAX_OCCUR_NODE_LIMIT);
+                    if (max > maxOccurNodeLimit && !fSchemaHandler.fSecurityManager.isNoLimit(maxOccurNodeLimit)) {
                         reportSchemaFatalError("MaxOccurLimit", new Object[] {new Integer(maxOccurNodeLimit)}, element);
 
                         // reset max values in case processing continues on error
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDHandler.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -194,6 +194,7 @@
     /** Property identifier: entity resolver. */
     public static final String ENTITY_RESOLVER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
+
     /** Property identifier: entity manager. */
     protected static final String ENTITY_MANAGER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
@@ -214,16 +215,13 @@
     protected static final String SECURITY_MANAGER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 
-    private static final String SECURE_PROCESSING =
-        Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
-
     /** Property identifier: locale. */
     protected static final String LOCALE =
         Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
 
-        /** Property identifier: Security property manager. */
+    /** Property identifier: Security property manager. */
     private static final String XML_SECURITY_PROPERTY_MANAGER =
-            Constants.XML_SECURITY_PROPERTY_MANAGER;
+        Constants.XML_SECURITY_PROPERTY_MANAGER;
 
     protected static final boolean DEBUG_NODE_POOL = false;
 
@@ -243,17 +241,12 @@
     // as unlikely as possible to cause collisions.
     public final static String REDEF_IDENTIFIER = "_fn3dktizrknc9pi";
 
-    //
-    //protected data that can be accessable by any traverser
+    //protected data that can be accessible by any traverser
 
     protected XSDeclarationPool fDeclPool = null;
 
-    /**
-     * <p>Security manager in effect.</p>
-     *
-     * <p>Protected to allow access by any traverser.</p>
-     */
-    protected XMLSecurityManager fSecureProcessing = null;
+    // the Security manager in effect.
+    protected XMLSecurityManager fSecurityManager = null;
 
     private String fAccessExternalSchema;
     private String fAccessExternalDTD;
@@ -266,27 +259,28 @@
     // XSDocumentInfoRegistry we can easily get the corresponding
     // XSDocumentInfo object.
     private boolean registryEmpty = true;
-    private Map<String, Element> fUnparsedAttributeRegistry = new HashMap();
-    private Map<String, Element> fUnparsedAttributeGroupRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedElementRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedGroupRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedIdentityConstraintRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedNotationRegistry =  new HashMap();
-    private Map<String, Element> fUnparsedTypeRegistry =  new HashMap();
+    private Map<String, Element> fUnparsedAttributeRegistry = new HashMap<>();
+    private Map<String, Element> fUnparsedAttributeGroupRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedElementRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedGroupRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedIdentityConstraintRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedNotationRegistry =  new HashMap<>();
+    private Map<String, Element> fUnparsedTypeRegistry =  new HashMap<>();
     // Compensation for the above maps to locate XSDocumentInfo,
     // Since we may take Schema Element directly, so can not get the
     // corresponding XSDocumentInfo object just using above maps.
-    private Map<String, XSDocumentInfo> fUnparsedAttributeRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedAttributeGroupRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedElementRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedGroupRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedIdentityConstraintRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedNotationRegistrySub =  new HashMap();
-    private Map<String, XSDocumentInfo> fUnparsedTypeRegistrySub =  new HashMap();
+    private Map<String, XSDocumentInfo> fUnparsedAttributeRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedAttributeGroupRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedElementRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedGroupRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedIdentityConstraintRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedNotationRegistrySub =  new HashMap<>();
+    private Map<String, XSDocumentInfo> fUnparsedTypeRegistrySub =  new HashMap<>();
 
     // Stores XSDocumentInfo (keyed by component name), to check for duplicate
     // components declared within the same xsd document
-    private Map fUnparsedRegistriesExt[] = new HashMap[] {
+    @SuppressWarnings("unchecked")
+    private Map<String, XSDocumentInfo> fUnparsedRegistriesExt[] = new HashMap[] {
         null,
         null, // ATTRIBUTE_TYPE
         null, // ATTRIBUTEGROUP_TYPE
@@ -300,17 +294,19 @@
     // this map is keyed on by XSDocumentInfo objects.  Its values
     // are Vectors containing the XSDocumentInfo objects <include>d,
     // <import>ed or <redefine>d by the key XSDocumentInfo.
-    private Map<XSDocumentInfo, Vector> fDependencyMap = new HashMap();
+    private Map<XSDocumentInfo, Vector<XSDocumentInfo>> fDependencyMap = new HashMap<>();
 
     // this map is keyed on by a target namespace.  Its values
     // are Vectors containing namespaces imported by schema documents
     // with the key target namespace.
-    // if an imprted schema has absent namespace, the value "null" is stored.
-    private Map<String, Vector> fImportMap = new HashMap();
+    // if an imported schema has absent namespace, the value "null" is stored.
+    private Map<String, Vector> fImportMap = new HashMap<> ();
+
     // all namespaces that imports other namespaces
     // if the importing schema has absent namespace, empty string is stored.
     // (because the key of a map can't be null.)
-    private Vector fAllTNSs = new Vector();
+    private Vector<String> fAllTNSs = new Vector<>();
+
     // stores instance document mappings between namespaces and schema hints
     private Map<String, XMLSchemaLoader.LocationArray> fLocationPairs = null;
 
@@ -333,7 +329,7 @@
         if(ele.getOwnerDocument() instanceof com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM){
             documentURI = ((com.sun.org.apache.xerces.internal.impl.xs.opti.SchemaDOM) ele.getOwnerDocument()).getDocumentURI();
         }
-        return documentURI != null ? documentURI : (String) fDoc2SystemId.get(ele);
+        return documentURI != null ? documentURI : fDoc2SystemId.get(ele);
     }
 
     // This vector stores strings which are combinations of the
@@ -341,11 +337,11 @@
     // schema document.  This combination is used so that the user's
     // EntityResolver can provide a consistent way of identifying a
     // schema document that is included in multiple other schemas.
-    private Map fTraversed = new HashMap();
+    private Map<XSDKey, Element> fTraversed = new HashMap<>();
 
     // this map contains a mapping from Schema Element to its systemId
     // this is useful to resolve a uri relative to the referring document
-    private Map fDoc2SystemId = new HashMap();
+    private Map<Element, String> fDoc2SystemId = new HashMap<>();
 
     // the primary XSDocumentInfo we were called to parse
     private XSDocumentInfo fRoot = null;
@@ -387,7 +383,15 @@
 
     // the XMLErrorReporter
     private XMLErrorReporter fErrorReporter;
-    private XMLEntityResolver fEntityResolver;
+
+    // the XMLErrorHandler
+    private XMLErrorHandler fErrorHandler;
+
+    // the Locale
+    private Locale fLocale;
+
+    // the XMLEntityManager
+    private XMLEntityResolver fEntityManager;
 
     // the XSAttributeChecker
     private XSAttributeChecker fAttributeChecker;
@@ -404,6 +408,9 @@
     // the Grammar Pool
     private XMLGrammarPool fGrammarPool;
 
+    // the security property manager
+    private XMLSecurityPropertyManager fSecurityPropertyMgr = null;
+
     //************ Traversers **********
     XSDAttributeGroupTraverser fAttributeGroupTraverser;
     XSDAttributeTraverser fAttributeTraverser;
@@ -638,7 +645,7 @@
         // for all grammars with <import>s
         for (int i = fAllTNSs.size() - 1; i >= 0; i--) {
             // get its target namespace
-            String tns = (String)fAllTNSs.elementAt(i);
+            String tns = fAllTNSs.elementAt(i);
             // get all namespaces it imports
             Vector ins = (Vector)fImportMap.get(tns);
             // get the grammar
@@ -696,12 +703,13 @@
         fAnnotationValidator.setFeature(VALIDATION, true);
         fAnnotationValidator.setFeature(XMLSCHEMA_VALIDATION, true);
         fAnnotationValidator.setProperty(XMLGRAMMAR_POOL, fGrammarBucketAdapter);
+        /** set security manager and XML Security Property Manager **/
+        fAnnotationValidator.setProperty(SECURITY_MANAGER, (fSecurityManager != null) ? fSecurityManager : new XMLSecurityManager(true));
+        fAnnotationValidator.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
         /** Set error handler. **/
-        XMLErrorHandler errorHandler = fErrorReporter.getErrorHandler();
-        fAnnotationValidator.setProperty(ERROR_HANDLER, (errorHandler != null) ? errorHandler : new DefaultErrorHandler());
+        fAnnotationValidator.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
         /** Set locale. **/
-        Locale locale = fErrorReporter.getLocale();
-        fAnnotationValidator.setProperty(LOCALE, locale);
+        fAnnotationValidator.setProperty(LOCALE, fLocale);
     }
 
     /**
@@ -880,10 +888,10 @@
 
         // store the document and its location
         // REVISIT: don't expose the DOM tree
-        sg.addDocument(null, (String)fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
+        sg.addDocument(null, fDoc2SystemId.get(currSchemaInfo.fSchemaElement));
 
         fDoc2XSDocumentMap.put(schemaRoot, currSchemaInfo);
-        Vector dependencies = new Vector();
+        Vector<XSDocumentInfo> dependencies = new Vector<>();
         Element rootNode = schemaRoot;
 
         Element newSchemaRoot = null;
@@ -1334,9 +1342,9 @@
             } // end for
 
             // now we're done with this one!
-                DOMUtil.setHidden(currDoc, fHiddenNodes);
+            DOMUtil.setHidden(currDoc, fHiddenNodes);
             // now add the schemas this guy depends on
-            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
+            Vector<XSDocumentInfo> currSchemaDepends = fDependencyMap.get(currSchemaDoc);
             for (int i = 0; i < currSchemaDepends.size(); i++) {
                 schemasToProcess.push(currSchemaDepends.elementAt(i));
             }
@@ -1466,7 +1474,7 @@
             DOMUtil.setHidden(currDoc, fHiddenNodes);
 
             // now add the schemas this guy depends on
-            Vector currSchemaDepends = (Vector)fDependencyMap.get(currSchemaDoc);
+            Vector<XSDocumentInfo> currSchemaDepends = fDependencyMap.get(currSchemaDoc);
             for (int i = 0; i < currSchemaDepends.size(); i++) {
                 schemasToProcess.push(currSchemaDepends.elementAt(i));
             }
@@ -1915,7 +1923,7 @@
     }
 
     public String schemaDocument2SystemId(XSDocumentInfo schemaDoc) {
-        return (String)fDoc2SystemId.get(schemaDoc.fSchemaElement);
+        return fDoc2SystemId.get(schemaDoc.fSchemaElement);
     }
 
     // This method determines whether there is a group
@@ -2044,7 +2052,7 @@
         XMLInputSource schemaSource = null;
         try {
             Map<String, XMLSchemaLoader.LocationArray> pairs = usePairs ? fLocationPairs : Collections.emptyMap();
-            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
+            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityManager);
         }
         catch (IOException ex) {
             if (mustResolve) {
@@ -2097,7 +2105,7 @@
         XMLInputSource schemaSource = null;
         try {
             Map<String, XMLSchemaLoader.LocationArray> pairs = usePairs ? fLocationPairs : Collections.emptyMap();
-            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityResolver);
+            schemaSource = XMLSchemaLoader.resolveDocument(desc, pairs, fEntityManager);
         }
         catch (IOException ex) {
             if (mustResolve) {
@@ -2152,7 +2160,7 @@
                 if (referType != XSDDescription.CONTEXT_PREPARSE){
                     schemaId = XMLEntityManager.expandSystemId(schemaSource.getSystemId(), schemaSource.getBaseSystemId(), false);
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if((schemaElement = (Element)fTraversed.get(key)) != null) {
+                    if((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -2211,7 +2219,7 @@
                 if (referType != XSDDescription.CONTEXT_PREPARSE) {
                     schemaId = XMLEntityManager.expandSystemId(inputSource.getSystemId(), schemaSource.getBaseSystemId(), false);
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                    if ((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -2238,9 +2246,8 @@
                         namespacePrefixes = true;
                         // If this is a Xerces SAX parser set the security manager if there is one
                         if (parser instanceof SAXParser) {
-                            Object securityManager = fSchemaParser.getProperty(SECURITY_MANAGER);
-                            if (securityManager != null) {
-                                parser.setProperty(SECURITY_MANAGER, securityManager);
+                            if (fSecurityManager != null) {
+                                parser.setProperty(SECURITY_MANAGER, fSecurityManager);
                             }
                         }
                     }
@@ -2347,7 +2354,7 @@
                     }
                     if (isDocument) {
                         key = new XSDKey(schemaId, referType, schemaNamespace);
-                        if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                        if ((schemaElement = fTraversed.get(key)) != null) {
                             fLastSchemaWasDuplicate = true;
                             return schemaElement;
                         }
@@ -2402,7 +2409,7 @@
                 }
                 if (isDocument) {
                     key = new XSDKey(schemaId, referType, schemaNamespace);
-                    if ((schemaElement = (Element) fTraversed.get(key)) != null) {
+                    if ((schemaElement = fTraversed.get(key)) != null) {
                         fLastSchemaWasDuplicate = true;
                         return schemaElement;
                     }
@@ -3502,40 +3509,21 @@
         // set symbol table
         fSymbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
 
-        fSecureProcessing = null;
-        if( componentManager!=null ) {
-            fSecureProcessing = (XMLSecurityManager) componentManager.getProperty(SECURE_PROCESSING, null);
-        }
+        // set security manager
+        fSecurityManager = (XMLSecurityManager) componentManager.getProperty(SECURITY_MANAGER, null);
+
+        //set entity manager
+        fEntityManager = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
 
         //set entity resolver
-        fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
         XMLEntityResolver er = (XMLEntityResolver)componentManager.getProperty(ENTITY_RESOLVER);
         if (er != null)
             fSchemaParser.setEntityResolver(er);
 
         // set error reporter
-        fErrorReporter =
-            (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
-        try {
-            XMLErrorHandler currErrorHandler = fErrorReporter.getErrorHandler();
-            // Setting a parser property can be much more expensive
-            // than checking its value.  Don't set the ERROR_HANDLER
-            // or LOCALE properties unless they've actually changed.
-            if (currErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
-                fSchemaParser.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
-                if (fAnnotationValidator != null) {
-                    fAnnotationValidator.setProperty(ERROR_HANDLER, (currErrorHandler != null) ? currErrorHandler : new DefaultErrorHandler());
-                }
-            }
-            Locale currentLocale = fErrorReporter.getLocale();
-            if (currentLocale != fSchemaParser.getProperty(LOCALE)) {
-                fSchemaParser.setProperty(LOCALE, currentLocale);
-                if (fAnnotationValidator != null) {
-                    fAnnotationValidator.setProperty(LOCALE, currentLocale);
-                }
-            }
-        }
-        catch (XMLConfigurationException e) {}
+        fErrorReporter = (XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER);
+        fErrorHandler = fErrorReporter.getErrorHandler();
+        fLocale = fErrorReporter.getLocale();
 
         fValidateAnnotations = componentManager.getFeature(VALIDATE_ANNOTATIONS, false);
         fHonourAllSchemaLocations = componentManager.getFeature(HONOUR_ALL_SCHEMALOCATIONS, false);
@@ -3543,56 +3531,66 @@
         fTolerateDuplicates = componentManager.getFeature(TOLERATE_DUPLICATES, false);
 
         try {
-            fSchemaParser.setFeature(
-                    CONTINUE_AFTER_FATAL_ERROR,
-                    fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
-        } catch (XMLConfigurationException e) {
+            // Setting a parser property can be much more expensive
+            // than checking its value.  Don't set the ERROR_HANDLER
+            // or LOCALE properties unless they've actually changed.
+            if (fErrorHandler != fSchemaParser.getProperty(ERROR_HANDLER)) {
+                fSchemaParser.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
+                if (fAnnotationValidator != null) {
+                    fAnnotationValidator.setProperty(ERROR_HANDLER, (fErrorHandler != null) ? fErrorHandler : new DefaultErrorHandler());
+                }
+            }
+            if (fLocale != fSchemaParser.getProperty(LOCALE)) {
+                fSchemaParser.setProperty(LOCALE, fLocale);
+                if (fAnnotationValidator != null) {
+                    fAnnotationValidator.setProperty(LOCALE, fLocale);
+                }
+            }
         }
+        catch (XMLConfigurationException e) {}
+
+        try {
+            fSchemaParser.setFeature(CONTINUE_AFTER_FATAL_ERROR, fErrorReporter.getFeature(CONTINUE_AFTER_FATAL_ERROR));
+        } catch (XMLConfigurationException e) {}
 
         try {
             if (componentManager.getFeature(ALLOW_JAVA_ENCODINGS, false)) {
                 fSchemaParser.setFeature(ALLOW_JAVA_ENCODINGS, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
+
         try {
             if (componentManager.getFeature(STANDARD_URI_CONFORMANT_FEATURE, false)) {
                 fSchemaParser.setFeature(STANDARD_URI_CONFORMANT_FEATURE, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
 
         try {
-            fGrammarPool =
-                (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
+            fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL);
         } catch (XMLConfigurationException e) {
             fGrammarPool = null;
         }
+
         // security features
         try {
             if (componentManager.getFeature(DISALLOW_DOCTYPE, false)) {
                 fSchemaParser.setFeature(DISALLOW_DOCTYPE, true);
             }
-        } catch (XMLConfigurationException e) {
-        }
+        } catch (XMLConfigurationException e) {}
+
         try {
-            Object security = componentManager.getProperty(SECURITY_MANAGER, null);
-            if (security != null){
-                fSchemaParser.setProperty(SECURITY_MANAGER, security);
+            if (fSecurityManager != null) {
+                fSchemaParser.setProperty(SECURITY_MANAGER, fSecurityManager);
             }
-        } catch (XMLConfigurationException e) {
-        }
-
-        XMLSecurityPropertyManager securityPropertyMgr = (XMLSecurityPropertyManager)
-                componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
+        } catch (XMLConfigurationException e) {}
+
+        fSecurityPropertyMgr = (XMLSecurityPropertyManager) componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
+
         //Passing on the setting to the parser
-        fSchemaParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, securityPropertyMgr);
-
-        fAccessExternalDTD = securityPropertyMgr.getValue(
-                XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
-
-        fAccessExternalSchema = securityPropertyMgr.getValue(
-                XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
+        fSchemaParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
+
+        fAccessExternalDTD = fSecurityPropertyMgr.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD);
+        fAccessExternalSchema = fSecurityPropertyMgr.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
 
     } // reset(XMLComponentManager)
 
@@ -4051,7 +4049,7 @@
          so long as there's some include/import/redefine path amongst them.
          If they rver reverse this decision the code's right here though...  - neilg
          // now look in fDependencyMap to see if this is reachable
-          if(((Vector)fDependencyMap.get(currSchema)).contains(declDocInfo)) {
+          if((fDependencyMap.get(currSchema)).contains(declDocInfo)) {
           return declDocInfo;
           }
           // obviously the requesting doc didn't include, redefine or
@@ -4072,9 +4070,9 @@
         if (DOMUtil.isHidden(startSchema.fSchemaElement, fHiddenNodes)) {
             // make it visible
             DOMUtil.setVisible(startSchema.fSchemaElement, fHiddenNodes);
-            Vector dependingSchemas = (Vector)fDependencyMap.get(startSchema);
+            Vector<XSDocumentInfo> dependingSchemas = fDependencyMap.get(startSchema);
             for (int i = 0; i < dependingSchemas.size(); i++) {
-                setSchemasVisible((XSDocumentInfo)dependingSchemas.elementAt(i));
+                setSchemasVisible(dependingSchemas.elementAt(i));
             }
         }
         // if it's visible already than so must be its children
@@ -4107,7 +4105,7 @@
             ElementImpl ele = (ElementImpl)e;
             // get system id from document object
             Document doc = ele.getOwnerDocument();
-            String sid = (String)fDoc2SystemId.get(DOMUtil.getRoot(doc));
+            String sid = fDoc2SystemId.get(DOMUtil.getRoot(doc));
             // line/column numbers are stored in the element node
             int line = ele.getLineNumber();
             int column = ele.getColumnNumber();
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/XML11Configuration.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -52,7 +52,6 @@
 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
 import com.sun.org.apache.xerces.internal.util.PropertyState;
 import com.sun.org.apache.xerces.internal.util.SymbolTable;
-import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler;
 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler;
@@ -166,59 +165,57 @@
     protected static final String USE_GRAMMAR_POOL_ONLY =
         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
 
-        // feature identifiers
+    // feature identifiers
 
-        /** Feature identifier: validation. */
-        protected static final String VALIDATION =
-                Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
+    /** Feature identifier: validation. */
+    protected static final String VALIDATION =
+        Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 
-        /** Feature identifier: namespaces. */
-        protected static final String NAMESPACES =
-                Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
+    /** Feature identifier: namespaces. */
+    protected static final String NAMESPACES =
+        Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
 
-        /** Feature identifier: external general entities. */
-        protected static final String EXTERNAL_GENERAL_ENTITIES =
-                Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE;
+    /** Feature identifier: external general entities. */
+    protected static final String EXTERNAL_GENERAL_ENTITIES =
+        Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE;
 
-        /** Feature identifier: external parameter entities. */
-        protected static final String EXTERNAL_PARAMETER_ENTITIES =
-                Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE;
+    /** Feature identifier: external parameter entities. */
+    protected static final String EXTERNAL_PARAMETER_ENTITIES =
+        Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE;
 
-        /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
-        protected static final String IGNORE_XSI_TYPE =
-            Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
+    /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
+    protected static final String IGNORE_XSI_TYPE =
+        Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
 
-        /** Feature identifier: whether to ignore ID/IDREF errors */
-        protected static final String ID_IDREF_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore ID/IDREF errors */
+    protected static final String ID_IDREF_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
 
-        /** Feature identifier: whether to ignore unparsed entity errors */
-        protected static final String UNPARSED_ENTITY_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore unparsed entity errors */
+    protected static final String UNPARSED_ENTITY_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
 
-        /** Feature identifier: whether to ignore identity constraint errors */
-        protected static final String IDENTITY_CONSTRAINT_CHECKING =
-            Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
+    /** Feature identifier: whether to ignore identity constraint errors */
+    protected static final String IDENTITY_CONSTRAINT_CHECKING =
+        Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
 
     // property identifiers
 
+    /** Property identifier: xml string. */
+    protected static final String XML_STRING =
+        Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
 
-        /** Property identifier: xml string. */
-        protected static final String XML_STRING =
-                Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY;
-
-        /** Property identifier: symbol table. */
-        protected static final String SYMBOL_TABLE =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
+    /** Property identifier: symbol table. */
+    protected static final String SYMBOL_TABLE =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 
-        /** Property identifier: error handler. */
-        protected static final String ERROR_HANDLER =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
+    /** Property identifier: error handler. */
+    protected static final String ERROR_HANDLER =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
 
-        /** Property identifier: entity resolver. */
-        protected static final String ENTITY_RESOLVER =
-                Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
-
+    /** Property identifier: entity resolver. */
+    protected static final String ENTITY_RESOLVER =
+        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 
     /** Property identifier: XML Schema validator. */
     protected static final String SCHEMA_VALIDATOR =
@@ -232,8 +229,6 @@
     protected static final String SCHEMA_NONS_LOCATION =
         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
 
-    // property identifiers
-
     /** Property identifier: error reporter. */
     protected static final String ERROR_REPORTER =
         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
@@ -313,33 +308,33 @@
     // Data
     //
 
-        protected SymbolTable fSymbolTable;
+    protected SymbolTable fSymbolTable;
     protected XMLInputSource fInputSource;
     protected ValidationManager fValidationManager;
-        protected XMLVersionDetector fVersionDetector;
+    protected XMLVersionDetector fVersionDetector;
     protected XMLLocator fLocator;
-        protected Locale fLocale;
+    protected Locale fLocale;
 
-        /** XML 1.0 Components. */
-        protected ArrayList fComponents;
+    /** XML 1.0 Components. */
+    protected ArrayList<XMLComponent> fComponents;
 
-        /** XML 1.1. Components. */
-        protected ArrayList fXML11Components = null;
+    /** XML 1.1. Components. */
+    protected ArrayList<XMLComponent> fXML11Components = null;
 
-        /** Common components: XMLEntityManager, XMLErrorReporter, XMLSchemaValidator */
-        protected ArrayList fCommonComponents = null;
+    /** Common components: XMLEntityManager, XMLErrorReporter, XMLSchemaValidator */
+    protected ArrayList<XMLComponent> fCommonComponents = null;
 
-        /** The document handler. */
-        protected XMLDocumentHandler fDocumentHandler;
+    /** The document handler. */
+    protected XMLDocumentHandler fDocumentHandler;
 
-        /** The DTD handler. */
-        protected XMLDTDHandler fDTDHandler;
+    /** The DTD handler. */
+    protected XMLDTDHandler fDTDHandler;
 
-        /** The DTD content model handler. */
-        protected XMLDTDContentModelHandler fDTDContentModelHandler;
+    /** The DTD content model handler. */
+    protected XMLDTDContentModelHandler fDTDContentModelHandler;
 
-        /** Last component in the document pipeline */
-        protected XMLDocumentSource fLastComponent;
+    /** Last component in the document pipeline */
+    protected XMLDocumentSource fLastComponent;
 
     /**
      * True if a parse is in progress. This state is needed because
@@ -477,15 +472,15 @@
 
         // create a vector to hold all the components in use
         // XML 1.0 specialized components
-        fComponents = new ArrayList();
+        fComponents = new ArrayList<>();
         // XML 1.1 specialized components
-        fXML11Components = new ArrayList();
+        fXML11Components = new ArrayList<>();
         // Common components for XML 1.1. and XML 1.0
-        fCommonComponents = new ArrayList();
+        fCommonComponents = new ArrayList<>();
 
         // create table for features and properties
-        fFeatures = new HashMap();
-        fProperties = new HashMap();
+        fFeatures = new HashMap<>();
+        fProperties = new HashMap<>();
 
         // add default recognized features
         final String[] recognizedFeatures =
@@ -580,35 +575,35 @@
         }
 
         fEntityManager = new XMLEntityManager();
-                fProperties.put(ENTITY_MANAGER, fEntityManager);
+        fProperties.put(ENTITY_MANAGER, fEntityManager);
         addCommonComponent(fEntityManager);
 
         fErrorReporter = new XMLErrorReporter();
         fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
-                fProperties.put(ERROR_REPORTER, fErrorReporter);
+        fProperties.put(ERROR_REPORTER, fErrorReporter);
         addCommonComponent(fErrorReporter);
 
         fNamespaceScanner = new XMLNSDocumentScannerImpl();
-                fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner);
+        fProperties.put(DOCUMENT_SCANNER, fNamespaceScanner);
         addComponent((XMLComponent) fNamespaceScanner);
 
         fDTDScanner = new XMLDTDScannerImpl();
-                fProperties.put(DTD_SCANNER, fDTDScanner);
+        fProperties.put(DTD_SCANNER, fDTDScanner);
         addComponent((XMLComponent) fDTDScanner);
 
         fDTDProcessor = new XMLDTDProcessor();
-                fProperties.put(DTD_PROCESSOR, fDTDProcessor);
+        fProperties.put(DTD_PROCESSOR, fDTDProcessor);
         addComponent((XMLComponent) fDTDProcessor);
 
         fDTDValidator = new XMLNSDTDValidator();
-                fProperties.put(DTD_VALIDATOR, fDTDValidator);
+        fProperties.put(DTD_VALIDATOR, fDTDValidator);
         addComponent(fDTDValidator);
 
         fDatatypeValidatorFactory = DTDDVFactory.getInstance();
-                fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory);
+        fProperties.put(DATATYPE_VALIDATOR_FACTORY, fDatatypeValidatorFactory);
 
         fValidationManager = new ValidationManager();
-                fProperties.put(VALIDATION_MANAGER, fValidationManager);
+        fProperties.put(VALIDATION_MANAGER, fValidationManager);
 
         fVersionDetector = new XMLVersionDetector();
 
@@ -935,20 +930,20 @@
                 // forward to every XML 1.0 component
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.setFeature(featureId, state);
                 }
                 // forward it to common components
                 count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.setFeature(featureId, state);
                 }
 
                 // forward to every XML 1.1 component
                 count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         try{
                                 c.setFeature(featureId, state);
                         }
@@ -996,19 +991,19 @@
                 // forward to every XML 1.0 component
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.setProperty(propertyId, value);
                 }
                 // forward it to every common Component
                 count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.setProperty(propertyId, value);
                 }
                 // forward it to every XML 1.1 component
                 count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         try{
                                 c.setProperty(propertyId, value);
                         }
@@ -1034,7 +1029,7 @@
         protected void reset() throws XNIException {
                 int count = fComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fComponents.get(i);
+                        XMLComponent c = fComponents.get(i);
                         c.reset(this);
                 }
 
@@ -1047,7 +1042,7 @@
                 // reset common components
                 int count = fCommonComponents.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fCommonComponents.get(i);
+                        XMLComponent c = fCommonComponents.get(i);
                         c.reset(this);
                 }
 
@@ -1061,7 +1056,7 @@
                 // reset every component
                 int count = fXML11Components.size();
                 for (int i = 0; i < count; i++) {
-                        XMLComponent c = (XMLComponent) fXML11Components.get(i);
+                        XMLComponent c = fXML11Components.get(i);
                         c.reset(this);
                 }
 
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/util/HTTPInputSource.java	Mon Feb 29 15:42:34 2016 +0000
@@ -51,7 +51,7 @@
     protected boolean fFollowRedirects = true;
 
     /** HTTP request properties. **/
-    protected Map fHTTPRequestProperties = new HashMap();
+    protected Map<String, String> fHTTPRequestProperties = new HashMap<>();
 
     //
     // Constructors
@@ -159,7 +159,7 @@
      * been set
      */
     public String getHTTPRequestProperty(String key) {
-        return (String) fHTTPRequestProperties.get(key);
+        return fHTTPRequestProperties.get(key);
     } // getHTTPRequestProperty(String):String
 
     /**
@@ -172,7 +172,7 @@
      * @return an iterator for the request properties this
      * input source contains
      */
-    public Iterator getHTTPRequestProperties() {
+    public Iterator<Map.Entry<String, String>> getHTTPRequestProperties() {
         return fHTTPRequestProperties.entrySet().iterator();
     } // getHTTPRequestProperties():Iterator
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/Bug8149915.xsd	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+<xs:annotation>
+   <xs:appinfo>Testapp for XSD annotation issue</xs:appinfo>
+   <xs:documentation xml:lang="en">This is an XSD annotation, just for the sake of it.</xs:documentation>
+</xs:annotation>
+</xs:schema>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/validation/SchemaTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package validation;
+
+import java.io.File;
+
+import javax.xml.XMLConstants;
+import javax.xml.validation.SchemaFactory;
+
+import org.testng.annotations.Test;
+
+/*
+ * @summary Test Schema creation
+ * @bug 8149915
+ */
+public class SchemaTest {
+
+    /*
+     * @bug 8149915
+     * Verifies that the annotation validator is initialized with the security manager for schema
+     * creation with http://apache.org/xml/features/validate-annotations=true.
+     */
+    @Test
+    public void testValidation() throws Exception {
+        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        factory.setFeature("http://apache.org/xml/features/validate-annotations", true);
+        factory.newSchema(new File(getClass().getResource("Bug8149915.xsd").getFile()));
+    }
+}
--- a/jaxws/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/jaxws/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -352,3 +352,4 @@
 0f557aa096e2a5c9733d406d8cf0c2e6b1f8ca60 jdk-9+104
 45a666c58e4c7d07638878684ad09decb3229dc9 jdk-9+105
 c072c572d14948563ef5d86e1921699b3a2396ab jdk-9+106
+fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107
--- a/jdk/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 8faf1aec77a9517c69d2f4d8dd146429852ace7f jdk-9+104
 55518739e399a1066c8613e19100d51b38d9f223 jdk-9+105
 6e9ecae50b4e0d37483fb2719202eea5dca026a4 jdk-9+106
+8701b2bb1d2e1b9abc2a9be0933993c7150a9dbe jdk-9+107
--- a/jdk/make/gensrc/GensrcMisc.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/gensrc/GensrcMisc.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,8 @@
 $(eval $(call SetupNativeCompilation, BUILD_GENSRC_SOR_EXE, \
     SRC := $(GENSRC_SOR_SRC), \
     INCLUDE_FILES := $(GENSRC_SOR_SRC_FILE), \
+    CFLAGS_windows := -nologo, \
+    LDFLAGS_windows := -nologo, \
     TOOLCHAIN := TOOLCHAIN_BUILD, \
     OBJECT_DIR := $(GENSRC_SOR_BIN), \
     OUTPUT_DIR := $(GENSRC_SOR_BIN), \
@@ -61,12 +63,12 @@
 SOR_PREGEN_FILE := $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/classes/sun/nio/ch/SocketOptionRegistry-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH).java.template
 
 ifeq ($(wildcard $(SOR_PREGEN_FILE)), )
-  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(BUILD_GENSRC_SOR_EXE)
+  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(BUILD_GENSRC_SOR_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(SOR_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_SOR_EXE) >> $@.tmp
+	$(BUILD_GENSRC_SOR_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
 else
   $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/ch/SocketOptionRegistry.java: $(SOR_PREGEN_FILE)
@@ -97,12 +99,12 @@
   UC_PREGEN_FILE := $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/classes/sun/nio/fs/UnixConstants-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH).java.template
 
   ifeq ($(wildcard $(UC_PREGEN_FILE)), )
-    $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(BUILD_GENSRC_UC_EXE)
+    $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(BUILD_GENSRC_UC_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(UC_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_UC_EXE) >> $@.tmp
+	$(BUILD_GENSRC_UC_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
   else
     $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/UnixConstants.java: $(UC_PREGEN_FILE)
@@ -132,12 +134,12 @@
       OUTPUT_DIR := $(GENSRC_SOL_BIN), \
       PROGRAM := genSolarisConstants))
 
-  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java: $(BUILD_GENSRC_SOL_EXE)
+  $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java: $(BUILD_GENSRC_SOL_EXE_TARGET)
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
 	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e \
 	    $(JDK_TOPDIR)/make/scripts/addNotices.sh "$(SOL_COPYRIGHT_YEARS)" > $@.tmp
-	$(BUILD_GENSRC_SOL_EXE) >> $@.tmp
+	$(BUILD_GENSRC_SOL_EXE_TARGET) >> $@.tmp
 	$(MV) $@.tmp $@
 
 
--- a/jdk/make/lib/Awt2dLibraries.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/lib/Awt2dLibraries.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -593,8 +593,8 @@
         LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/..), \
         REORDER := $(LIBAWT_HEADLESS_REORDER), \
         LIBS_unix := -lawt -ljvm -ljava, \
-        LIBS_linux := -lm $(LIBDL), \
-        LIBS_solaris := -lm $(LIBDL) $(LIBCXX) -lc, \
+        LIBS_linux := $(LIBM) $(LIBDL), \
+        LIBS_solaris := $(LIBM) $(LIBDL) $(LIBCXX) -lc, \
         OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libawt_headless, \
     ))
 
--- a/jdk/make/lib/CoreLibraries.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/lib/CoreLibraries.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -137,12 +137,6 @@
   endif
 endif
 
-ifeq ($(OPENJDK_TARGET_OS), linux)
-  ifeq ($(OPENJDK_TARGET_CPU), x86_64)
-    BUILD_LIBJAVA_Bits.c_CFLAGS := $(C_O_FLAG_NORM)
-  endif
-endif
-
 $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \
     LIBRARY := java, \
     OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
@@ -163,7 +157,7 @@
     LIBS_unix := -ljvm -lverify, \
     LIBS_linux := $(LIBDL) $(BUILD_LIBFDLIBM), \
     LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL) $(BUILD_LIBFDLIBM) -lc, \
-    LIBS_aix := $(LIBDL) $(BUILD_LIBFDLIBM) -lm,\
+    LIBS_aix := $(LIBDL) $(BUILD_LIBFDLIBM) $(LIBM),\
     LIBS_macosx := -lfdlibm \
         -framework CoreFoundation \
         -framework Foundation \
--- a/jdk/make/lib/Lib-java.instrument.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/lib/Lib-java.instrument.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -67,7 +67,6 @@
         -L$(call FindLibDirForModule, java.base)/jli, \
     LDFLAGS_macosx := -Wl$(COMMA)-all_load, \
     LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
-    LDFLAGS_windows := -export:Agent_OnAttach, \
     LIBS := $(JDKLIB_LIBS), \
     LIBS_unix := -ljava $(LIBZ), \
     LIBS_linux := -ljli $(LIBDL), \
--- a/jdk/make/lib/Lib-jdk.jdi.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/lib/Lib-jdk.jdi.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
--- a/jdk/make/lib/Lib-jdk.jdwp.agent.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/lib/Lib-jdk.jdwp.agent.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Mon Feb 29 15:42:34 2016 +0000
@@ -229,12 +229,6 @@
 		Java_java_lang_Throwable_fillInStackTrace;
                 Java_java_lang_Throwable_getStackTraceDepth;
                 Java_java_lang_Throwable_getStackTraceElement;
-                Java_java_nio_Bits_copyFromShortArray;
-                Java_java_nio_Bits_copyToShortArray;
-                Java_java_nio_Bits_copyFromIntArray;
-                Java_java_nio_Bits_copyToIntArray;
-                Java_java_nio_Bits_copyFromLongArray;
-                Java_java_nio_Bits_copyToLongArray;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
 		Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2;
--- a/jdk/make/mapfiles/libnet/mapfile-vers	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -87,6 +87,9 @@
 		Java_java_net_PlainSocketImpl_socketConnect;
 		Java_java_net_PlainDatagramSocketImpl_getTimeToLive;
 		Java_java_net_PlainDatagramSocketImpl_setTimeToLive;
+                Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0;
+                Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0;
+                Java_jdk_net_Sockets_isReusePortAvailable0;
 		Java_sun_net_PortConfig_getUpper0;
 		Java_sun_net_PortConfig_getLower0;
 		Java_sun_net_dns_ResolverConfigurationImpl_localDomain0;
@@ -112,6 +115,7 @@
 		NET_EnableFastTcpLoopback;
 		NET_ThrowNew;
                 ipv6_available;
+                reuseport_available;
                 initInetAddressIDs;
 
 	local:
--- a/jdk/make/mapfiles/libnio/mapfile-linux	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/mapfiles/libnio/mapfile-linux	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -109,6 +109,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/mapfiles/libnio/mapfile-macosx	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/mapfiles/libnio/mapfile-macosx	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -102,6 +102,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/mapfiles/libnio/mapfile-solaris	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/mapfiles/libnio/mapfile-solaris	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -97,6 +97,7 @@
 		Java_sun_nio_ch_Net_setIntOption0;
                 Java_sun_nio_ch_Net_initIDs;
 		Java_sun_nio_ch_Net_isIPv6Available0;
+                Java_sun_nio_ch_Net_isReusePortAvailable0;
 		Java_sun_nio_ch_Net_joinOrDrop4;
 		Java_sun_nio_ch_Net_blockOrUnblock4;
 		Java_sun_nio_ch_Net_joinOrDrop6;
--- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java	Mon Feb 29 15:42:34 2016 +0000
@@ -248,10 +248,7 @@
             dir.mkdirs();
         }
         String className =
-            (CLDRConverter.isBaseModule ? "CLDRBaseLocaleDataMetaInfo" :
-                "CLDRLocaleDataMetaInfo_" +
-                CLDRConverter.DESTINATION_DIR.substring(CLDRConverter.DESTINATION_DIR.lastIndexOf('/')+1)
-                    .replaceAll("\\.", "_"));
+            (CLDRConverter.isBaseModule ? "CLDRBaseLocaleDataMetaInfo" : "CLDRLocaleDataMetaInfo");
         File file = new File(dir, className + ".java");
         if (!file.exists()) {
             file.createNewFile();
--- a/jdk/make/src/classes/build/tools/dtdbuilder/DTDParser.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/src/classes/build/tools/dtdbuilder/DTDParser.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -908,16 +908,12 @@
             this.dtd = dtd;
             this.in = new DTDInputStream(in, dtd);
 
-            long tm = System.currentTimeMillis();
             ch = this.in.read();
             parseSection();
 
             if (ch != -1) {
                 error("premature");
             }
-
-            tm = System.currentTimeMillis() - tm;
-            System.err.println("[Parsed DTD " + dtd + " in " + tm + "ms]");
         } catch (IOException e) {
             error("ioexception");
         } catch (Exception e) {
--- a/jdk/make/src/classes/build/tools/module/boot.modules	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/src/classes/build/tools/module/boot.modules	Mon Feb 29 15:42:34 2016 +0000
@@ -2,6 +2,7 @@
 java.compiler
 java.datatransfer
 java.desktop
+java.httpclient
 java.instrument
 java.logging
 java.management
--- a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,21 @@
 #include <netinet/tcp.h>
 #endif
 
+/* Defines SO_REUSEPORT */
+#if !defined(SO_REUSEPORT)
+#ifdef _WIN32
+#define SO_REUSEPORT 0
+#elif __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
+
 /**
  * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level
  * socket options to the platform specific level and option.
@@ -102,6 +117,7 @@
     emit_unspec("StandardSocketOptions.SO_SNDBUF",    SOL_SOCKET, SO_SNDBUF);
     emit_unspec("StandardSocketOptions.SO_RCVBUF",    SOL_SOCKET, SO_RCVBUF);
     emit_unspec("StandardSocketOptions.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR);
+    emit_unspec("StandardSocketOptions.SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT);
     emit_unspec("StandardSocketOptions.TCP_NODELAY",  IPPROTO_TCP, TCP_NODELAY);
 
     emit_inet("StandardSocketOptions.IP_TOS",            IPPROTO_IP,     IP_TOS);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1026,6 +1026,9 @@
   .asCollector(long[].class, 1);
 assertEquals("[123]", (String) longsToString.invokeExact((long)123));
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @param arrayLength the number of arguments to collect into a new array argument
      * @return a new method handle which collects some trailing argument
@@ -1067,6 +1070,9 @@
     swWrite4.invoke('W', 'X', 'Y', 'Z', 3, 1);
     assertEquals("BCPQRSZ", swr.toString());
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param collectArgPos the zero-based position in the parameter list at which to start collecting.
      * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
      * @param arrayLength the number of arguments to collect into a new array argument
@@ -1356,8 +1362,11 @@
      * The reference {@code x} must be convertible to the first parameter
      * type of the target.
      * <p>
-     * (<em>Note:</em>  Because method handles are immutable, the target method handle
-     * retains its original type and behavior.)
+     * <em>Note:</em>  Because method handles are immutable, the target method handle
+     * retains its original type and behavior.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param x  the value to bind to the first argument of the target
      * @return a new method handle which prepends the given value to the incoming
      *         argument list, before calling the original method handle
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -778,8 +778,21 @@
             return (asTypeCache = wrapper);
         }
 
+        // Customize target if counting happens for too long.
+        private int invocations = CUSTOMIZE_THRESHOLD;
+        private void maybeCustomizeTarget() {
+            int c = invocations;
+            if (c >= 0) {
+                if (c == 1) {
+                    target.customize();
+                }
+                invocations = c - 1;
+            }
+        }
+
         boolean countDown() {
             int c = count;
+            maybeCustomizeTarget();
             if (c <= 1) {
                 // Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
                 if (isCounting) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Mon Feb 29 15:42:34 2016 +0000
@@ -2139,7 +2139,7 @@
      * if its index does not appear in the array.
      * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
      * incoming arguments which are not mentioned in the reordering array
-     * are may be any type, as determined only by {@code newType}.
+     * may be of any type, as determined only by {@code newType}.
      * <blockquote><pre>{@code
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
@@ -2157,6 +2157,9 @@
 assert(twice.type().equals(intfn1));
 assert((int)twice.invokeExact(21) == 42);
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after arguments are reordered
      * @param newType the expected type of the new method handle
      * @param reorder an index array which controls the reordering
@@ -2421,6 +2424,9 @@
      * It may range between zero and <i>N-L</i> (inclusively),
      * where <i>N</i> is the arity of the target method handle
      * and <i>L</i> is the length of the values array.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after the argument is inserted
      * @param pos where to insert the argument (zero for the first)
      * @param values the series of arguments to insert
@@ -2639,14 +2645,25 @@
 MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
 assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * denotes the return type of both the {@code target} and resulting adapter.
+     * {@code P}/{@code p} and {@code B}/{@code b} represent the types and values
+     * of the parameters and arguments that precede and follow the filter position
+     * {@code pos}, respectively. {@code A[i]}/{@code a[i]} stand for the types and
+     * values of the filtered parameters and arguments; they also represent the
+     * return types of the {@code filter[i]} handles. The latter accept arguments
+     * {@code v[i]} of type {@code V[i]}, which also appear in the signature of
+     * the resulting adapter.
      * <blockquote><pre>{@code
-     * V target(P... p, A[i]... a[i], B... b);
+     * T target(P... p, A[i]... a[i], B... b);
      * A[i] filter[i](V[i]);
      * T adapter(P... p, V[i]... v[i], B... b) {
-     *   return target(p..., f[i](v[i])..., b...);
+     *   return target(p..., filter[i](v[i])..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after arguments are filtered
      * @param pos the position of the first argument to filter
@@ -2753,7 +2770,17 @@
 assertEquals("[top, [[up, down, strange], charm], bottom]",
              (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the return type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} stand for the return type and value of the
+     * {@code filter}, which are also found in the signature and arguments of
+     * the {@code target}, respectively, unless {@code V} is {@code void}.
+     * {@code A}/{@code a} and {@code C}/{@code c} represent the parameter types
+     * and values preceding and following the collection position, {@code pos},
+     * in the {@code target}'s signature. They also turn up in the resulting
+     * adapter's signature and arguments, where they surround
+     * {@code B}/{@code b}, which represent the parameter types and arguments
+     * to the {@code filter} (if any).
      * <blockquote><pre>{@code
      * T target(A...,V,C...);
      * V filter(B...);
@@ -2771,7 +2798,7 @@
      * // and if the filter has a void return:
      * T target3(A...,C...);
      * void filter3(B...);
-     * void adapter3(A... a,B... b,C... c) {
+     * T adapter3(A... a,B... b,C... c) {
      *   filter3(b...);
      *   return target3(a...,c...);
      * }
@@ -2791,6 +2818,9 @@
      * a non-void result, then {@code collectArguments(mh, N, coll)}
      * is equivalent to {@code filterArguments(mh, N, coll)}.
      * Other equivalences are possible but would require argument permutation.
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after filtering the subsequence of arguments
      * @param pos the position of the first adapter argument to pass to the filter,
@@ -2864,29 +2894,36 @@
 MethodHandle f0 = filterReturnValue(cat, length);
 System.out.println((int) f0.invokeExact("x", "y")); // 2
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code,
+     * {@code T}/{@code t} represent the result type and value of the
+     * {@code target}; {@code V}, the result type of the {@code filter}; and
+     * {@code A}/{@code a}, the types and values of the parameters and arguments
+     * of the {@code target} as well as the resulting adapter.
      * <blockquote><pre>{@code
-     * V target(A...);
-     * T filter(V);
-     * T adapter(A... a) {
-     *   V v = target(a...);
-     *   return filter(v);
+     * T target(A...);
+     * V filter(T);
+     * V adapter(A... a) {
+     *   T t = target(a...);
+     *   return filter(t);
      * }
      * // and if the target has a void return:
      * void target2(A...);
-     * T filter2();
-     * T adapter2(A... a) {
+     * V filter2();
+     * V adapter2(A... a) {
      *   target2(a...);
      *   return filter2();
      * }
      * // and if the filter has a void return:
-     * V target3(A...);
+     * T target3(A...);
      * void filter3(V);
      * void adapter3(A... a) {
-     *   V v = target3(a...);
-     *   filter3(v);
+     *   T t = target3(a...);
+     *   filter3(t);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke before filtering the return value
      * @param filter method handle to call on the return value
      * @return method handle which incorporates the specified return value filtering logic
@@ -2964,7 +3001,15 @@
 // also prints "boo":
 assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the result type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} represent the type and value of the parameter and argument
+     * of {@code target} that precedes the folding position; {@code V} also is
+     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+     * types and values of the {@code N} parameters and arguments at the folding
+     * position. {@code B}/{@code b} represent the types and values of the
+     * {@code target} parameters and arguments that follow the folded parameters
+     * and arguments.
      * <blockquote><pre>{@code
      * // there are N arguments in A...
      * T target(V, A[N]..., B...);
@@ -2981,6 +3026,9 @@
      *   return target2(a..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      * @param target the method handle to invoke after arguments are combined
      * @param combiner method handle to call initially on the incoming arguments
      * @return method handle which incorporates the specified argument folding logic
@@ -3022,7 +3070,13 @@
      * argument and return types, except that the return type
      * of the test must be boolean, and the test is allowed
      * to have fewer arguments than the other two method handles.
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>
+     * Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the uniform result type of the three involved handles;
+     * {@code A}/{@code a}, the types and values of the {@code target}
+     * parameters and arguments that are consumed by the {@code test}; and
+     * {@code B}/{@code b}, those types and values of the {@code target}
+     * parameters and arguments that are not consumed by the {@code test}.
      * <blockquote><pre>{@code
      * boolean test(A...);
      * T target(A...,B...);
@@ -3084,7 +3138,13 @@
      * argument and return types, except that handler may omit trailing arguments
      * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
      * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>
+     * Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the return type of the {@code target} and {@code handler},
+     * and correspondingly that of the resulting adapter; {@code A}/{@code a},
+     * the types and values of arguments to the resulting handle consumed by
+     * {@code handler}; and {@code B}/{@code b}, those of arguments to the
+     * resulting handle discarded by {@code handler}.
      * <blockquote><pre>{@code
      * T target(A..., B...);
      * T handler(ExType, A...);
@@ -3828,8 +3888,9 @@
      * (Note that, except for argument type conversions, combinators represent {@code void} values in parameter lists
      * by omitting the corresponding paradoxical arguments, not by inserting {@code null} or zero values.)
      * <p>
-     * The {@code target} and {@code cleanup} handles' return types must be the same. Their parameter type lists also
-     * must be the same, but the {@code cleanup} handle must accept one or two more leading parameters:<ul>
+     * The {@code target} and {@code cleanup} handles must have the same corresponding argument and return types, except
+     * that the {@code cleanup} handle may omit trailing arguments. Also, the {@code cleanup} handle must have one or
+     * two extra leading parameters:<ul>
      * <li>a {@code Throwable}, which will carry the exception thrown by the {@code target} handle (if any); and
      * <li>a parameter of the same type as the return type of both {@code target} and {@code cleanup}, which will carry
      * the result from the execution of the {@code target} handle.
@@ -3932,7 +3993,16 @@
     // also prints "jum":
     assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
      * }</pre></blockquote>
-     * <p> Here is pseudocode for the resulting adapter:
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the result type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} represent the type and value of the parameter and argument
+     * of {@code target} that precedes the folding position; {@code V} also is
+     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+     * types and values of the {@code N} parameters and arguments at the folding
+     * position. {@code Z}/{@code z} and {@code B}/{@code b} represent the types
+     * and values of the {@code target} parameters and arguments that precede and
+     * follow the folded parameters and arguments starting at {@code pos},
+     * respectively.
      * <blockquote><pre>{@code
      * // there are N arguments in A...
      * T target(Z..., V, A[N]..., B...);
@@ -3949,6 +4019,9 @@
      *   return target2(z..., a..., b...);
      * }
      * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
      *
      * @param target the method handle to invoke after arguments are combined
      * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
@@ -4064,8 +4137,10 @@
         // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
         // target parameter list.
         int cleanupArgIndex = rtype == void.class ? 1 : 2;
-        if (!cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size()).
-                equals(target.type().parameterList().subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
+        List<Class<?>> cleanupArgSuffix = cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size());
+        List<Class<?>> targetParamTypes = target.type().parameterList();
+        if (targetParamTypes.size() < cleanupArgSuffix.size() ||
+                !cleanupArgSuffix.equals(targetParamTypes.subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
             throw misMatchedTypes("cleanup parameters after (Throwable,result) and target parameter list prefix",
                     cleanup.type(), target.type());
         }
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,9 @@
 import java.io.IOException;
 import java.security.AccessController;
 import sun.net.ResourceManager;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * Abstract datagram and multicast socket implementation base class.
@@ -70,6 +73,45 @@
             });
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    private static volatile Set<SocketOption<?>> socketOptions;
+
+    /**
+     * Returns a set of SocketOptions supported by this impl
+     * and by this impl's socket (Socket or ServerSocket)
+     *
+     * @return a Set of SocketOptions
+     */
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        Set<SocketOption<?>> options = socketOptions;
+        if (options == null) {
+            if (isReusePortAvailable()) {
+                options = new HashSet<>();
+                options.addAll(super.supportedOptions());
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+                options = Collections.unmodifiableSet(options);
+            } else {
+                options = super.supportedOptions();
+            }
+            socketOptions = options;
+        }
+        return options;
+    }
+
     /**
      * Creates a datagram socket
      */
@@ -303,6 +345,14 @@
              if (o == null || !(o instanceof Boolean))
                  throw new SocketException("bad argument for IP_MULTICAST_LOOP");
              break;
+         case SO_REUSEPORT:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_REUSEPORT");
+             }
+             if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                 throw new UnsupportedOperationException("unsupported option");
+             }
+             break;
          default:
              throw new SocketException("invalid option: " + optID);
          }
@@ -343,6 +393,13 @@
                 result = socketGetOption(optID);
                 break;
 
+            case SO_REUSEPORT:
+                if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+                result = socketGetOption(optID);
+                break;
+
             default:
                 throw new SocketException("invalid option: " + optID);
         }
@@ -364,4 +421,5 @@
     }
 
     abstract int dataAvailable();
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,9 @@
 import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
 import sun.net.ResourceManager;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * Default Socket Implementation. This implementation does
@@ -87,6 +90,45 @@
             });
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    private static volatile Set<SocketOption<?>> socketOptions;
+
+   /**
+    * Returns a set of SocketOptions supported by this impl
+    * and by this impl's socket (Socket or ServerSocket)
+    *
+    * @return a Set of SocketOptions
+    */
+    @Override
+    protected Set<SocketOption<?>> supportedOptions() {
+        Set<SocketOption<?>> options = socketOptions;
+        if (options == null) {
+            if (isReusePortAvailable()) {
+                options = new HashSet<>();
+                options.addAll(super.supportedOptions());
+                options.add(StandardSocketOptions.SO_REUSEPORT);
+                options = Collections.unmodifiableSet(options);
+            } else {
+                options = super.supportedOptions();
+            }
+            socketOptions = options;
+        }
+        return options;
+    }
+
     /**
      * Creates a socket with a boolean that specifies whether this
      * is a stream socket (true) or an unconnected UDP socket (false).
@@ -269,6 +311,13 @@
                 throw new SocketException("bad parameter for SO_REUSEADDR");
             on = ((Boolean)val).booleanValue();
             break;
+        case SO_REUSEPORT:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_REUSEPORT");
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT))
+                throw new UnsupportedOperationException("unsupported option");
+            on = ((Boolean)val).booleanValue();
+            break;
         default:
             throw new SocketException("unrecognized TCP option: " + opt);
         }
@@ -326,6 +375,12 @@
         case SO_KEEPALIVE:
             ret = socketGetOption(opt, null);
             return Boolean.valueOf(ret != -1);
+        case SO_REUSEPORT:
+            if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+                throw new UnsupportedOperationException("unsupported option");
+            }
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
         // should never get here
         default:
             return null;
@@ -723,4 +778,6 @@
 
     public static final int SHUT_RD = 0;
     public static final int SHUT_WR = 1;
+
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/java/net/Authenticator.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/Authenticator.java	Mon Feb 29 15:42:34 2016 +0000
@@ -320,6 +320,48 @@
     }
 
     /**
+     * Ask this authenticator for a password.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     * @param url The requesting URL that caused the authentication
+     * @param reqType The type (server or proxy) of the entity requesting
+     *              authentication.
+     *
+     * @return The username/password, or null if one can't be gotten
+     *
+     * @since 9
+     */
+    public PasswordAuthentication
+    requestPasswordAuthenticationInstance(String host,
+                                          InetAddress addr,
+                                          int port,
+                                          String protocol,
+                                          String prompt,
+                                          String scheme,
+                                          URL url,
+                                          RequestorType reqType) {
+        synchronized (this) {
+            this.reset();
+            this.requestingHost = host;
+            this.requestingSite = addr;
+            this.requestingPort = port;
+            this.requestingProtocol = protocol;
+            this.requestingPrompt = prompt;
+            this.requestingScheme = scheme;
+            this.requestingURL = url;
+            this.requestingAuthType = reqType;
+            return this.getPasswordAuthentication();
+        }
+    }
+
+    /**
      * Gets the {@code hostname} of the
      * site or proxy requesting authentication, or {@code null}
      * if not available.
--- a/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -287,6 +287,9 @@
             setOption(SocketOptions.SO_RCVBUF, value);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            setOption(SocketOptions.SO_REUSEPORT, value);
         } else if (name == StandardSocketOptions.IP_TOS) {
             setOption(SocketOptions.IP_TOS, value);
         } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
@@ -329,6 +332,9 @@
             return (T) getOption(SocketOptions.SO_RCVBUF);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             return (T) getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            return (T) getOption(SocketOptions.SO_REUSEPORT);
         } else if (name == StandardSocketOptions.IP_TOS) {
             return (T) getOption(SocketOptions.IP_TOS);
         } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
--- a/jdk/src/java.base/share/classes/java/net/JarURLConnection.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/JarURLConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -173,6 +173,14 @@
         }
 
         jarFileURL = new URL(spec.substring(0, separator++));
+        /*
+         * The url argument may have had a runtime fragment appended, so
+         * we need to add a runtime fragment to the jarFileURL to enable
+         * runtime versioning when the underlying jar file is opened.
+         */
+        if ("runtime".equals(url.getRef())) {
+            jarFileURL = new URL(jarFileURL, "#runtime");
+        }
         entryName = null;
 
         /* if ! is the last letter of the innerURL, entryName is null */
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -98,7 +98,11 @@
      * <p>
      * When the socket is created the
      * {@link DatagramSocket#setReuseAddress(boolean)} method is
-     * called to enable the SO_REUSEADDR socket option.
+     * called to enable the SO_REUSEADDR socket option. When
+     * {@link StandardSocketOptions#SO_REUSEPORT SO_REUSEPORT} is
+     * supported then
+     * {@link DatagramSocketImpl#setOption(SocketOption, Object)}
+     * is called to enable the socket option.
      *
      * @exception IOException if an I/O exception occurs
      * while creating the MulticastSocket
@@ -106,6 +110,7 @@
      *             {@code checkListen} method doesn't allow the operation.
      * @see SecurityManager#checkListen
      * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object)
      */
     public MulticastSocket() throws IOException {
         this(new InetSocketAddress(0));
@@ -167,6 +172,11 @@
         // Enable SO_REUSEADDR before binding
         setReuseAddress(true);
 
+        // Enable SO_REUSEPORT if supported before binding
+        if (supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            this.setOption(StandardSocketOptions.SO_REUSEPORT, true);
+        }
+
         if (bindaddr != null) {
             try {
                 bind(bindaddr);
--- a/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Mon Feb 29 15:42:34 2016 +0000
@@ -162,4 +162,49 @@
      * @throws IllegalArgumentException if either argument is null
      */
     public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe);
+
+    /**
+     * Returns a ProxySelector which uses the given proxy address for all HTTP
+     * and HTTPS requests. If proxy is {@code null} then proxying is disabled.
+     *
+     * @param proxyAddress
+     *        The address of the proxy
+     *
+     * @return a ProxySelector
+     *
+     * @since 9
+     */
+    public static ProxySelector of(InetSocketAddress proxyAddress) {
+        return new StaticProxySelector(proxyAddress);
+    }
+
+    static class StaticProxySelector extends ProxySelector {
+        private static final List<Proxy> NO_PROXY_LIST = List.of(Proxy.NO_PROXY);
+        final List<Proxy> list;
+
+        StaticProxySelector(InetSocketAddress address){
+            Proxy p;
+            if (address == null) {
+                p = Proxy.NO_PROXY;
+            } else {
+                p = new Proxy(Proxy.Type.HTTP, address);
+            }
+            list = List.of(p);
+        }
+
+        @Override
+        public void connectFailed(URI uri, SocketAddress sa, IOException e) {
+            /* ignore */
+        }
+
+        @Override
+        public synchronized List<Proxy> select(URI uri) {
+            String scheme = uri.getScheme().toLowerCase();
+            if (scheme.equals("http") || scheme.equals("https")) {
+                return list;
+            } else {
+                return NO_PROXY_LIST;
+            }
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -386,6 +386,9 @@
             setOption(SocketOptions.SO_RCVBUF, value);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            setOption(SocketOptions.SO_REUSEPORT, value);
         } else if (name == StandardSocketOptions.SO_LINGER &&
                 (getSocket() != null)) {
             setOption(SocketOptions.SO_LINGER, value);
@@ -426,6 +429,9 @@
             return (T)getOption(SocketOptions.SO_RCVBUF);
         } else if (name == StandardSocketOptions.SO_REUSEADDR) {
             return (T)getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_REUSEPORT &&
+            supportedOptions().contains(name)) {
+            return (T)getOption(SocketOptions.SO_REUSEPORT);
         } else if (name == StandardSocketOptions.SO_LINGER &&
                 (getSocket() != null)) {
             return (T)getOption(SocketOptions.SO_LINGER);
--- a/jdk/src/java.base/share/classes/java/net/SocketOptions.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/SocketOptions.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -170,6 +170,17 @@
 
     @Native public static final int SO_REUSEADDR = 0x04;
 
+    /** Sets SO_REUSEPORT for a socket. This option enables and disables
+     *  the ability to have multiple sockets listen to the same address
+     *  and port.
+     * <P>
+     * Valid for: SocketImpl, DatagramSocketImpl
+     *
+     * @since 9
+     * @see StandardSocketOptions#SO_REUSEPORT
+     */
+    @Native public static final int SO_REUSEPORT = 0x0E;
+
     /**
      * Sets SO_BROADCAST for a socket. This option enables and disables
      * the ability of the process to send broadcast messages. It is supported
--- a/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -187,6 +187,29 @@
         new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
 
     /**
+     * Re-use port.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The exact semantics of this
+     * socket option are socket type and system dependent.
+     *
+     * <p> In the case of stream-oriented sockets, this socket option usually allows
+     * multiple listening sockets to be bound to both same address
+     * and same port.
+     *
+     * <p> For datagram-oriented sockets the socket option usually allows
+     * multiple UDP sockets to be bound to the same address and port.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Changing the value of this socket option
+     * after the socket is bound has no effect.
+     *
+     * @since 9
+     */
+    public static final SocketOption<Boolean> SO_REUSEPORT =
+        new StdSocketOption<Boolean>("SO_REUSEPORT", Boolean.class);
+
+    /**
      * Linger on close if data is present.
      *
      * <p> The value of this socket option is an {@code Integer} that controls
--- a/jdk/src/java.base/share/classes/java/net/package-info.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/net/package-info.java	Mon Feb 29 15:42:34 2016 +0000
@@ -121,7 +121,8 @@
  *            underlying protocol handlers like http or https.</li>
  *       <li>{@link java.net.HttpURLConnection} is a subclass of URLConnection
  *            and provides some additional functionalities specific to the
- *            HTTP protocol.</li>
+ *            HTTP protocol. This API has been superceded by the newer
+              HTTP client API described in the previous section.</li>
  * </ul>
  * <p>The recommended usage is to use {@link java.net.URI} to identify
  *    resources, then convert it into a {@link java.net.URL} when it is time to
--- a/jdk/src/java.base/share/classes/java/nio/Bits.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/nio/Bits.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -807,31 +807,131 @@
         }
     }
 
-    static void copyFromCharArray(Object src, long srcPos, long dstAddr,
-                                  long length)
-    {
-        copyFromShortArray(src, srcPos, dstAddr, length);
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 16-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromCharArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
     }
 
-    static void copyToCharArray(long srcAddr, Object dst, long dstPos,
-                                long length)
-    {
-        copyToShortArray(srcAddr, dst, dstPos, length);
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 16-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToCharArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 16-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromShortArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 16-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToShortArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
     }
 
-    static native void copyFromShortArray(Object src, long srcPos, long dstAddr,
-                                          long length);
-    static native void copyToShortArray(long srcAddr, Object dst, long dstPos,
-                                        long length);
+    /**
+     * Copy and unconditionally byte swap 32 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 32-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromIntArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 4);
+    }
+
+    /**
+     * Copy and unconditionally byte swap 32 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 32-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToIntArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 4);
+    }
 
-    static native void copyFromIntArray(Object src, long srcPos, long dstAddr,
-                                        long length);
-    static native void copyToIntArray(long srcAddr, Object dst, long dstPos,
-                                      long length);
+    /**
+     * Copy and unconditionally byte swap 64 bit elements from a heap array to off-heap memory
+     *
+     * @param src
+     *        the source array, must be a 64-bit primitive array type
+     * @param srcPos
+     *        byte offset within source array of the first element to read
+     * @param dstAddr
+     *        destination address
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyFromLongArray(Object src, long srcPos, long dstAddr, long length) {
+        unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 8);
+    }
 
-    static native void copyFromLongArray(Object src, long srcPos, long dstAddr,
-                                         long length);
-    static native void copyToLongArray(long srcAddr, Object dst, long dstPos,
-                                       long length);
-
+    /**
+     * Copy and unconditionally byte swap 64 bit elements from off-heap memory to a heap array
+     *
+     * @param srcAddr
+     *        source address
+     * @param dst
+     *        destination array, must be a 64-bit primitive array type
+     * @param dstPos
+     *        byte offset within the destination array of the first element to write
+     * @param length
+     *        number of bytes to copy
+     */
+    static void copyToLongArray(long srcAddr, Object dst, long dstPos, long length) {
+        unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 8);
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/Currency.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/Currency.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,7 +92,12 @@
  * and the remainder of entries in file are processed. For instances where duplicate
  * country code entries exist, the behavior of the Currency information for that
  * {@code Currency} is undefined and the remainder of entries in file are processed.
+ * <p>
+ * It is recommended to use {@link java.math.BigDecimal} class while dealing
+ * with {@code Currency} or monetary values as it provides better handling of floating
+ * point numbers and their operations.
  *
+ * @see java.math.BigDecimal
  * @since 1.4
  */
 public final class Currency implements Serializable {
@@ -516,14 +521,16 @@
     }
 
     /**
-     * Gets the default number of fraction digits used with this currency.
-     * For example, the default number of fraction digits for the Euro is 2,
-     * while for the Japanese Yen it's 0.
-     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
-     * -1 is returned.
-     *
-     * @return the default number of fraction digits used with this currency
-     */
+    * Gets the default number of fraction digits used with this currency.
+    * Note that the number of fraction digits is the same as ISO 4217's
+    * minor unit for the currency.
+    * For example, the default number of fraction digits for the Euro is 2,
+    * while for the Japanese Yen it's 0.
+    * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
+    * -1 is returned.
+    *
+    * @return the default number of fraction digits used with this currency
+    */
     public int getDefaultFractionDigits() {
         return defaultFractionDigits;
     }
--- a/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -646,5 +646,13 @@
          * manifest attribute used for package versioning.
          */
         public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
+
+        /**
+         * {@code Name} object for {@code Multi-Release}
+         * manifest attribute that indicates this is a multi-release JAR file.
+         *
+         * @since   9
+         */
+        public static final Name MULTI_RELEASE = new Name("Multi-Release");
     }
 }
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Mon Feb 29 15:42:34 2016 +0000
@@ -28,6 +28,7 @@
 import java.io.*;
 import java.lang.ref.SoftReference;
 import java.net.URL;
+import java.security.PrivilegedAction;
 import java.util.*;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
@@ -37,28 +38,91 @@
 import java.security.AccessController;
 import java.security.CodeSource;
 import jdk.internal.misc.SharedSecrets;
-import sun.security.action.GetPropertyAction;
 import sun.security.util.ManifestEntryVerifier;
 import sun.security.util.SignatureFileVerifier;
 
+import static java.util.jar.Attributes.Name.MULTI_RELEASE;
+
 /**
  * The {@code JarFile} class is used to read the contents of a jar file
  * from any file that can be opened with {@code java.io.RandomAccessFile}.
  * It extends the class {@code java.util.zip.ZipFile} with support
- * for reading an optional {@code Manifest} entry. The
- * {@code Manifest} can be used to specify meta-information about the
- * jar file and its entries.
+ * for reading an optional {@code Manifest} entry, and support for
+ * processing multi-release jar files.  The {@code Manifest} can be used
+ * to specify meta-information about the jar file and its entries.
+ *
+ * <p>A multi-release jar file is a jar file that contains
+ * a manifest with a main attribute named "Multi-Release",
+ * a set of "base" entries, some of which are public classes with public
+ * or protected methods that comprise the public interface of the jar file,
+ * and a set of "versioned" entries contained in subdirectories of the
+ * "META-INF/versions" directory.  The versioned entries are partitioned by the
+ * major version of the Java platform.  A versioned entry, with a version
+ * {@code n}, {@code 8 < n}, in the "META-INF/versions/{n}" directory overrides
+ * the base entry as well as any entry with a version number {@code i} where
+ * {@code 8 < i < n}.
+ *
+ * <p>By default, a {@code JarFile} for a multi-release jar file is configured
+ * to process the multi-release jar file as if it were a plain (unversioned) jar
+ * file, and as such an entry name is associated with at most one base entry.
+ * The {@code JarFile} may be configured to process a multi-release jar file by
+ * creating the {@code JarFile} with the
+ * {@link JarFile#JarFile(File, boolean, int, Release)} constructor.  The
+ * {@code Release} object sets a maximum version used when searching for
+ * versioned entries.  When so configured, an entry name
+ * can correspond with at most one base entry and zero or more versioned
+ * entries. A search is required to associate the entry name with the latest
+ * versioned entry whose version is less than or equal to the maximum version
+ * (see {@link #getEntry(String)}).
+ *
+ * <p>Class loaders that utilize {@code JarFile} to load classes from the
+ * contents of {@code JarFile} entries should construct the {@code JarFile}
+ * by invoking the {@link JarFile#JarFile(File, boolean, int, Release)}
+ * constructor with the value {@code Release.RUNTIME} assigned to the last
+ * argument.  This assures that classes compatible with the major
+ * version of the running JVM are loaded from multi-release jar files.
+ *
+ * <p>If the verify flag is on when opening a signed jar file, the content of
+ * the file is verified against its signature embedded inside the file. Please
+ * note that the verification process does not include validating the signer's
+ * certificate. A caller should inspect the return value of
+ * {@link JarEntry#getCodeSigners()} to further determine if the signature
+ * can be trusted.
  *
  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  * or method in this class will cause a {@link NullPointerException} to be
  * thrown.
  *
- * If the verify flag is on when opening a signed jar file, the content of the
- * file is verified against its signature embedded inside the file. Please note
- * that the verification process does not include validating the signer's
- * certificate. A caller should inspect the return value of
- * {@link JarEntry#getCodeSigners()} to further determine if the signature
- * can be trusted.
+ * @implNote
+ * <div class="block">
+ * If the API can not be used to configure a {@code JarFile} (e.g. to override
+ * the configuration of a compiled application or library), two {@code System}
+ * properties are available.
+ * <ul>
+ * <li>
+ * {@code jdk.util.jar.version} can be assigned a value that is the
+ * {@code String} representation of a non-negative integer
+ * {@code <= Version.current().major()}.  The value is used to set the effective
+ * runtime version to something other than the default value obtained by
+ * evaluating {@code Version.current().major()}. The effective runtime version
+ * is the version that the {@link JarFile#JarFile(File, boolean, int, Release)}
+ * constructor uses when the value of the last argument is
+ * {@code Release.RUNTIME}.
+ * </li>
+ * <li>
+ * {@code jdk.util.jar.enableMultiRelease} can be assigned one of the three
+ * {@code String} values <em>true</em>, <em>false</em>, or <em>force</em>.  The
+ * value <em>true</em>, the default value, enables multi-release jar file
+ * processing.  The value <em>false</em> disables multi-release jar processing,
+ * ignoring the "Multi-Release" manifest attribute, and the versioned
+ * directories in a multi-release jar file if they exist.  Furthermore,
+ * the method {@link JarFile#isMultiRelease()} returns <em>false</em>. The value
+ * <em>force</em> causes the {@code JarFile} to be initialized to runtime
+ * versioning after construction.  It effectively does the same as this code:
+ * {@code (new JarFile(File, boolean, int, Release.RUNTIME)}.
+ * </li>
+ * </ul>
+ * </div>
  *
  * @author  David Connelly
  * @see     Manifest
@@ -68,26 +132,126 @@
  */
 public
 class JarFile extends ZipFile {
+    private final static int BASE_VERSION;
+    private final static int RUNTIME_VERSION;
+    private final static boolean MULTI_RELEASE_ENABLED;
+    private final static boolean MULTI_RELEASE_FORCED;
     private SoftReference<Manifest> manRef;
     private JarEntry manEntry;
     private JarVerifier jv;
     private boolean jvInitialized;
     private boolean verify;
+    private final int version;
+    private boolean notVersioned;
+    private final boolean runtimeVersioned;
 
     // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true)
     private boolean hasClassPathAttribute;
     // true if manifest checked for special attributes
     private volatile boolean hasCheckedSpecialAttributes;
 
-    // Set up JavaUtilJarAccess in SharedSecrets
     static {
+        // Set up JavaUtilJarAccess in SharedSecrets
         SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
+
+        BASE_VERSION = 8;  // one less than lowest version for versioned entries
+        RUNTIME_VERSION = AccessController.doPrivileged(
+                new PrivilegedAction<Integer>() {
+                    public Integer run() {
+                        Integer v = sun.misc.Version.jdkMajorVersion(); // fixme when JEP 223 Version integrated
+                        Integer i = Integer.getInteger("jdk.util.jar.version", v);
+                        i = i < 0 ? 0 : i;
+                        return i > v ? v : i;
+                    }
+                }
+        );
+        String multi_release = AccessController.doPrivileged(
+                new PrivilegedAction<String>() {
+                    public String run() {
+                        return System.getProperty("jdk.util.jar.enableMultiRelease", "true");
+                    }
+                }
+        );
+        switch (multi_release) {
+            case "true":
+            default:
+                MULTI_RELEASE_ENABLED = true;
+                MULTI_RELEASE_FORCED = false;
+                break;
+            case "false":
+                MULTI_RELEASE_ENABLED = false;
+                MULTI_RELEASE_FORCED = false;
+                break;
+            case "force":
+                MULTI_RELEASE_ENABLED = true;
+                MULTI_RELEASE_FORCED = true;
+                break;
+        }
     }
 
     /**
+     * A set of constants that represent the entries in either the base directory
+     * or one of the versioned directories in a multi-release jar file.  It's
+     * possible for a multi-release jar file to contain versioned directories
+     * that are not represented by the constants of the {@code Release} enum.
+     * In those cases, the entries will not be located by this {@code JarFile}
+     * through the aliasing mechanism, but they can be directly accessed by
+     * specifying the full path name of the entry.
+     *
+     * @since 9
+     */
+    public enum Release {
+        /**
+         * Represents unversioned entries, or entries in "regular", as opposed
+         * to multi-release jar files.
+         */
+        BASE(BASE_VERSION),
+
+        /**
+         * Represents entries found in the META-INF/versions/9 directory of a
+         * multi-release jar file.
+         */
+        VERSION_9(9),
+
+        // fill in the "blanks" for future releases
+
+        /**
+         * Represents entries found in the META-INF/versions/{n} directory of a
+         * multi-release jar file, where {@code n} is the effective runtime
+         * version of the jar file.
+         *
+         * @implNote
+         * <div class="block">
+         * The effective runtime version is determined
+         * by evaluating {@code Version.current().major()} or by using the value
+         * of the {@code jdk.util.jar.version} System property if it exists.
+         * </div>
+         */
+        RUNTIME(RUNTIME_VERSION);
+
+        Release(int version) {
+            this.version = version;
+        }
+
+        private static Release valueOf(int version) {
+            return version <= BASE.value() ? BASE : valueOf("VERSION_" + version);
+        }
+
+        private final int version;
+
+        private int value() {
+            return this.version;
+        }
+    }
+
+    private static final String META_INF = "META-INF/";
+
+    private static final String META_INF_VERSIONS = META_INF + "versions/";
+
+    /**
      * The JAR manifest file name.
      */
-    public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+    public static final String MANIFEST_NAME = META_INF + "MANIFEST.MF";
 
     /**
      * Creates a new {@code JarFile} to read from the specified
@@ -129,7 +293,6 @@
         this(file, true, ZipFile.OPEN_READ);
     }
 
-
     /**
      * Creates a new {@code JarFile} to read from the specified
      * {@code File} object.
@@ -144,7 +307,6 @@
         this(file, verify, ZipFile.OPEN_READ);
     }
 
-
     /**
      * Creates a new {@code JarFile} to read from the specified
      * {@code File} object in the specified mode.  The mode argument
@@ -162,10 +324,104 @@
      * @since 1.3
      */
     public JarFile(File file, boolean verify, int mode) throws IOException {
+        this(file, verify, mode, Release.BASE);
+        this.notVersioned = true;
+    }
+
+    /**
+     * Creates a new {@code JarFile} to read from the specified
+     * {@code File} object in the specified mode.  The mode argument
+     * must be either {@code OPEN_READ} or {@code OPEN_READ | OPEN_DELETE}.
+     * The version argument configures the {@code JarFile} for processing
+     * multi-release jar files.
+     *
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @param mode the mode in which the file is to be opened
+     * @param version specifies the release version for a multi-release jar file
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalArgumentException
+     *         if the {@code mode} argument is invalid
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     * @throws NullPointerException if {@code version} is {@code null}
+     * @since 9
+     */
+    public JarFile(File file, boolean verify, int mode, Release version) throws IOException {
         super(file, mode);
+        Objects.requireNonNull(version);
         this.verify = verify;
+        // version applies to multi-release jar files, ignored for regular jar files
+        this.version = MULTI_RELEASE_FORCED ? RUNTIME_VERSION : version.value();
+        this.runtimeVersioned = version == Release.RUNTIME;
+        assert runtimeVersionExists();
     }
 
+    private boolean runtimeVersionExists() {
+        int version = sun.misc.Version.jdkMajorVersion();  // fixme when JEP 223 integrated
+        try {
+            Release.valueOf(version);
+            return true;
+        } catch (IllegalArgumentException x) {
+            System.err.println("No JarFile.Release object for release " + version);
+            return false;
+        }
+    }
+
+    /**
+     * Returns the maximum version used when searching for versioned entries.
+     *
+     * @return the maximum version, or {@code Release.BASE} if this jar file is
+     *         processed as if it is an unversioned jar file or is not a
+     *         multi-release jar file
+     * @since 9
+     */
+    public final Release getVersion() {
+        if (isMultiRelease()) {
+            return runtimeVersioned ? Release.RUNTIME : Release.valueOf(version);
+        } else {
+            return Release.BASE;
+        }
+    }
+
+    /**
+     * Indicates whether or not this jar file is a multi-release jar file.
+     *
+     * @return true if this JarFile is a multi-release jar file
+     * @since 9
+     */
+    public final boolean isMultiRelease() {
+        // do not call this code in a constructor because some subclasses use
+        // lazy loading of manifest so it won't be available at construction time
+        if (MULTI_RELEASE_ENABLED) {
+            // Doubled-checked locking pattern
+            Boolean result = isMultiRelease;
+            if (result == null) {
+                synchronized (this) {
+                    result = isMultiRelease;
+                    if (result == null) {
+                        Manifest man = null;
+                        try {
+                            man = getManifest();
+                        } catch (IOException e) {
+                            //Ignored, manifest cannot be read
+                        }
+                        isMultiRelease = result = (man != null)
+                                && man.getMainAttributes().containsKey(MULTI_RELEASE)
+                                ? Boolean.TRUE : Boolean.FALSE;
+                    }
+                }
+            }
+            return result == Boolean.TRUE;
+        } else {
+            return false;
+        }
+    }
+    // the following field, isMultiRelease, should only be used in the method
+    // isMultiRelease(), like a static local
+    private volatile Boolean isMultiRelease;    // is jar multi-release?
+
     /**
      * Returns the jar file manifest, or {@code null} if none.
      *
@@ -209,40 +465,87 @@
     }
 
     /**
-     * Returns the {@code JarEntry} for the given entry name or
+     * Returns the {@code JarEntry} for the given base entry name or
      * {@code null} if not found.
      *
+     * <p>If this {@code JarFile} is a multi-release jar file and is configured
+     * to be processed as such, then a search is performed to find and return
+     * a {@code JarEntry} that is the latest versioned entry associated with the
+     * given entry name.  The returned {@code JarEntry} is the versioned entry
+     * corresponding to the given base entry name prefixed with the string
+     * {@code "META-INF/versions/{n}/"}, for the largest value of {@code n} for
+     * which an entry exists.  If such a versioned entry does not exist, then
+     * the {@code JarEntry} for the base entry is returned, otherwise
+     * {@code null} is returned if no entries are found.  The initial value for
+     * the version {@code n} is the maximum version as returned by the method
+     * {@link JarFile#getVersion()}.
+     *
      * @param name the jar file entry name
-     * @return the {@code JarEntry} for the given entry name or
-     *         {@code null} if not found.
+     * @return the {@code JarEntry} for the given entry name, or
+     *         the versioned entry name, or {@code null} if not found
      *
      * @throws IllegalStateException
      *         may be thrown if the jar file has been closed
      *
      * @see java.util.jar.JarEntry
+     *
+     * @implSpec
+     * <div class="block">
+     * This implementation invokes {@link JarFile#getEntry(String)}.
+     * </div>
      */
     public JarEntry getJarEntry(String name) {
         return (JarEntry)getEntry(name);
     }
 
     /**
-     * Returns the {@code ZipEntry} for the given entry name or
+     * Returns the {@code ZipEntry} for the given base entry name or
      * {@code null} if not found.
      *
+     * <p>If this {@code JarFile} is a multi-release jar file and is configured
+     * to be processed as such, then a search is performed to find and return
+     * a {@code ZipEntry} that is the latest versioned entry associated with the
+     * given entry name.  The returned {@code ZipEntry} is the versioned entry
+     * corresponding to the given base entry name prefixed with the string
+     * {@code "META-INF/versions/{n}/"}, for the largest value of {@code n} for
+     * which an entry exists.  If such a versioned entry does not exist, then
+     * the {@code ZipEntry} for the base entry is returned, otherwise
+     * {@code null} is returned if no entries are found.  The initial value for
+     * the version {@code n} is the maximum version as returned by the method
+     * {@link JarFile#getVersion()}.
+     *
      * @param name the jar file entry name
      * @return the {@code ZipEntry} for the given entry name or
-     *         {@code null} if not found
+     *         the versioned entry name or {@code null} if not found
      *
      * @throws IllegalStateException
      *         may be thrown if the jar file has been closed
      *
      * @see java.util.zip.ZipEntry
+     *
+     * @implSpec
+     * <div class="block">
+     * This implementation may return a versioned entry for the requested name
+     * even if there is not a corresponding base entry.  This can occur
+     * if there is a private or package-private versioned entry that matches.
+     * If a subclass overrides this method, assure that the override method
+     * invokes {@code super.getEntry(name)} to obtain all versioned entries.
+     * </div>
      */
     public ZipEntry getEntry(String name) {
         ZipEntry ze = super.getEntry(name);
         if (ze != null) {
             return new JarFileEntry(ze);
         }
+        // no matching base entry, but maybe there is a versioned entry,
+        // like a new private class
+        if (isMultiRelease()) {
+            ze = new ZipEntry(name);
+            ZipEntry vze = getVersionedEntry(ze);
+            if (ze != vze) {
+                return new JarFileEntry(name, vze);
+            }
+        }
         return null;
     }
 
@@ -250,14 +553,42 @@
             Iterator<JarEntry>
     {
         final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
+        ZipEntry ze;
 
         public boolean hasNext() {
-            return e.hasMoreElements();
+            if (notVersioned) {
+                return e.hasMoreElements();
+            }
+            if (ze != null) {
+                return true;
+            }
+            return findNext();
+        }
+
+        private boolean findNext() {
+            while (e.hasMoreElements()) {
+                ZipEntry ze2 = e.nextElement();
+                if (!ze2.getName().startsWith(META_INF_VERSIONS)) {
+                    ze = ze2;
+                    return true;
+                }
+            }
+            return false;
         }
 
         public JarEntry next() {
-            ZipEntry ze = e.nextElement();
-            return new JarFileEntry(ze);
+            ZipEntry ze2;
+
+            if (notVersioned) {
+                ze2 = e.nextElement();
+                return new JarFileEntry(ze2.getName(), ze2);
+            }
+            if (ze != null || findNext()) {
+                ze2 = ze;
+                ze = null;
+                return new JarFileEntry(ze2);
+            }
+            throw new NoSuchElementException();
         }
 
         public boolean hasMoreElements() {
@@ -274,7 +605,19 @@
     }
 
     /**
-     * Returns an enumeration of the jar file entries.
+     * Returns an enumeration of the jar file entries.  The set of entries
+     * returned depends on whether or not the jar file is a multi-release jar
+     * file, and on the constructor used to create the {@code JarFile}.  If the
+     * jar file is not a multi-release jar file, all entries are returned,
+     * regardless of how the {@code JarFile} is created.  If the constructor
+     * does not take a {@code Release} argument, all entries are returned.
+     * If the jar file is a multi-release jar file and the constructor takes a
+     * {@code Release} argument, then the set of entries returned is equivalent
+     * to the set of entries that would be returned if the set was built by
+     * invoking {@link JarFile#getEntry(String)} or
+     * {@link JarFile#getJarEntry(String)} with the name of each base entry in
+     * the jar file.  A base entry is an entry whose path name does not start
+     * with "META-INF/versions/".
      *
      * @return an enumeration of the jar file entries
      * @throws IllegalStateException
@@ -285,10 +628,21 @@
     }
 
     /**
-     * Returns an ordered {@code Stream} over the jar file entries.
+     * Returns an ordered {@code Stream} over all the jar file entries.
      * Entries appear in the {@code Stream} in the order they appear in
-     * the central directory of the jar file.
-     *
+     * the central directory of the jar file.  The set of entries
+     * returned depends on whether or not the jar file is a multi-release jar
+     * file, and on the constructor used to create the {@code JarFile}.  If the
+     * jar file is not a multi-release jar file, all entries are returned,
+     * regardless of how the {@code JarFile} is created.  If the constructor
+     * does not take a {@code Release} argument, all entries are returned.
+     * If the jar file is a multi-release jar file and the constructor takes a
+     * {@code Release} argument, then the set of entries returned is equivalent
+     * to the set of entries that would be returned if the set was built by
+     * invoking {@link JarFile#getEntry(String)} or
+     * {@link JarFile#getJarEntry(String)} with the name of each base entry in
+     * the jar file.  A base entry is an entry whose path name does not start
+     * with "META-INF/versions/".
      * @return an ordered {@code Stream} of entries in this jar file
      * @throws IllegalStateException if the jar file has been closed
      * @since 1.8
@@ -300,14 +654,44 @@
                         Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
     }
 
+    private ZipEntry searchForVersionedEntry(final int version, String name) {
+        ZipEntry vze = null;
+        String sname = "/" + name;
+        int i = version;
+        while (i > BASE_VERSION) {
+            vze = super.getEntry(META_INF_VERSIONS + i + sname);
+            if (vze != null) break;
+            i--;
+        }
+        return vze;
+    }
+
+    private ZipEntry getVersionedEntry(ZipEntry ze) {
+        ZipEntry vze = null;
+        if (version > BASE_VERSION && !ze.isDirectory()) {
+            String name = ze.getName();
+            if (!name.startsWith(META_INF)) {
+                vze = searchForVersionedEntry(version, name);
+            }
+        }
+        return vze == null ? ze : vze;
+    }
+
     private class JarFileEntry extends JarEntry {
+        final private String name;
+
         JarFileEntry(ZipEntry ze) {
-            super(ze);
+            super(isMultiRelease() ? getVersionedEntry(ze) : ze);
+            this.name = ze.getName();
+        }
+        JarFileEntry(String name, ZipEntry vze) {
+            super(vze);
+            this.name = name;
         }
         public Attributes getAttributes() throws IOException {
             Manifest man = JarFile.this.getManifest();
             if (man != null) {
-                return man.getAttributes(getName());
+                return man.getAttributes(super.getName());
             } else {
                 return null;
             }
@@ -319,7 +703,7 @@
                 throw new RuntimeException(e);
             }
             if (certs == null && jv != null) {
-                certs = jv.getCerts(JarFile.this, this);
+                certs = jv.getCerts(JarFile.this, reifiedEntry());
             }
             return certs == null ? null : certs.clone();
         }
@@ -330,10 +714,22 @@
                 throw new RuntimeException(e);
             }
             if (signers == null && jv != null) {
-                signers = jv.getCodeSigners(JarFile.this, this);
+                signers = jv.getCodeSigners(JarFile.this, reifiedEntry());
             }
             return signers == null ? null : signers.clone();
         }
+        JarFileEntry reifiedEntry() {
+            if (isMultiRelease()) {
+                String entryName = super.getName();
+                return entryName.equals(this.name) ? this : new JarFileEntry(entryName, this);
+            }
+            return this;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
     }
 
     /*
@@ -491,12 +887,19 @@
         // wrap a verifier stream around the real stream
         return new JarVerifier.VerifierStream(
             getManifestFromReference(),
-            ze instanceof JarFileEntry ?
-            (JarEntry) ze : getJarEntry(ze.getName()),
+            verifiableEntry(ze),
             super.getInputStream(ze),
             jv);
     }
 
+    private JarEntry verifiableEntry(ZipEntry ze) {
+        if (!(ze instanceof JarFileEntry)) {
+            ze = getJarEntry(ze.getName());
+        }
+        // assure the name and entry match for verification
+        return ze == null ? null : ((JarFileEntry)ze).reifiedEntry();
+    }
+
     // Statics for hand-coded Boyer-Moore search
     private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'};
     // The bad character shift for "class-path"
@@ -523,7 +926,7 @@
     private JarEntry getManEntry() {
         if (manEntry == null) {
             // First look up manifest entry using standard name
-            manEntry = getJarEntry(MANIFEST_NAME);
+            ZipEntry manEntry = super.getEntry(MANIFEST_NAME);
             if (manEntry == null) {
                 // If not found, then iterate through all the "META-INF/"
                 // entries to find a match.
@@ -531,12 +934,15 @@
                 if (names != null) {
                     for (String name : names) {
                         if (MANIFEST_NAME.equals(name.toUpperCase(Locale.ENGLISH))) {
-                            manEntry = getJarEntry(name);
+                            manEntry = super.getEntry(name);
                             break;
                         }
                     }
                 }
             }
+            this.manEntry = (manEntry == null)
+                    ? null
+                    : new JarFileEntry(manEntry.getName(), manEntry);
         }
         return manEntry;
     }
--- a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,8 +64,7 @@
     private static final Map<Provider, Object> verifyingProviders =
             new IdentityHashMap<>();
 
-    // Set the default value. May be changed in the static initializer.
-    private static boolean isRestricted = true;
+    private static final boolean isRestricted;
 
     /*
      * Don't let anyone instantiate this.
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Signal.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Signal.java	Mon Feb 29 15:42:34 2016 +0000
@@ -279,6 +279,11 @@
         public void handle(Signal sig) {
             throw new UnsupportedOperationException("invoking native signal handle not supported");
         }
+
+        public String toString() {
+            return this == SIG_DFL ? "SIG_DFL" :
+                    (this == SIG_IGN ? "SIG_IGN" : super.toString());
+        }
     }
 
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -458,6 +458,78 @@
         copyMemory(null, srcAddress, null, destAddress, bytes);
     }
 
+    private boolean isPrimitiveArray(Class<?> c) {
+        Class<?> componentType = c.getComponentType();
+        return componentType != null && componentType.isPrimitive();
+    }
+
+    private native void copySwapMemory0(Object srcBase, long srcOffset,
+                                        Object destBase, long destOffset,
+                                        long bytes, long elemSize);
+
+    /**
+     * Copies all elements from one block of memory to another block,
+     * *unconditionally* byte swapping the elements on the fly.
+     *
+     * <p>This method determines each block's base address by means of two parameters,
+     * and so it provides (in effect) a <em>double-register</em> addressing mode,
+     * as discussed in {@link #getInt(Object,long)}.  When the object reference is null,
+     * the offset supplies an absolute base address.
+     *
+     * @since 9
+     */
+    public void copySwapMemory(Object srcBase, long srcOffset,
+                               Object destBase, long destOffset,
+                               long bytes, long elemSize) {
+        if (bytes < 0) {
+            throw new IllegalArgumentException();
+        }
+        if (elemSize != 2 && elemSize != 4 && elemSize != 8) {
+            throw new IllegalArgumentException();
+        }
+        if (bytes % elemSize != 0) {
+            throw new IllegalArgumentException();
+        }
+        if ((srcBase == null && srcOffset == 0) ||
+            (destBase == null && destOffset == 0)) {
+            throw new NullPointerException();
+        }
+
+        // Must be off-heap, or primitive heap arrays
+        if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) {
+            throw new IllegalArgumentException();
+        }
+        if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sanity check size and offsets on 32-bit platforms. Most
+        // significant 32 bits must be zero.
+        if (ADDRESS_SIZE == 4 &&
+            (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) {
+            throw new IllegalArgumentException();
+        }
+
+        if (bytes == 0) {
+            return;
+        }
+
+        copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
+    }
+
+   /**
+     * Copies all elements from one block of memory to another block, byte swapping the
+     * elements on the fly.
+     *
+     * This provides a <em>single-register</em> addressing mode, as
+     * discussed in {@link #getInt(Object,long)}.
+     *
+     * Equivalent to {@code copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize)}.
+     */
+    public void copySwapMemory(long srcAddress, long destAddress, long bytes, long elemSize) {
+        copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize);
+    }
+
     /**
      * Disposes of a block of native memory, as obtained from {@link
      * #allocateMemory} or {@link #reallocateMemory}.  The address passed to
@@ -1159,7 +1231,12 @@
     /** @see #getLongUnaligned(Object, long) */
     @HotSpotIntrinsicCandidate
     public final char getCharUnaligned(Object o, long offset) {
-        return (char)getShortUnaligned(o, offset);
+        if ((offset & 1) == 0) {
+            return getChar(o, offset);
+        } else {
+            return (char)makeShort(getByte(o, offset),
+                                   getByte(o, offset + 1));
+        }
     }
 
     /** @see #getLongUnaligned(Object, long, boolean) */
--- a/jdk/src/java.base/share/classes/jdk/net/Sockets.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/net/Sockets.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -251,9 +251,23 @@
         }
     }
 
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
+
+    /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
     private static void initOptionSets() {
         boolean flowsupported = ExtendedOptionsImpl.flowSupported();
-
+        boolean reuseportsupported = isReusePortAvailable();
         // Socket
 
         Set<SocketOption<?>> set = new HashSet<>();
@@ -261,6 +275,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.SO_LINGER);
         set.add(StandardSocketOptions.IP_TOS);
         set.add(StandardSocketOptions.TCP_NODELAY);
@@ -275,6 +292,9 @@
         set = new HashSet<>();
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         set = Collections.unmodifiableSet(set);
         options.put(ServerSocket.class, set);
@@ -285,6 +305,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         if (flowsupported) {
             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
@@ -298,6 +321,9 @@
         set.add(StandardSocketOptions.SO_SNDBUF);
         set.add(StandardSocketOptions.SO_RCVBUF);
         set.add(StandardSocketOptions.SO_REUSEADDR);
+        if (reuseportsupported) {
+            set.add(StandardSocketOptions.SO_REUSEPORT);
+        }
         set.add(StandardSocketOptions.IP_TOS);
         set.add(StandardSocketOptions.IP_MULTICAST_IF);
         set.add(StandardSocketOptions.IP_MULTICAST_TTL);
@@ -308,4 +334,6 @@
         set = Collections.unmodifiableSet(set);
         options.put(MulticastSocket.class, set);
     }
+
+    private static native boolean isReusePortAvailable0();
 }
--- a/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java	Mon Feb 29 15:42:34 2016 +0000
@@ -63,6 +63,7 @@
 import java.util.jar.Manifest;
 import java.util.jar.Attributes;
 import java.util.jar.Attributes.Name;
+import java.util.zip.ZipFile;
 
 import jdk.internal.jimage.ImageLocation;
 import jdk.internal.jimage.ImageReader;
@@ -727,9 +728,10 @@
                 if (!p.exists()) {
                     throw new FileNotFoundException(p.getPath());
                 }
-                return checkJar(new JarFile(p.getPath()));
+                return checkJar(new JarFile(new File(p.getPath()), true, ZipFile.OPEN_READ,
+                        JarFile.Release.RUNTIME));
             }
-            URLConnection uc = getBaseURL().openConnection();
+            URLConnection uc = (new URL(getBaseURL(), "#runtime")).openConnection();
             uc.setRequestProperty(USER_AGENT_JAVA_VERSION, JAVA_VERSION);
             JarFile jarFile = ((JarURLConnection)uc).getJarFile();
             return checkJar(jarFile);
@@ -756,7 +758,9 @@
 
             final URL url;
             try {
-                url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
+                // add #runtime fragment to tell JarURLConnection to use
+                // runtime versioning if the underlying jar file is multi-release
+                url = new URL(getBaseURL(), ParseUtil.encodePath(name, false) + "#runtime");
                 if (check) {
                     URLClassPath.check(url);
                 }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java	Mon Feb 29 15:42:34 2016 +0000
@@ -65,9 +65,10 @@
     }
 
     static JarFile getJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
-        if (isFileURL(url))
-            return new URLJarFile(url, closeController);
-        else {
+        if (isFileURL(url)) {
+            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
+            return new URLJarFile(url, closeController, version);
+        } else {
             return retrieve(url, closeController);
         }
     }
@@ -89,8 +90,13 @@
         this.closeController = closeController;
     }
 
-    private URLJarFile(URL url, URLJarFileCloseController closeController) throws IOException {
-        super(ParseUtil.decode(url.getFile()));
+    private URLJarFile(File file, URLJarFileCloseController closeController, Release version) throws IOException {
+        super(file, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE, version);
+        this.closeController = closeController;
+    }
+
+    private URLJarFile(URL url, URLJarFileCloseController closeController, Release version) throws IOException {
+        super(new File(ParseUtil.decode(url.getFile())), true, ZipFile.OPEN_READ, version);
         this.closeController = closeController;
     }
 
@@ -179,14 +185,6 @@
      * Given a URL, retrieves a JAR file, caches it to disk, and creates a
      * cached JAR file object.
      */
-    private static JarFile retrieve(final URL url) throws IOException {
-        return retrieve(url, null);
-    }
-
-    /**
-     * Given a URL, retrieves a JAR file, caches it to disk, and creates a
-     * cached JAR file object.
-     */
      private static JarFile retrieve(final URL url, final URLJarFileCloseController closeController) throws IOException {
         /*
          * See if interface is set, then call retrieve function of the class
@@ -202,6 +200,7 @@
         {
 
             JarFile result = null;
+            Release version = "runtime".equals(url.getRef()) ? Release.RUNTIME : Release.BASE;
 
             /* get the stream before asserting privileges */
             try (final InputStream in = url.openConnection().getInputStream()) {
@@ -211,7 +210,7 @@
                             Path tmpFile = Files.createTempFile("jar_cache", null);
                             try {
                                 Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
-                                JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController);
+                                JarFile jarFile = new URLJarFile(tmpFile.toFile(), closeController, version);
                                 tmpFile.toFile().deleteOnExit();
                                 return jarFile;
                             } catch (Throwable thr) {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -231,6 +231,9 @@
             HashSet<SocketOption<?>> set = new HashSet<>(2);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             return Collections.unmodifiableSet(set);
         }
     }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -508,6 +508,9 @@
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_KEEPALIVE);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.TCP_NODELAY);
             if (ExtendedOptionsImpl.flowSupported()) {
                 set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -298,6 +298,9 @@
             set.add(StandardSocketOptions.SO_SNDBUF);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.SO_BROADCAST);
             set.add(StandardSocketOptions.IP_TOS);
             set.add(StandardSocketOptions.IP_MULTICAST_IF);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,6 +56,8 @@
 
     private static volatile boolean checkedIPv6;
     private static volatile boolean isIPv6Available;
+    private static volatile boolean checkedReusePort;
+    private static volatile boolean isReusePortAvailable;
 
     /**
      * Tells whether dual-IPv4/IPv6 sockets should be used.
@@ -69,6 +71,17 @@
     }
 
     /**
+     * Tells whether SO_REUSEPORT is supported.
+     */
+    static boolean isReusePortAvailable() {
+        if (!checkedReusePort) {
+            isReusePortAvailable = isReusePortAvailable0();
+            checkedReusePort = true;
+        }
+        return isReusePortAvailable;
+    }
+
+    /**
      * Returns true if exclusive binding is on
      */
     static boolean useExclusiveBind() {
@@ -389,6 +402,8 @@
 
     private static native boolean isIPv6Available0();
 
+    private static native boolean isReusePortAvailable0();
+
     /*
      * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS
      */
--- a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 import java.util.*;
 import sun.net.NetHooks;
 
-
 /**
  * An implementation of ServerSocketChannels
  */
@@ -185,6 +184,9 @@
             HashSet<SocketOption<?>> set = new HashSet<>(2);
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.IP_TOS);
             return Collections.unmodifiableSet(set);
         }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -234,6 +234,9 @@
             set.add(StandardSocketOptions.SO_RCVBUF);
             set.add(StandardSocketOptions.SO_KEEPALIVE);
             set.add(StandardSocketOptions.SO_REUSEADDR);
+            if (Net.isReusePortAvailable()) {
+                set.add(StandardSocketOptions.SO_REUSEPORT);
+            }
             set.add(StandardSocketOptions.SO_LINGER);
             set.add(StandardSocketOptions.TCP_NODELAY);
             // additional options required by socket adaptor
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,9 +81,6 @@
 
     private boolean serverKeyExchangeReceived;
 
-    private final boolean enableStatusRequestExtension =
-            Debug.getBooleanProperty(
-                    "jdk.tls.client.enableStatusRequestExtension", true);
     private boolean staplingActive = false;
     private X509Certificate[] deferredCerts;
 
@@ -761,7 +758,7 @@
                     type == ExtensionType.EXT_STATUS_REQUEST_V2) {
                 // Only enable the stapling feature if the client asserted
                 // these extensions.
-                if (enableStatusRequestExtension) {
+                if (sslContext.isStaplingEnabled(true)) {
                     staplingActive = true;
                 } else {
                     fatalSE(Alerts.alert_unexpected_message, "Server set " +
@@ -1562,7 +1559,7 @@
         }
 
         // Add status_request and status_request_v2 extensions
-        if (enableStatusRequestExtension) {
+        if (sslContext.isStaplingEnabled(true)) {
             clientHelloMessage.addCertStatusReqListV2Extension();
             clientHelloMessage.addCertStatusRequestExtension();
         }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,11 @@
     // DTLS cookie exchange manager
     private volatile HelloCookieManager helloCookieManager;
 
-    private StatusResponseManager statusResponseManager;
+    private final boolean clientEnableStapling = Debug.getBooleanProperty(
+            "jdk.tls.client.enableStatusRequestExtension", true);
+    private final boolean serverEnableStapling = Debug.getBooleanProperty(
+            "jdk.tls.server.enableStatusRequestExtension", false);
+    private volatile StatusResponseManager statusResponseManager;
 
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
@@ -80,7 +84,6 @@
             }
         }
         trustManager = chooseTrustManager(tm);
-        statusResponseManager = new StatusResponseManager();
 
         if (sr == null) {
             secureRandom = JsseJce.getSecureRandom();
@@ -258,6 +261,18 @@
     }
 
     StatusResponseManager getStatusResponseManager() {
+        if (serverEnableStapling && statusResponseManager == null) {
+            synchronized (this) {
+                if (statusResponseManager == null) {
+                    if (debug != null && Debug.isOn("sslctx")) {
+                        System.out.println(
+                                "Initializing StatusResponseManager");
+                    }
+                    statusResponseManager = new StatusResponseManager();
+                }
+            }
+        }
+
         return statusResponseManager;
     }
 
@@ -309,6 +324,18 @@
                (cipherSuites == getClientDefaultCipherSuiteList());
     }
 
+    /**
+     * Return whether client or server side stapling has been enabled
+     * for this SSLContextImpl
+     * @param isClient true if the caller is operating in a client side role,
+     * false if acting as a server.
+     * @return true if stapling has been enabled for the specified role, false
+     * otherwise.
+     */
+    boolean isStaplingEnabled(boolean isClient) {
+        return isClient ? clientEnableStapling : serverEnableStapling;
+    }
+
     /*
      * Return the list of all available CipherSuites with a priority of
      * minPriority or above.
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -118,10 +118,6 @@
                     LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS,
                     new SSLAlgorithmDecomposer());
 
-    // To switch off the status_request[_v2] extensions
-    private static final boolean enableStatusRequestExtension =
-            Debug.getBooleanProperty(
-                    "jdk.tls.server.enableStatusRequestExtension", false);
     private boolean staplingActive = false;
     private long statusRespTimeout;
 
@@ -589,7 +585,7 @@
                 (CertStatusReqListV2Extension)mesg.extensions.get(
                         ExtensionType.EXT_STATUS_REQUEST_V2);
         // Keep stapling active if at least one of the extensions has been set
-        staplingActive = enableStatusRequestExtension &&
+        staplingActive = sslContext.isStaplingEnabled(false) &&
                 (statReqExt != null || statReqExtV2 != null);
 
         /*
@@ -932,19 +928,32 @@
             }
 
             if (statReqType != null && statReqData != null) {
-                // Next, attempt to obtain status responses
                 StatusResponseManager statRespMgr =
                         sslContext.getStatusResponseManager();
-                responseMap = statRespMgr.get(statReqType, statReqData, certs,
-                        statusRespTimeout, TimeUnit.MILLISECONDS);
-                if (!responseMap.isEmpty()) {
-                    // We now can safely assert status_request[_v2] in our
-                    // ServerHello, and know for certain that we can provide
-                    // responses back to this client for this connection.
-                    if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST) {
-                        m1.extensions.add(new CertStatusReqExtension());
-                    } else if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST_V2) {
-                        m1.extensions.add(new CertStatusReqListV2Extension());
+                if (statRespMgr != null) {
+                    responseMap = statRespMgr.get(statReqType, statReqData,
+                            certs, statusRespTimeout, TimeUnit.MILLISECONDS);
+                    if (!responseMap.isEmpty()) {
+                        // We now can safely assert status_request[_v2] in our
+                        // ServerHello, and know for certain that we can provide
+                        // responses back to this client for this connection.
+                        if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST) {
+                            m1.extensions.add(new CertStatusReqExtension());
+                        } else if (statusRespExt ==
+                                ExtensionType.EXT_STATUS_REQUEST_V2) {
+                            m1.extensions.add(
+                                    new CertStatusReqListV2Extension());
+                        }
+                    }
+                } else {
+                    // This should not happen if stapling is active, but
+                    // if lazy initialization of the StatusResponseManager
+                    // doesn't occur we should turn off stapling.
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Warning: lazy initialization " +
+                                "of the StatusResponseManager failed.  " +
+                                "Stapling has been disabled.");
+                        staplingActive = false;
                     }
                 }
             }
--- a/jdk/src/java.base/share/native/libjava/Bits.c	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jlong.h"
-#include <string.h>
-
-#define MBYTE 1048576
-
-#define GETCRITICAL_OR_RETURN(bytes, env, obj) { \
-    bytes = (*env)->GetPrimitiveArrayCritical(env, obj, NULL); \
-    if (bytes == NULL)  { \
-        if ((*env)->ExceptionOccurred(env) == NULL) \
-            JNU_ThrowInternalError(env, "Unable to get array"); \
-        return; \
-    } \
-}
-
-#define RELEASECRITICAL(bytes, env, obj, mode) { \
-    (*env)->ReleasePrimitiveArrayCritical(env, obj, bytes, mode); \
-}
-
-#define SWAPSHORT(x) ((jshort)(((x) << 8) | (((x) >> 8) & 0xff)))
-#define SWAPINT(x)   ((jint)((SWAPSHORT((jshort)(x)) << 16) | \
-                            (SWAPSHORT((jshort)((x) >> 16)) & 0xffff)))
-#define SWAPLONG(x)  ((jlong)(((jlong)SWAPINT((jint)(x)) << 32) | \
-                              ((jlong)SWAPINT((jint)((x) >> 32)) & 0xffffffff)))
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromShortArray(JNIEnv *env, jclass clazz, jobject src,
-                                      jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jshort *srcShort, *dstShort, *endShort;
-    jshort tmpShort;
-
-    dstShort = (jshort *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcShort = (jshort *)(bytes + srcPos);
-        endShort = srcShort + (size / sizeof(jshort));
-        while (srcShort < endShort) {
-          tmpShort = *srcShort++;
-          *dstShort++ = SWAPSHORT(tmpShort);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToShortArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                    jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jshort *srcShort, *dstShort, *endShort;
-    jshort tmpShort;
-
-    srcShort = (jshort *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstShort = (jshort *)(bytes + dstPos);
-        endShort = srcShort + (size / sizeof(jshort));
-        while (srcShort < endShort) {
-            tmpShort = *srcShort++;
-            *dstShort++ = SWAPSHORT(tmpShort);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromIntArray(JNIEnv *env, jclass clazz, jobject src,
-                                    jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jint *srcInt, *dstInt, *endInt;
-    jint tmpInt;
-
-    dstInt = (jint *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcInt = (jint *)(bytes + srcPos);
-        endInt = srcInt + (size / sizeof(jint));
-        while (srcInt < endInt) {
-            tmpInt = *srcInt++;
-            *dstInt++ = SWAPINT(tmpInt);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToIntArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                  jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jint *srcInt, *dstInt, *endInt;
-    jint tmpInt;
-
-    srcInt = (jint *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstInt = (jint *)(bytes + dstPos);
-        endInt = srcInt + (size / sizeof(jint));
-        while (srcInt < endInt) {
-            tmpInt = *srcInt++;
-            *dstInt++ = SWAPINT(tmpInt);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyFromLongArray(JNIEnv *env, jclass clazz, jobject src,
-                                     jlong srcPos, jlong dstAddr, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jlong *srcLong, *dstLong, *endLong;
-    jlong tmpLong;
-
-    dstLong = (jlong *)jlong_to_ptr(dstAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, src);
-
-        srcLong = (jlong *)(bytes + srcPos);
-        endLong = srcLong + (size / sizeof(jlong));
-        while (srcLong < endLong) {
-            tmpLong = *srcLong++;
-            *dstLong++ = SWAPLONG(tmpLong);
-        }
-
-        RELEASECRITICAL(bytes, env, src, JNI_ABORT);
-
-        length -= size;
-        srcPos += size;
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_java_nio_Bits_copyToLongArray(JNIEnv *env, jclass clazz, jlong srcAddr,
-                                   jobject dst, jlong dstPos, jlong length)
-{
-    jbyte *bytes;
-    size_t size;
-    jlong *srcLong, *dstLong, *endLong;
-    jlong tmpLong;
-
-    srcLong = (jlong *)jlong_to_ptr(srcAddr);
-
-    while (length > 0) {
-        size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
-
-        GETCRITICAL_OR_RETURN(bytes, env, dst);
-
-        dstLong = (jlong *)(bytes + dstPos);
-        endLong = srcLong + (size / sizeof(jlong));
-        while (srcLong < endLong) {
-            tmpLong = *srcLong++;
-            *dstLong++ = SWAPLONG(tmpLong);
-        }
-
-        RELEASECRITICAL(bytes, env, dst, 0);
-
-        length -= size;
-        dstPos += size;
-    }
-}
--- a/jdk/src/java.base/share/native/libnet/net_util.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/native/libnet/net_util.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,14 +29,21 @@
 #include "net_util.h"
 
 int IPv6_supported() ;
+int reuseport_supported() ;
 
 static int IPv6_available;
+static int REUSEPORT_available;
 
 JNIEXPORT jint JNICALL ipv6_available()
 {
     return IPv6_available ;
 }
 
+JNIEXPORT jint JNICALL reuseport_available()
+{
+    return REUSEPORT_available;
+}
+
 JNIEXPORT jint JNICALL
 DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
 {
@@ -45,7 +52,6 @@
     jmethodID mid;
     jstring s;
     jint preferIPv4Stack;
-
     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) {
         return JNI_EVERSION; /* JNI version not supported */
     }
@@ -64,6 +70,9 @@
        supporting socket APIs are available
     */
     IPv6_available = IPv6_supported() & (!preferIPv4Stack);
+
+    /* check if SO_REUSEPORT is supported on this platform */
+    REUSEPORT_available = reuseport_supported();
     platformInit();
     parseExclusiveBindProperty(env);
 
--- a/jdk/src/java.base/share/native/libnet/net_util.h	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/native/libnet/net_util.h	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -131,6 +131,8 @@
 
 JNIEXPORT jint JNICALL ipv6_available() ;
 
+JNIEXPORT jint JNICALL reuseport_available() ;
+
 void
 NET_AllocSockaddr(struct sockaddr **him, int *len);
 
--- a/jdk/src/java.base/share/native/libzip/CRC32.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/share/native/libzip/CRC32.c	Mon Feb 29 15:42:34 2016 +0000
@@ -54,7 +54,7 @@
     return crc;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 ZIP_CRC32(jint crc, const jbyte *buf, jint len)
 {
     return crc32(crc, (Bytef*)buf, len);
--- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,15 @@
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            super.setOption(name, value);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                super.setOption(name, value);
+            } else {
+               if (supportedOptions().contains(name)) {
+                   super.setOption(name, value);
+               } else {
+                   throw new UnsupportedOperationException("unsupported option");
+               }
+            }
         } else {
             if (!flowSupported()) {
                 throw new UnsupportedOperationException("unsupported option");
@@ -62,7 +70,15 @@
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            return super.getOption(name);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                return super.getOption(name);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    return super.getOption(name);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         }
         if (!flowSupported()) {
             throw new UnsupportedOperationException("unsupported option");
@@ -87,6 +103,9 @@
     }
 
     protected void socketSetOption(int opt, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         try {
             socketSetOption0(opt, val);
         } catch (SocketException se) {
--- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,15 @@
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            super.setOption(name, value);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                super.setOption(name, value);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    super.setOption(name, value);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         } else {
             if (getSocket() == null || !flowSupported()) {
                 throw new UnsupportedOperationException("unsupported option");
@@ -76,7 +84,15 @@
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
-            return super.getOption(name);
+            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+                return super.getOption(name);
+            } else {
+                if (supportedOptions().contains(name)) {
+                    return super.getOption(name);
+                } else {
+                    throw new UnsupportedOperationException("unsupported option");
+                }
+            }
         }
         if (getSocket() == null || !flowSupported()) {
             throw new UnsupportedOperationException("unsupported option");
@@ -101,6 +117,9 @@
     }
 
     protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
         try {
             socketSetOption0(opt, b, val);
         } catch (SocketException se) {
--- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/jar/JarFileFactory.java	Mon Feb 29 15:42:34 2016 +0000
@@ -85,7 +85,7 @@
                 synchronized (instance) {
                     result = getCachedJarFile(url);
                     if (result == null) {
-                        fileCache.put(URLUtil.urlNoFragString(url), local_result);
+                        fileCache.put(urlKey(url), local_result);
                         urlCache.put(local_result, url);
                         result = local_result;
                     } else {
@@ -113,13 +113,13 @@
         synchronized (instance) {
             URL urlRemoved = urlCache.remove(jarFile);
             if (urlRemoved != null)
-                fileCache.remove(URLUtil.urlNoFragString(urlRemoved));
+                fileCache.remove(urlKey(urlRemoved));
         }
     }
 
     private JarFile getCachedJarFile(URL url) {
         assert Thread.holdsLock(instance);
-        JarFile result = fileCache.get(URLUtil.urlNoFragString(url));
+        JarFile result = fileCache.get(urlKey(url));
 
         /* if the JAR file is cached, the permission will always be there */
         if (result != null) {
@@ -149,6 +149,12 @@
         return result;
     }
 
+    private String urlKey(URL url) {
+        String urlstr =  URLUtil.urlNoFragString(url);
+        if ("runtime".equals(url.getRef())) urlstr += "#runtime";
+        return urlstr;
+    }
+
     private Permission getPermission(JarFile jarFile) {
         try {
             URLConnection uc = getConnection(jarFile);
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1392,6 +1392,7 @@
             }
 
         case java_net_SocketOptions_SO_REUSEADDR:
+        case java_net_SocketOptions_SO_REUSEPORT:
         case java_net_SocketOptions_SO_BROADCAST:
             {
                 jclass cls;
@@ -1769,6 +1770,9 @@
         case java_net_SocketOptions_SO_REUSEADDR:
             return createBoolean(env, optval.i);
 
+        case java_net_SocketOptions_SO_REUSEPORT:
+            return createBoolean(env, optval.i);
+
         case java_net_SocketOptions_SO_SNDBUF:
         case java_net_SocketOptions_SO_RCVBUF:
         case java_net_SocketOptions_IP_TOS:
--- a/jdk/src/java.base/unix/native/libnet/SdpSupport.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnet/SdpSupport.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -108,6 +108,11 @@
         len = sizeof(arg);
         if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0)
             setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len);
+#ifdef SO_REUSEPORT
+        len = sizeof(arg);
+        if (getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, &len) == 0)
+            setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, len);
+#endif
         len = sizeof(arg);
         if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0)
             setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/native/libnet/SocketImpl.c	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+#include <string.h>
+
+#include "net_util.h"
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -439,6 +439,25 @@
 }
 #endif /* DONT_ENABLE_IPV6 */
 
+jint reuseport_supported()
+{
+    /* Do a simple dummy call, and try to figure out from that */
+    int one = 1;
+    int rv, s;
+    s = socket(PF_INET, SOCK_STREAM, 0);
+    if (s < 0) {
+        return JNI_FALSE;
+    }
+    rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one));
+    if (rv != 0) {
+        rv = JNI_FALSE;
+    } else {
+        rv = JNI_TRUE;
+    }
+    close(s);
+    return rv;
+}
+
 void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
                                                const char* hostname,
                                                int gai_error)
@@ -1014,6 +1033,7 @@
         { java_net_SocketOptions_SO_RCVBUF,             SOL_SOCKET,     SO_RCVBUF },
         { java_net_SocketOptions_SO_KEEPALIVE,          SOL_SOCKET,     SO_KEEPALIVE },
         { java_net_SocketOptions_SO_REUSEADDR,          SOL_SOCKET,     SO_REUSEADDR },
+        { java_net_SocketOptions_SO_REUSEPORT,          SOL_SOCKET,     SO_REUSEPORT },
         { java_net_SocketOptions_SO_BROADCAST,          SOL_SOCKET,     SO_BROADCAST },
         { java_net_SocketOptions_IP_TOS,                IPPROTO_IP,     IP_TOS },
         { java_net_SocketOptions_IP_MULTICAST_IF,       IPPROTO_IP,     IP_MULTICAST_IF },
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.h	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,19 @@
 #define NET_WAIT_WRITE   0x02
 #define NET_WAIT_CONNECT 0x04
 
+/* Defines SO_REUSEPORT */
+#ifndef SO_REUSEPORT
+#ifdef __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
+
 jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
 
 /************************************************************************
--- a/jdk/src/java.base/unix/native/libnio/ch/Net.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -161,6 +161,12 @@
     return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    return (reuseport_available()) ? JNI_TRUE : JNI_FALSE;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
     return -1;
--- a/jdk/src/java.base/unix/native/libnio/ch/nio_util.h	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/unix/native/libnio/ch/nio_util.h	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,18 @@
   } while((_result == -1) && (errno == EINTR)); \
 } while(0)
 
+/* Defines SO_REUSEPORT */
+#ifndef SO_REUSEPORT
+#ifdef __linux__
+#define SO_REUSEPORT 15
+#elif __solaris__
+#define SO_REUSEPORT 0x100e
+#elif defined(AIX) || defined(MACOSX)
+#define SO_REUSEPORT 0x0200
+#else
+#define SO_REUSEPORT 0
+#endif
+#endif
 
 /* NIO utility procedures */
 
--- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -167,6 +167,11 @@
 
         int optionValue = 0;
 
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+
         switch(opt) {
             case IP_TOS :
             case SO_RCVBUF :
@@ -200,6 +205,9 @@
         }
         if (opt == SO_REUSEADDR && reuseAddressEmulated)
             return isReuseAddress;
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT)
+            throw new UnsupportedOperationException("unsupported option");
 
         int value = socketGetIntOption(nativefd, opt);
         Object returnValue = null;
--- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -181,6 +181,10 @@
         if (opt == SO_TIMEOUT) {  // timeout implemented through select.
             return;
         }
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
 
         int optionValue = 0;
 
@@ -224,6 +228,10 @@
             localAddress(nativefd, (InetAddressContainer)iaContainerObj);
             return 0;  // return value doesn't matter.
         }
+        // SO_REUSEPORT is not supported on Windows.
+        if (opt == SO_REUSEPORT) {
+            throw new UnsupportedOperationException("unsupported option");
+        }
 
         // SO_REUSEADDR emulated when using exclusive bind
         if (opt == SO_REUSEADDR && exclusiveBind)
--- a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -173,10 +173,18 @@
     }
 
     public void setOption(int opt, Object val) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         impl.setOption(opt, val);
     }
 
     public Object getOption(int opt) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         return impl.getOption(opt);
     }
 
@@ -332,14 +340,27 @@
 
     void socketSetOption(int cmd, boolean on, Object value)
         throws SocketException {
+        if (cmd == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         impl.socketSetOption(cmd, on, value);
     }
 
     int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
+        if (opt == SocketOptions.SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         return impl.socketGetOption(opt, iaContainerObj);
     }
 
     void socketSendUrgentData(int data) throws IOException {
         impl.socketSendUrgentData(data);
     }
+
+    static boolean isReusePortAvailable() {
+        // SO_REUSEPORT is not supported on Windows.
+        return false;
+    }
 }
--- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -130,6 +130,9 @@
             return socketLocalAddress(family);
         } else if (optID == SO_REUSEADDR && reuseAddressEmulated) {
             return isReuseAddress;
+        } else if (optID == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else {
             return super.getOption(optID);
         }
@@ -142,6 +145,9 @@
             // socket already bound, emulate
             reuseAddressEmulated = true;
             isReuseAddress = (Boolean)val;
+        } else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else {
             socketNativeSetOption(opt, val);
         }
--- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -128,6 +128,9 @@
         } else if (opt == SO_REUSEADDR && exclusiveBind) {
             // SO_REUSEADDR emulated when using exclusive bind
             return isReuseAddress;
+        } else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
         } else
             return super.getOption(opt);
     }
@@ -144,6 +147,10 @@
         // SO_REUSEADDR emulated when using exclusive bind
         if (opt == SO_REUSEADDR && exclusiveBind)
             isReuseAddress = on;
+        else if (opt == SO_REUSEPORT) {
+            // SO_REUSEPORT is not supported on Windows.
+            throw new UnsupportedOperationException("unsupported option");
+        }
         else
             socketNativeSetOption(opt, on, value);
     }
--- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/jar/JarFileFactory.java	Mon Feb 29 15:42:34 2016 +0000
@@ -95,7 +95,7 @@
                 synchronized (instance) {
                     result = getCachedJarFile(url);
                     if (result == null) {
-                        fileCache.put(URLUtil.urlNoFragString(url), local_result);
+                        fileCache.put(urlKey(url), local_result);
                         urlCache.put(local_result, url);
                         result = local_result;
                     } else {
@@ -123,13 +123,13 @@
         synchronized (instance) {
             URL urlRemoved = urlCache.remove(jarFile);
             if (urlRemoved != null)
-                fileCache.remove(URLUtil.urlNoFragString(urlRemoved));
+                fileCache.remove(urlKey(urlRemoved));
         }
     }
 
     private JarFile getCachedJarFile(URL url) {
         assert Thread.holdsLock(instance);
-        JarFile result = fileCache.get(URLUtil.urlNoFragString(url));
+        JarFile result = fileCache.get(urlKey(url));
 
         /* if the JAR file is cached, the permission will always be there */
         if (result != null) {
@@ -159,6 +159,12 @@
         return result;
     }
 
+    private String urlKey(URL url) {
+        String urlstr =  URLUtil.urlNoFragString(url);
+        if ("runtime".equals(url.getRef())) urlstr += "#runtime";
+        return urlstr;
+    }
+
     private Permission getPermission(JarFile jarFile) {
         try {
             URLConnection uc = getConnection(jarFile);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/windows/native/libnet/SocketImpl.c	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <jni.h>
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -242,6 +242,11 @@
     return JNI_TRUE;
 }
 
+jint reuseport_supported()
+{
+    /* SO_REUSEPORT is not supported onn Windows */
+    return JNI_FALSE;
+}
 /*
  * Return the default TOS value
  */
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.h	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h	Mon Feb 29 15:42:34 2016 +0000
@@ -54,6 +54,9 @@
 
 #else
 
+/*SO_REUSEPORT is not supported on Windows, define it to 0*/
+#define SO_REUSEPORT 0
+
 /* Retain this code a little longer to support building in
  * old environments.  _MSC_VER is defined as:
  *     1200 for MSVC++ 6.0
@@ -353,3 +356,4 @@
 
 JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0_XP
 (JNIEnv *env, jclass cls, jstring name, jint index);
+
--- a/jdk/src/java.base/windows/native/libnio/ch/Net.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,6 +93,13 @@
     return ipv6_available() ? JNI_TRUE : JNI_FALSE;
 }
 
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1)
+{
+    // SO_REUSEPORT is not supported on Windows
+    return JNI_FALSE;
+}
+
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) {
     return 1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.nio.channels.SelectableChannel;
+
+/**
+ * Event handling interface from HttpClientImpl's selector.
+ *
+ * <p> If blockingChannel is true, then the channel will be put in blocking
+ * mode prior to handle() being called. If false, then it remains non-blocking.
+ */
+abstract class AsyncEvent {
+
+    /**
+     * Implement this if channel should be made blocking before calling handle()
+     */
+    public interface Blocking { }
+
+    /**
+     * Implement this if channel should remain non-blocking before calling handle()
+     */
+    public interface NonBlocking { }
+
+    /** Returns the channel */
+    public abstract SelectableChannel channel();
+
+    /** Returns the selector interest op flags OR'd */
+    public abstract int interestOps();
+
+    /** Called when event occurs */
+    public abstract void handle();
+
+    /** Called when selector is shutting down. Abort all exchanges. */
+    public abstract void abort();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import static java.net.Authenticator.RequestorType.PROXY;
+import static java.net.Authenticator.RequestorType.SERVER;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.InetSocketAddress;
+import java.net.URISyntaxException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.LinkedList;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+/**
+ * Implementation of Http Basic authentication.
+ */
+class AuthenticationFilter implements HeaderFilter {
+
+    static private final Base64.Encoder encoder = Base64.getEncoder();
+
+    static final int DEFAULT_RETRY_LIMIT = 3;
+
+    static final int retry_limit = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT);
+
+    static final int UNAUTHORIZED = 401;
+    static final int PROXY_UNAUTHORIZED = 407;
+
+    private PasswordAuthentication getCredentials(String header,
+                                                  boolean proxy,
+                                                  HttpRequestImpl req)
+        throws IOException
+    {
+        HttpClientImpl client = req.client();
+        java.net.Authenticator auth =
+                client.authenticator()
+                      .orElseThrow(() -> new IOException("No authenticator set"));
+        URI uri = req.uri();
+        HeaderParser parser = new HeaderParser(header);
+        String authscheme = parser.findKey(0);
+
+        String realm = parser.findValue("realm");
+        java.net.Authenticator.RequestorType rtype = proxy ? PROXY : SERVER;
+
+        // needs to be instance method in Authenticator
+        return auth.requestPasswordAuthenticationInstance(uri.getHost(),
+                                                          null,
+                                                          uri.getPort(),
+                                                          uri.getScheme(),
+                                                          realm,
+                                                          authscheme,
+                                                          uri.toURL(),
+                                                          rtype
+        );
+    }
+
+    private URI getProxyURI(HttpRequestImpl r) {
+        InetSocketAddress proxy = r.proxy();
+        if (proxy == null) {
+            return null;
+        }
+
+        // our own private scheme for proxy URLs
+        // eg. proxy.http://host:port/
+        String scheme = "proxy." + r.uri().getScheme();
+        try {
+            return new URI(scheme,
+                           null,
+                           proxy.getHostString(),
+                           proxy.getPort(),
+                           null,
+                           null,
+                           null);
+        } catch (URISyntaxException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        // use preemptive authentication if an entry exists.
+        Cache cache = getCache(r);
+
+        // Proxy
+        if (r.exchange.proxyauth == null) {
+            URI proxyURI = getProxyURI(r);
+            if (proxyURI != null) {
+                CacheEntry ca = cache.get(proxyURI, true);
+                if (ca != null) {
+                    r.exchange.proxyauth = new AuthInfo(true, ca.scheme, null, ca);
+                    addBasicCredentials(r, true, ca.value);
+                }
+            }
+        }
+
+        // Server
+        if (r.exchange.serverauth == null) {
+            CacheEntry ca = cache.get(r.uri(), false);
+            if (ca != null) {
+                r.exchange.serverauth = new AuthInfo(true, ca.scheme, null, ca);
+                addBasicCredentials(r, false, ca.value);
+            }
+        }
+    }
+
+    // TODO: refactor into per auth scheme class
+    static private void addBasicCredentials(HttpRequestImpl r,
+                                            boolean proxy,
+                                            PasswordAuthentication pw) {
+        String hdrname = proxy ? "Proxy-Authorization" : "Authorization";
+        StringBuilder sb = new StringBuilder(128);
+        sb.append(pw.getUserName()).append(':').append(pw.getPassword());
+        String s = encoder.encodeToString(sb.toString().getBytes(ISO_8859_1));
+        String value = "Basic " + s;
+        r.setSystemHeader(hdrname, value);
+    }
+
+    // Information attached to a HttpRequestImpl relating to authentication
+    static class AuthInfo {
+        final boolean fromcache;
+        final String scheme;
+        int retries;
+        PasswordAuthentication credentials; // used in request
+        CacheEntry cacheEntry; // if used
+
+        AuthInfo(boolean fromcache,
+                 String scheme,
+                 PasswordAuthentication credentials) {
+            this.fromcache = fromcache;
+            this.scheme = scheme;
+            this.credentials = credentials;
+            this.retries = 1;
+        }
+
+        AuthInfo(boolean fromcache,
+                 String scheme,
+                 PasswordAuthentication credentials,
+                 CacheEntry ca) {
+            this(fromcache, scheme, credentials);
+            assert credentials == null || (ca != null && ca.value == null);
+            cacheEntry = ca;
+        }
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        Cache cache = getCache(r.request);
+        int status = r.statusCode();
+        HttpHeaders hdrs = r.headers();
+        HttpRequestImpl req = r.request();
+
+        if (status != UNAUTHORIZED && status != PROXY_UNAUTHORIZED) {
+            // check if any authentication succeeded for first time
+            if (req.exchange.serverauth != null && !req.exchange.serverauth.fromcache) {
+                AuthInfo au = req.exchange.serverauth;
+                cache.store(au.scheme, req.uri(), false, au.credentials);
+            }
+            if (req.exchange.proxyauth != null && !req.exchange.proxyauth.fromcache) {
+                AuthInfo au = req.exchange.proxyauth;
+                cache.store(au.scheme, req.uri(), false, au.credentials);
+            }
+            return null;
+        }
+
+        boolean proxy = status == PROXY_UNAUTHORIZED;
+        String authname = proxy ? "Proxy-Authentication" : "WWW-Authenticate";
+        String authval = hdrs.firstValue(authname).orElseThrow(() -> {
+            return new IOException("Invalid auth header");
+        });
+        HeaderParser parser = new HeaderParser(authval);
+        String scheme = parser.findKey(0);
+
+        // TODO: Need to generalise from Basic only. Delegate to a provider class etc.
+
+        if (!scheme.equalsIgnoreCase("Basic")) {
+            return null;   // error gets returned to app
+        }
+
+        String realm = parser.findValue("realm");
+        AuthInfo au = proxy ? req.exchange.proxyauth : req.exchange.serverauth;
+        if (au == null) {
+            PasswordAuthentication pw = getCredentials(authval, proxy, req);
+            if (pw == null) {
+                throw new IOException("No credentials provided");
+            }
+            // No authentication in request. Get credentials from user
+            au = new AuthInfo(false, "Basic", pw);
+            if (proxy)
+                req.exchange.proxyauth = au;
+            else
+                req.exchange.serverauth = au;
+            addBasicCredentials(req, proxy, pw);
+            return req;
+        } else if (au.retries > retry_limit) {
+            throw new IOException("too many authentication attempts");
+        } else {
+            // we sent credentials, but they were rejected
+            if (au.fromcache) {
+                cache.remove(au.cacheEntry);
+            }
+            // try again
+            au.credentials = getCredentials(authval, proxy, req);
+            addBasicCredentials(req, proxy, au.credentials);
+            au.retries++;
+            return req;
+        }
+    }
+
+    static final HashMap<HttpClientImpl,Cache> caches = new HashMap<>();
+
+    static synchronized Cache getCache(HttpRequestImpl req) {
+        HttpClientImpl client = req.client();
+        Cache c = caches.get(client);
+        if (c == null) {
+            c = new Cache();
+            caches.put(client, c);
+        }
+        return c;
+    }
+
+    static class Cache {
+        final LinkedList<CacheEntry> entries = new LinkedList<>();
+
+        synchronized CacheEntry get(URI uri, boolean proxy) {
+            for (CacheEntry entry : entries) {
+                if (entry.equalsKey(uri, proxy)) {
+                    return entry;
+                }
+            }
+            return null;
+        }
+
+        synchronized void remove(String authscheme, URI domain, boolean proxy) {
+            for (CacheEntry entry : entries) {
+                if (entry.equalsKey(domain, proxy)) {
+                    entries.remove(entry);
+                }
+            }
+        }
+
+        synchronized void remove(CacheEntry entry) {
+            entries.remove(entry);
+        }
+
+        synchronized void store(String authscheme,
+                                URI domain,
+                                boolean proxy,
+                                PasswordAuthentication value) {
+            remove(authscheme, domain, proxy);
+            entries.add(new CacheEntry(authscheme, domain, proxy, value));
+        }
+    }
+
+    static class CacheEntry {
+        final String root;
+        final String scheme;
+        final boolean proxy;
+        final PasswordAuthentication value;
+
+        CacheEntry(String authscheme,
+                   URI uri,
+                   boolean proxy,
+                   PasswordAuthentication value) {
+            this.scheme = authscheme;
+            this.root = uri.resolve(".").toString(); // remove extraneous components
+            this.proxy = proxy;
+            this.value = value;
+        }
+
+        public PasswordAuthentication value() {
+            return value;
+        }
+
+        public boolean equalsKey(URI uri, boolean proxy) {
+            if (this.proxy != proxy) {
+                return false;
+            }
+            String other = uri.toString();
+            return other.startsWith(root);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Implemented by buffer pools.
+ */
+interface BufferHandler {
+
+    ByteBuffer getBuffer();
+
+    void returnBuffer(ByteBuffer buffer);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Objects;
+
+/**
+ * Http 1.1 connection pool.
+ */
+class ConnectionPool {
+
+    static final long KEEP_ALIVE = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.keepalive.timeout", 1200); // seconds
+
+    // Pools of idle connections
+
+    final HashMap<CacheKey,LinkedList<HttpConnection>> plainPool;
+    final HashMap<CacheKey,LinkedList<HttpConnection>> sslPool;
+    CacheCleaner cleaner;
+
+    /**
+     * Entries in connection pool are keyed by destination address and/or
+     * proxy address:
+     * case 1: plain TCP not via proxy (destination only)
+     * case 2: plain TCP via proxy (proxy only)
+     * case 3: SSL not via proxy (destination only)
+     * case 4: SSL over tunnel (destination and proxy)
+     */
+    static class CacheKey {
+        final InetSocketAddress proxy;
+        final InetSocketAddress destination;
+
+        CacheKey(InetSocketAddress destination, InetSocketAddress proxy) {
+            this.proxy = proxy;
+            this.destination = destination;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final CacheKey other = (CacheKey) obj;
+            if (!Objects.equals(this.proxy, other.proxy)) {
+                return false;
+            }
+            if (!Objects.equals(this.destination, other.destination)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(proxy, destination);
+        }
+    }
+
+    static class ExpiryEntry {
+        final HttpConnection connection;
+        final long expiry; // absolute time in seconds of expiry time
+        ExpiryEntry(HttpConnection connection, long expiry) {
+            this.connection = connection;
+            this.expiry = expiry;
+        }
+    }
+
+    final LinkedList<ExpiryEntry> expiryList;
+
+    /**
+     * There should be one of these per HttpClient.
+     */
+    ConnectionPool() {
+        plainPool = new HashMap<>();
+        sslPool = new HashMap<>();
+        expiryList = new LinkedList<>();
+        cleaner = new CacheCleaner();
+    }
+
+    void start() {
+        cleaner.start();
+    }
+
+    static CacheKey cacheKey(InetSocketAddress destination,
+                             InetSocketAddress proxy) {
+        return new CacheKey(destination, proxy);
+    }
+
+    synchronized HttpConnection getConnection(boolean secure,
+                                              InetSocketAddress addr,
+                                              InetSocketAddress proxy) {
+        CacheKey key = new CacheKey(addr, proxy);
+        HttpConnection c = secure ? findConnection(key, sslPool)
+                                  : findConnection(key, plainPool);
+        //System.out.println ("getConnection returning: " + c);
+        return c;
+    }
+
+    /**
+     * Returns the connection to the pool.
+     *
+     * @param conn
+     */
+    synchronized void returnToPool(HttpConnection conn) {
+        if (conn instanceof PlainHttpConnection) {
+            putConnection(conn, plainPool);
+        } else {
+            putConnection(conn, sslPool);
+        }
+        addToExpiryList(conn);
+        //System.out.println("Return to pool: " + conn);
+    }
+
+    private HttpConnection
+    findConnection(CacheKey key,
+                   HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        LinkedList<HttpConnection> l = pool.get(key);
+        if (l == null || l.size() == 0) {
+            return null;
+        } else {
+            HttpConnection c = l.removeFirst();
+            removeFromExpiryList(c);
+            return c;
+        }
+    }
+
+    /* called from cache cleaner only  */
+    private void
+    removeFromPool(HttpConnection c,
+                   HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        //System.out.println("cacheCleaner removing: " + c);
+        LinkedList<HttpConnection> l = pool.get(c.cacheKey());
+        assert l != null;
+        boolean wasPresent = l.remove(c);
+        assert wasPresent;
+    }
+
+    private void
+    putConnection(HttpConnection c,
+                  HashMap<CacheKey,LinkedList<HttpConnection>> pool) {
+        CacheKey key = c.cacheKey();
+        LinkedList<HttpConnection> l = pool.get(key);
+        if (l == null) {
+            l = new LinkedList<>();
+            pool.put(key, l);
+        }
+        l.add(c);
+    }
+
+    // only runs while entries exist in cache
+
+    class CacheCleaner extends Thread {
+
+        volatile boolean stopping;
+
+        CacheCleaner() {
+            super(null, null, "HTTP-Cache-cleaner", 0, false);
+            setDaemon(true);
+        }
+
+        synchronized boolean stopping() {
+            return stopping;
+        }
+
+        synchronized void stopCleaner() {
+            stopping = true;
+        }
+
+        @Override
+        public void run() {
+            while (!stopping()) {
+                try {
+                    Thread.sleep(3000);
+                } catch (InterruptedException e) {}
+                cleanCache();
+            }
+        }
+    }
+
+    synchronized void removeFromExpiryList(HttpConnection c) {
+        if (c == null) {
+            return;
+        }
+        ListIterator<ExpiryEntry> li = expiryList.listIterator();
+        while (li.hasNext()) {
+            ExpiryEntry e = li.next();
+            if (e.connection.equals(c)) {
+                li.remove();
+                return;
+            }
+        }
+        if (expiryList.isEmpty()) {
+            cleaner.stopCleaner();
+        }
+    }
+
+    private void cleanCache() {
+        long now = System.currentTimeMillis() / 1000;
+        LinkedList<HttpConnection> closelist = new LinkedList<>();
+
+        synchronized (this) {
+            ListIterator<ExpiryEntry> li = expiryList.listIterator();
+            while (li.hasNext()) {
+                ExpiryEntry entry = li.next();
+                if (entry.expiry <= now) {
+                    li.remove();
+                    HttpConnection c = entry.connection;
+                    closelist.add(c);
+                    if (c instanceof PlainHttpConnection) {
+                        removeFromPool(c, plainPool);
+                    } else {
+                        removeFromPool(c, sslPool);
+                    }
+                }
+            }
+        }
+        for (HttpConnection c : closelist) {
+            //System.out.println ("KAC: closing " + c);
+            c.close();
+        }
+    }
+
+    private synchronized void addToExpiryList(HttpConnection conn) {
+        long now = System.currentTimeMillis() / 1000;
+        long then = now + KEEP_ALIVE;
+
+        if (expiryList.isEmpty())
+            cleaner = new CacheCleaner();
+
+        ListIterator<ExpiryEntry> li = expiryList.listIterator();
+        while (li.hasNext()) {
+            ExpiryEntry entry = li.next();
+
+            if (then > entry.expiry) {
+                li.previous();
+                // insert here
+                li.add(new ExpiryEntry(conn, then));
+                return;
+            }
+        }
+        // first element of list
+        expiryList.add(new ExpiryEntry(conn, then));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.net.CookieManager;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+class CookieFilter implements HeaderFilter {
+
+    final HttpClientImpl client;
+    final CookieManager cookieMan;
+
+    CookieFilter(HttpClientImpl client) {
+        this.client = client;
+        this.cookieMan = client.cookieManager().orElseThrow(
+                () -> new IllegalArgumentException("no cookie manager"));
+    }
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        Map<String,List<String>> userheaders, cookies;
+        userheaders = r.getUserHeaders().directMap();
+        cookies = cookieMan.get(r.uri(), userheaders);
+        // add the returned cookies
+        HttpHeadersImpl systemHeaders = r.getSystemHeaders();
+        Set<String> keys = cookies.keySet();
+        for (String hdrname : keys) {
+            List<String> vals = cookies.get(hdrname);
+            for (String val : vals) {
+                systemHeaders.addHeader(hdrname, val);
+            }
+        }
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        HttpHeaders hdrs = r.headers();
+        cookieMan.put(r.uri(), hdrs.map());
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetSocketAddress;
+import java.net.SocketPermission;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLPermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * One request/response exchange (handles 100/101 intermediate response also).
+ * depth field used to track number of times a new request is being sent
+ * for a given API request. If limit exceeded exception is thrown.
+ *
+ * Security check is performed here:
+ * - uses AccessControlContext captured at API level
+ * - checks for appropriate URLPermission for request
+ * - if permission allowed, grants equivalent SocketPermission to call
+ * - in case of direct HTTP proxy, checks additionally for access to proxy
+ *    (CONNECT proxying uses its own Exchange, so check done there)
+ *
+ */
+class Exchange {
+
+    final HttpRequestImpl request;
+    final HttpClientImpl client;
+    ExchangeImpl exchImpl;
+    HttpResponseImpl response;
+    final List<SocketPermission> permissions = new LinkedList<>();
+    AccessControlContext acc;
+    boolean upgrading; // to HTTP/2
+
+    Exchange(HttpRequestImpl request) {
+        this.request = request;
+        this.upgrading = false;
+        this.client = request.client();
+    }
+
+    /* If different AccessControlContext to be used  */
+    Exchange(HttpRequestImpl request, AccessControlContext acc) {
+        this.request = request;
+        this.acc = acc;
+        this.upgrading = false;
+        this.client = request.client();
+    }
+
+    public HttpRequestImpl request() {
+        return request;
+    }
+
+    public HttpResponseImpl response() throws IOException, InterruptedException {
+        response = responseImpl(null);
+        return response;
+    }
+
+    public void cancel() {
+        if (exchImpl != null)
+            exchImpl.cancel();
+    }
+
+    public void h2Upgrade() {
+        upgrading = true;
+        request.setH2Upgrade();
+    }
+
+    static final SocketPermission[] SOCKET_ARRAY = new SocketPermission[0];
+
+    HttpResponseImpl responseImpl(HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        if (acc == null) {
+            acc = request.getAccessControlContext();
+        }
+        SecurityException e = securityCheck(acc);
+        if (e != null)
+            throw e;
+
+        if (permissions.size() > 0) {
+            try {
+                return AccessController.doPrivileged(
+                        (PrivilegedExceptionAction<HttpResponseImpl>)() ->
+                             responseImpl0(connection),
+                        null,
+                        permissions.toArray(SOCKET_ARRAY));
+            } catch (Throwable ee) {
+                if (ee instanceof PrivilegedActionException) {
+                    ee = ee.getCause();
+                }
+                if (ee instanceof IOException)
+                    throw (IOException)ee;
+                else
+                    throw new RuntimeException(ee); // TODO: fix
+            }
+        } else {
+            return responseImpl0(connection);
+        }
+    }
+
+    HttpResponseImpl responseImpl0(HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        exchImpl = ExchangeImpl.get(this, connection);
+        if (request.expectContinue()) {
+            request.addSystemHeader("Expect", "100-Continue");
+            exchImpl.sendHeadersOnly();
+            HttpResponseImpl resp = exchImpl.getResponse();
+            logResponse(resp);
+            if (resp.statusCode() != 100) {
+                return resp;
+            }
+            exchImpl.sendBody();
+            return exchImpl.getResponse();
+        } else {
+            exchImpl.sendRequest();
+            HttpResponseImpl resp = exchImpl.getResponse();
+            logResponse(resp);
+            return checkForUpgrade(resp, exchImpl);
+        }
+    }
+
+    // Completed HttpResponse will be null if response succeeded
+    // will be a non null responseAsync if expect continue returns an error
+
+    public CompletableFuture<HttpResponseImpl> responseAsync(Void v) {
+        return responseAsyncImpl(null);
+    }
+
+    CompletableFuture<HttpResponseImpl> responseAsyncImpl(HttpConnection connection) {
+        if (acc == null) {
+            acc = request.getAccessControlContext();
+        }
+        SecurityException e = securityCheck(acc);
+        if (e != null) {
+            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+            cf.completeExceptionally(e);
+            return cf;
+        }
+        if (permissions.size() > 0) {
+            return AccessController.doPrivileged(
+                    (PrivilegedAction<CompletableFuture<HttpResponseImpl>>)() ->
+                        responseAsyncImpl0(connection),
+                    null,
+                    permissions.toArray(SOCKET_ARRAY));
+        } else {
+            return responseAsyncImpl0(connection);
+        }
+    }
+
+    CompletableFuture<HttpResponseImpl> responseAsyncImpl0(HttpConnection connection) {
+        try {
+            exchImpl = ExchangeImpl.get(this, connection);
+        } catch (IOException | InterruptedException e) {
+            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+            cf.completeExceptionally(e);
+            return cf;
+        }
+        if (request.expectContinue()) {
+            request.addSystemHeader("Expect", "100-Continue");
+            return exchImpl.sendHeadersAsync()
+                    .thenCompose(exchImpl::getResponseAsync)
+                    .thenCompose((HttpResponseImpl r1) -> {
+                        int rcode = r1.statusCode();
+                        CompletableFuture<HttpResponseImpl> cf =
+                                checkForUpgradeAsync(r1, exchImpl);
+                        if (cf != null)
+                            return cf;
+                        if (rcode == 100) {
+                            return exchImpl.sendBodyAsync()
+                                .thenCompose(exchImpl::getResponseAsync)
+                                .thenApply((r) -> {
+                                    logResponse(r);
+                                    return r;
+                                });
+                        } else {
+                            Exchange.this.response = r1;
+                            logResponse(r1);
+                            return CompletableFuture.completedFuture(r1);
+                        }
+                    });
+        } else {
+            return exchImpl
+                .sendHeadersAsync()
+                .thenCompose((Void v) -> {
+                    // send body and get response at same time
+                    exchImpl.sendBodyAsync();
+                    return exchImpl.getResponseAsync(null);
+                })
+                    .thenCompose((HttpResponseImpl r1) -> {
+                        int rcode = r1.statusCode();
+                        CompletableFuture<HttpResponseImpl> cf =
+                                checkForUpgradeAsync(r1, exchImpl);
+                        if (cf != null) {
+                            return cf;
+                        } else {
+                            Exchange.this.response = r1;
+                            logResponse(r1);
+                            return CompletableFuture.completedFuture(r1);
+                        }
+                    })
+                .thenApply((HttpResponseImpl response) -> {
+                    this.response = response;
+                    logResponse(response);
+                    return response;
+                });
+        }
+    }
+
+    // if this response was received in reply to an upgrade
+    // then create the Http2Connection from the HttpConnection
+    // initialize it and wait for the real response on a newly created Stream
+
+    private CompletableFuture<HttpResponseImpl>
+    checkForUpgradeAsync(HttpResponseImpl resp,
+                         ExchangeImpl ex) {
+        int rcode = resp.statusCode();
+        if (upgrading && (rcode == 101)) {
+            Http1Exchange e = (Http1Exchange)ex;
+            // check for 101 switching protocols
+            return e.responseBodyAsync(HttpResponse.ignoreBody())
+                .thenCompose((Void v) ->
+                     Http2Connection.createAsync(e.connection(),
+                                                 client.client2(),
+                                                 this)
+                        .thenCompose((Http2Connection c) -> {
+                            Stream s = c.getStream(1);
+                            exchImpl = s;
+                            c.putConnection();
+                            return s.getResponseAsync(null);
+                        })
+                );
+        }
+        return CompletableFuture.completedFuture(resp);
+    }
+
+    private HttpResponseImpl checkForUpgrade(HttpResponseImpl resp,
+                                             ExchangeImpl ex)
+        throws IOException, InterruptedException
+    {
+        int rcode = resp.statusCode();
+        if (upgrading && (rcode == 101)) {
+            Http1Exchange e = (Http1Exchange) ex;
+            // must get connection from Http1Exchange
+            e.responseBody(HttpResponse.ignoreBody(), false);
+            Http2Connection h2con = new Http2Connection(e.connection(),
+                                                        client.client2(),
+                                                        this);
+            h2con.putConnection();
+            Stream s = h2con.getStream(1);
+            exchImpl = s;
+            return s.getResponse();
+        }
+        return resp;
+    }
+
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) {
+        try {
+            return exchImpl.responseBody(processor);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+
+    private void logResponse(HttpResponseImpl r) {
+        if (!Log.requests())
+            return;
+        StringBuilder sb = new StringBuilder();
+        String method = r.request().method();
+        URI uri = r.uri();
+        String uristring = uri == null ? "" : uri.toString();
+        sb.append('(')
+          .append(method)
+          .append(" ")
+          .append(uristring)
+          .append(") ")
+          .append(Integer.toString(r.statusCode()));
+        Log.logResponse(sb.toString());
+    }
+
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        return exchImpl.responseBodyAsync(processor);
+    }
+
+    private URI getURIForSecurityCheck() {
+        URI u;
+        String method = request.method();
+        InetSocketAddress authority = request.authority();
+        URI uri = request.uri();
+
+        // CONNECT should be restricted at API level
+        if (method.equalsIgnoreCase("CONNECT")) {
+            try {
+                u = new URI("socket",
+                             null,
+                             authority.getHostString(),
+                             authority.getPort(),
+                             null,
+                             null,
+                             null);
+            } catch (URISyntaxException e) {
+                throw new InternalError(e); // shouldn't happen
+            }
+        } else {
+            u = uri;
+        }
+        return u;
+    }
+
+    /**
+     * Do the security check and return any exception.
+     * Return null if no check needed or passes.
+     *
+     * Also adds any generated permissions to the "permissions" list.
+     */
+    private SecurityException securityCheck(AccessControlContext acc) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return null;
+        }
+
+        String method = request.method();
+        HttpHeadersImpl userHeaders = request.getUserHeaders();
+        URI u = getURIForSecurityCheck();
+        URLPermission p = Utils.getPermission(u, method, userHeaders.directMap());
+
+        try {
+            assert acc != null;
+            sm.checkPermission(p, acc);
+            permissions.add(getSocketPermissionFor(u));
+        } catch (SecurityException e) {
+            return e;
+        }
+        InetSocketAddress proxy = request.proxy();
+        if (proxy != null) {
+            // may need additional check
+            if (!method.equals("CONNECT")) {
+                // a direct http proxy. Need to check access to proxy
+                try {
+                    u = new URI("socket", null, proxy.getHostString(),
+                        proxy.getPort(), null, null, null);
+                } catch (URISyntaxException e) {
+                    throw new InternalError(e); // shouldn't happen
+                }
+                p = new URLPermission(u.toString(), "CONNECT");
+                try {
+                    sm.checkPermission(p, acc);
+                } catch (SecurityException e) {
+                    permissions.clear();
+                    return e;
+                }
+                String sockperm = proxy.getHostString() +
+                        ":" + Integer.toString(proxy.getPort());
+
+                permissions.add(new SocketPermission(sockperm, "connect,resolve"));
+            }
+        }
+        return null;
+    }
+
+    private static SocketPermission getSocketPermissionFor(URI url) {
+        if (System.getSecurityManager() == null)
+            return null;
+
+        StringBuilder sb = new StringBuilder();
+        String host = url.getHost();
+        sb.append(host);
+        int port = url.getPort();
+        if (port == -1) {
+            String scheme = url.getScheme();
+            if ("http".equals(scheme)) {
+                sb.append(":80");
+            } else { // scheme must be https
+                sb.append(":443");
+            }
+        } else {
+            sb.append(':')
+              .append(Integer.toString(port));
+        }
+        String target = sb.toString();
+        return new SocketPermission(target, "connect");
+    }
+
+    AccessControlContext getAccessControlContext() {
+        return acc;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExchangeImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import static java.net.http.HttpClient.Version.HTTP_1_1;
+
+/**
+ * Splits request so that headers and body can be sent separately with optional
+ * (multiple) responses in between (e.g. 100 Continue). Also request and
+ * response always sent/received in different calls.
+ *
+ * Synchronous and asynchronous versions of each method are provided.
+ *
+ * Separate implementations of this class exist for HTTP/1.1 and HTTP/2
+ *      Http1Exchange   (HTTP/1.1)
+ *      Stream          (HTTP/2)
+ *
+ * These implementation classes are where work is allocated to threads.
+ */
+abstract class ExchangeImpl {
+
+    final Exchange exchange;
+
+    ExchangeImpl(Exchange e) {
+        this.exchange = e;
+    }
+
+    /**
+     * Initiates a new exchange and assigns it to a connection if one exists
+     * already. connection usually null.
+     */
+    static ExchangeImpl get(Exchange exchange, HttpConnection connection)
+        throws IOException, InterruptedException
+    {
+        HttpRequestImpl req = exchange.request();
+        if (req.version() == HTTP_1_1) {
+            return new Http1Exchange(exchange, connection);
+        } else {
+            Http2ClientImpl c2 = exchange.request().client().client2(); // TODO: improve
+            HttpRequestImpl request = exchange.request();
+            Http2Connection c = c2.getConnectionFor(request);
+            if (c == null) {
+                // no existing connection. Send request with HTTP 1 and then
+                // upgrade if successful
+                ExchangeImpl ex = new Http1Exchange(exchange, connection);
+                exchange.h2Upgrade();
+                return ex;
+            }
+            return c.createStream(exchange);
+        }
+    }
+
+    /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */
+
+    /**
+     * Sends the request headers only. May block until all sent.
+     */
+    abstract void sendHeadersOnly() throws IOException, InterruptedException;
+
+    /**
+     * Gets response headers by blocking if necessary. This may be an
+     * intermediate response (like 101) or a final response 200 etc.
+     */
+    abstract HttpResponseImpl getResponse() throws IOException;
+
+    /**
+     * Sends a request body after request headers.
+     */
+    abstract void sendBody() throws IOException, InterruptedException;
+
+    /**
+     * Sends the entire request (headers and body) blocking.
+     */
+    abstract void sendRequest() throws IOException, InterruptedException;
+
+    /**
+     * Asynchronous version of sendHeaders().
+     */
+    abstract CompletableFuture<Void> sendHeadersAsync();
+
+    /**
+     * Asynchronous version of getResponse().  Requires void parameter for
+     * CompletableFuture chaining.
+     */
+    abstract CompletableFuture<HttpResponseImpl> getResponseAsync(Void v);
+
+    /**
+     * Asynchronous version of sendBody().
+     */
+    abstract CompletableFuture<Void> sendBodyAsync();
+
+    /**
+     * Cancels a request.  Not currently exposed through API.
+     */
+    abstract void cancel();
+
+    /**
+     * Asynchronous version of sendRequest().
+     */
+    abstract CompletableFuture<Void> sendRequestAsync();
+
+    abstract <T> T responseBody(HttpResponse.BodyProcessor<T> processor)
+        throws IOException;
+
+    /**
+     * Asynchronous version of responseBody().
+     */
+    abstract <T> CompletableFuture<T>
+    responseBodyAsync(HttpResponse.BodyProcessor<T> processor);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ExecutorWrapper.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Supplier;
+
+/**
+ * Wraps the supplied user ExecutorService.
+ *
+ * 1) when a Security manager set, the correct access control context
+ *    is used to execute task
+ *
+ * 2) memory fence implemented
+ */
+class ExecutorWrapper {
+
+    final ExecutorService userExecutor; // the actual executor service used
+    final Executor executor;
+
+    public static ExecutorWrapper wrap(ExecutorService userExecutor) {
+        return new ExecutorWrapper(userExecutor);
+    }
+
+    /**
+     * Returns a dummy ExecutorWrapper which uses the calling thread
+     */
+    public static ExecutorWrapper callingThread() {
+        return new ExecutorWrapper();
+    }
+
+    private ExecutorWrapper(ExecutorService userExecutor) {
+        // used for executing in calling thread
+        this.userExecutor = userExecutor;
+        this.executor = userExecutor;
+    }
+
+    private ExecutorWrapper() {
+        this.userExecutor = null;
+        this.executor = (Runnable command) -> {
+            command.run();
+        };
+    }
+
+    public ExecutorService userExecutor() {
+        return userExecutor;
+    }
+
+    public synchronized void synchronize() {}
+
+    public void execute(Runnable r, Supplier<AccessControlContext> ctxSupplier) {
+        synchronize();
+        Runnable r1 = () -> {
+            try {
+                r.run();
+            } catch (Throwable t) {
+                Log.logError(t);
+            }
+        };
+
+        if (ctxSupplier != null && System.getSecurityManager() != null) {
+            AccessControlContext acc = ctxSupplier.get();
+            if (acc == null) {
+                throw new InternalError();
+            }
+            AccessController.doPrivilegedWithCombiner(
+                (PrivilegedAction<Void>)() -> {
+                    executor.execute(r1); // all throwables must be caught
+                    return null;
+                }, acc);
+        } else {
+            executor.execute(r1); // all throwables must be caught
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.util.LinkedList;
+import java.util.List;
+
+class FilterFactory {
+
+    final LinkedList<Class<? extends HeaderFilter>> filterClasses = new LinkedList<>();
+
+    public void addFilter(Class<? extends HeaderFilter> type) {
+        filterClasses.add(type);
+    }
+
+    List<HeaderFilter> getFilterChain() {
+        List<HeaderFilter> l = new LinkedList<>();
+        for (Class<? extends HeaderFilter> clazz : filterClasses) {
+            try {
+                l.add(clazz.newInstance());
+            } catch (ReflectiveOperationException e) {
+                throw new InternalError(e);
+            }
+        }
+        return l;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFilter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+
+/**
+ * A header filter that can examine or modify, typically system headers for
+ * requests before they are sent, and responses before they are returned to the
+ * user. Some ability to resend requests is provided.
+ *
+ */
+interface HeaderFilter {
+
+    void request(HttpRequestImpl r) throws IOException;
+
+    /**
+     * Returns null if response ok to be given to user.  Non null is a request
+     * that must be resent and its response given to user. If impl throws an
+     * exception that is returned to user instead.
+     */
+    HttpRequestImpl response(HttpResponseImpl r) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderParser.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+/* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers
+ * sensibly:
+ * From a String like: 'timeout=15, max=5'
+ * create an array of Strings:
+ * { {"timeout", "15"},
+ *   {"max", "5"}
+ * }
+ * From one like: 'Basic Realm="FuzzFace" Foo="Biz Bar Baz"'
+ * create one like (no quotes in literal):
+ * { {"basic", null},
+ *   {"realm", "FuzzFace"}
+ *   {"foo", "Biz Bar Baz"}
+ * }
+ * keys are converted to lower case, vals are left as is....
+ */
+class HeaderParser {
+
+    /* table of key/val pairs */
+    String raw;
+    String[][] tab;
+    int nkeys;
+    int asize = 10; // initial size of array is 10
+
+    public HeaderParser(String raw) {
+        this.raw = raw;
+        tab = new String[asize][2];
+        parse();
+    }
+
+    private HeaderParser () { }
+
+    /**
+     * Creates a new HeaderParser from this, whose keys (and corresponding
+     * values) range from "start" to "end-1"
+     */
+    public HeaderParser subsequence(int start, int end) {
+        if (start == 0 && end == nkeys) {
+            return this;
+        }
+        if (start < 0 || start >= end || end > nkeys)
+            throw new IllegalArgumentException("invalid start or end");
+        HeaderParser n = new HeaderParser();
+        n.tab = new String [asize][2];
+        n.asize = asize;
+        System.arraycopy (tab, start, n.tab, 0, (end-start));
+        n.nkeys= (end-start);
+        return n;
+    }
+
+    private void parse() {
+
+        if (raw != null) {
+            raw = raw.trim();
+            char[] ca = raw.toCharArray();
+            int beg = 0, end = 0, i = 0;
+            boolean inKey = true;
+            boolean inQuote = false;
+            int len = ca.length;
+            while (end < len) {
+                char c = ca[end];
+                if ((c == '=') && !inQuote) { // end of a key
+                    tab[i][0] = new String(ca, beg, end-beg).toLowerCase(Locale.US);
+                    inKey = false;
+                    end++;
+                    beg = end;
+                } else if (c == '\"') {
+                    if (inQuote) {
+                        tab[i++][1]= new String(ca, beg, end-beg);
+                        inQuote=false;
+                        do {
+                            end++;
+                        } while (end < len && (ca[end] == ' ' || ca[end] == ','));
+                        inKey=true;
+                        beg=end;
+                    } else {
+                        inQuote=true;
+                        end++;
+                        beg=end;
+                    }
+                } else if (c == ' ' || c == ',') { // end key/val, of whatever we're in
+                    if (inQuote) {
+                        end++;
+                        continue;
+                    } else if (inKey) {
+                        tab[i++][0] = (new String(ca, beg, end-beg)).toLowerCase(Locale.US);
+                    } else {
+                        tab[i++][1] = (new String(ca, beg, end-beg));
+                    }
+                    while (end < len && (ca[end] == ' ' || ca[end] == ',')) {
+                        end++;
+                    }
+                    inKey = true;
+                    beg = end;
+                } else {
+                    end++;
+                }
+                if (i == asize) {
+                    asize = asize * 2;
+                    String[][] ntab = new String[asize][2];
+                    System.arraycopy (tab, 0, ntab, 0, tab.length);
+                    tab = ntab;
+                }
+            }
+            // get last key/val, if any
+            if (--end > beg) {
+                if (!inKey) {
+                    if (ca[end] == '\"') {
+                        tab[i++][1] = (new String(ca, beg, end-beg));
+                    } else {
+                        tab[i++][1] = (new String(ca, beg, end-beg+1));
+                    }
+                } else {
+                    tab[i++][0] = (new String(ca, beg, end-beg+1)).toLowerCase();
+                }
+            } else if (end == beg) {
+                if (!inKey) {
+                    if (ca[end] == '\"') {
+                        tab[i++][1] = String.valueOf(ca[end-1]);
+                    } else {
+                        tab[i++][1] = String.valueOf(ca[end]);
+                    }
+                } else {
+                    tab[i++][0] = String.valueOf(ca[end]).toLowerCase();
+                }
+            }
+            nkeys=i;
+        }
+    }
+
+    public String findKey(int i) {
+        if (i < 0 || i > asize)
+            return null;
+        return tab[i][0];
+    }
+
+    public String findValue(int i) {
+        if (i < 0 || i > asize)
+            return null;
+        return tab[i][1];
+    }
+
+    public String findValue(String key) {
+        return findValue(key, null);
+    }
+
+    public String findValue(String k, String Default) {
+        if (k == null)
+            return Default;
+        k = k.toLowerCase(Locale.US);
+        for (int i = 0; i < asize; ++i) {
+            if (tab[i][0] == null) {
+                return Default;
+            } else if (k.equals(tab[i][0])) {
+                return tab[i][1];
+            }
+        }
+        return Default;
+    }
+
+    class ParserIterator implements Iterator<String> {
+        int index;
+        boolean returnsValue; // or key
+
+        ParserIterator (boolean returnValue) {
+            returnsValue = returnValue;
+        }
+        @Override
+        public boolean hasNext () {
+            return index<nkeys;
+        }
+        @Override
+        public String next () {
+            if (index >= nkeys)
+                throw new NoSuchElementException();
+            return tab[index++][returnsValue?1:0];
+        }
+    }
+
+    public Iterator<String> keys () {
+        return new ParserIterator (false);
+    }
+
+    public Iterator<String> values () {
+        return new ParserIterator (true);
+    }
+
+    @Override
+    public String toString () {
+        Iterator<String> k = keys();
+        StringBuilder sb = new StringBuilder();
+        sb.append("{size=").append(asize).append(" nkeys=").append(nkeys)
+                .append(' ');
+        for (int i=0; k.hasNext(); i++) {
+            String key = k.next();
+            String val = findValue (i);
+            if (val != null && "".equals (val)) {
+                val = null;
+            }
+            sb.append(" {").append(key).append(val == null ? "" : "," + val)
+                    .append('}');
+            if (k.hasNext()) {
+                sb.append (',');
+            }
+        }
+        sb.append (" }");
+        return sb.toString();
+    }
+
+    public int findInt(String k, int Default) {
+        try {
+            return Integer.parseInt(findValue(k, String.valueOf(Default)));
+        } catch (Throwable t) {
+            return Default;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Encapsulates one HTTP/1.1 request/responseAsync exchange.
+ */
+class Http1Exchange extends ExchangeImpl {
+
+    final HttpRequestImpl request;        // main request
+    final List<CompletableFuture<?>> operations; // used for cancel
+    final Http1Request requestAction;
+    volatile Http1Response response;
+    final HttpConnection connection;
+    final HttpClientImpl client;
+    final ExecutorWrapper executor;
+
+    @Override
+    public String toString() {
+        return request.toString();
+    }
+
+    HttpRequestImpl request() {
+        return request;
+    }
+
+    Http1Exchange(Exchange exchange, HttpConnection connection)
+        throws IOException
+    {
+        super(exchange);
+        this.request = exchange.request();
+        this.client = request.client();
+        this.executor = client.executorWrapper();
+        this.operations = Collections.synchronizedList(new LinkedList<>());
+        if (connection != null) {
+            this.connection = connection;
+        } else {
+            InetSocketAddress addr = getAddress(request);
+            this.connection = HttpConnection.getConnection(addr, request);
+        }
+        this.requestAction = new Http1Request(request, this.connection);
+    }
+
+    private static InetSocketAddress getAddress(HttpRequestImpl req) {
+        URI uri = req.uri();
+        if (uri == null) {
+            return req.authority();
+        }
+        int port = uri.getPort();
+        if (port == -1) {
+            if (uri.getScheme().equalsIgnoreCase("https")) {
+                port = 443;
+            } else {
+                port = 80;
+            }
+        }
+        String host = uri.getHost();
+        if (req.proxy() == null) {
+            return new InetSocketAddress(host, port);
+        } else {
+            return InetSocketAddress.createUnresolved(host, port);
+        }
+    }
+
+    HttpConnection connection() {
+        return connection;
+    }
+
+    @Override
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor)
+        throws IOException
+    {
+        return responseBody(processor, true);
+    }
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor,
+                       boolean return2Cache)
+        throws IOException
+    {
+        try {
+            T body = response.readBody(processor, return2Cache);
+            return body;
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    @Override
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        CompletableFuture<T> cf = new CompletableFuture<>();
+        request.client()
+               .executorWrapper()
+               .execute(() -> {
+                            try {
+                                T body = responseBody(processor);
+                                cf.complete(body);
+                            } catch (Throwable e) {
+                                cf.completeExceptionally(e);
+                            }
+                        },
+                        () -> response.response.getAccessControlContext()); // TODO: fix
+        return cf;
+    }
+
+    @Override
+    void sendHeadersOnly() throws IOException, InterruptedException {
+        try {
+            if (!connection.connected()) {
+                connection.connect();
+            }
+            requestAction.sendHeadersOnly();
+        } catch (Throwable e) {
+            connection.close();
+            throw e;
+        }
+    }
+
+    @Override
+    void sendBody() throws IOException {
+        try {
+            requestAction.continueRequest();
+        } catch (Throwable e) {
+            connection.close();
+            throw e;
+        }
+    }
+
+    @Override
+    HttpResponseImpl getResponse() throws IOException {
+        try {
+            response = new Http1Response(connection, this);
+            response.readHeaders();
+            return response.response();
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    @Override
+    void sendRequest() throws IOException, InterruptedException {
+        try {
+            if (!connection.connected()) {
+                connection.connect();
+            }
+            requestAction.sendRequest();
+        } catch (Throwable t) {
+            connection.close();
+            throw t;
+        }
+    }
+
+    private void closeConnection() {
+        connection.close();
+    }
+
+    @Override
+    CompletableFuture<Void> sendHeadersAsync() {
+        if (!connection.connected()) {
+            CompletableFuture<Void> op = connection.connectAsync()
+                    .thenCompose(this::sendHdrsAsyncImpl)
+                    .whenComplete((Void b, Throwable t) -> {
+                        if (t != null)
+                            closeConnection();
+                    });
+            operations.add(op);
+            return op;
+        } else {
+            return sendHdrsAsyncImpl(null);
+        }
+    }
+
+    private CompletableFuture<Void> sendHdrsAsyncImpl(Void v) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+                            try {
+                                requestAction.sendHeadersOnly();
+                                cf.complete(null);
+                            } catch (Throwable e) {
+                                cf.completeExceptionally(e);
+                                connection.close();
+                            }
+                         },
+                         () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+
+    /**
+     * Cancel checks to see if request and responseAsync finished already.
+     * If not it closes the connection and completes all pending operations
+     */
+    @Override
+    synchronized void cancel() {
+        if (requestAction != null && requestAction.finished()
+                && response != null && response.finished()) {
+            return;
+        }
+        connection.close();
+        IOException e = new IOException("Request cancelled");
+        int count = 0;
+        for (CompletableFuture<?> cf : operations) {
+            cf.completeExceptionally(e);
+            count++;
+        }
+        Log.logError("Http1Exchange.cancel: count=" + count);
+    }
+
+    CompletableFuture<HttpResponseImpl> getResponseAsyncImpl(Void v) {
+        CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
+        try {
+            response = new Http1Response(connection, Http1Exchange.this);
+            response.readHeaders();
+            cf.complete(response.response());
+        } catch (IOException e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<HttpResponseImpl> getResponseAsync(Void v) {
+        CompletableFuture<HttpResponseImpl> cf =
+            connection.whenReceivingResponse()
+                      .thenCompose(this::getResponseAsyncImpl);
+
+        operations.add(cf);
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<Void> sendBodyAsync() {
+        final CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                requestAction.continueRequest();
+                cf.complete(null);
+            } catch (Throwable e) {
+                cf.completeExceptionally(e);
+                connection.close();
+            }
+        }, () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+
+    @Override
+    CompletableFuture<Void> sendRequestAsync() {
+        CompletableFuture<Void> op;
+        if (!connection.connected()) {
+            op = connection.connectAsync()
+                .thenCompose(this::sendRequestAsyncImpl)
+                .whenComplete((Void v, Throwable t) -> {
+                    if (t != null) {
+                        closeConnection();
+                    }
+                });
+        } else {
+            op = sendRequestAsyncImpl(null);
+        }
+        operations.add(op);
+        return op;
+    }
+
+    CompletableFuture<Void> sendRequestAsyncImpl(Void v) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                requestAction.sendRequest();
+                cf.complete(null);
+            } catch (Throwable e) {
+                cf.completeExceptionally(e);
+                connection.close();
+            }
+        }, () -> request.getAccessControlContext());
+        operations.add(cf);
+        return cf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.util.function.LongConsumer;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/**
+ *  A HTTP/1.1 request.
+ *
+ * send() -> Writes the request + body to the given channel, in one blocking
+ * operation.
+ */
+class Http1Request {
+
+    final HttpRequestImpl request;
+    final HttpConnection chan;
+    // Multiple buffers are used to hold different parts of request
+    // See line 206 and below for description
+    final ByteBuffer[] buffers;
+    final HttpRequest.BodyProcessor requestProc;
+    final HttpHeadersImpl userHeaders, systemHeaders;
+    final LongConsumer flowController;
+    boolean streaming;
+    long contentLength;
+
+    Http1Request(HttpRequestImpl request, HttpConnection connection)
+        throws IOException
+    {
+        this.request = request;
+        this.chan = connection;
+        buffers = new ByteBuffer[5]; // TODO: check
+        this.requestProc = request.requestProcessor();
+        this.userHeaders = request.getUserHeaders();
+        this.systemHeaders = request.getSystemHeaders();
+        this.flowController = this::dummy;
+    }
+
+    private void logHeaders() throws IOException {
+        StringBuilder sb = new StringBuilder(256);
+        sb.append("REQUEST HEADERS:\r\n");
+        collectHeaders1(sb, request, systemHeaders);
+        collectHeaders1(sb, request, userHeaders);
+        Log.logHeaders(sb.toString());
+    }
+
+    private void dummy(long x) {
+        // not used in this class
+    }
+
+    private void collectHeaders0() throws IOException {
+        if (Log.headers()) {
+            logHeaders();
+        }
+        StringBuilder sb = new StringBuilder(256);
+        collectHeaders1(sb, request, systemHeaders);
+        collectHeaders1(sb, request, userHeaders);
+        sb.append("\r\n");
+        String headers = sb.toString();
+        buffers[1] = ByteBuffer.wrap(headers.getBytes(StandardCharsets.US_ASCII));
+    }
+
+    private void collectHeaders1(StringBuilder sb,
+                                 HttpRequestImpl request,
+                                 HttpHeadersImpl headers)
+        throws IOException
+    {
+        Map<String,List<String>> h = headers.directMap();
+        Set<Map.Entry<String,List<String>>> entries = h.entrySet();
+
+        for (Map.Entry<String,List<String>> entry : entries) {
+            String key = entry.getKey();
+            sb.append(key).append(": ");
+            List<String> values = entry.getValue();
+            int num = values.size();
+            for (String value : values) {
+                sb.append(value);
+                if (--num > 0) {
+                    sb.append(',');
+                }
+            }
+            sb.append("\r\n");
+        }
+    }
+
+    private static final int BUFSIZE = 64 * 1024; // TODO: configurable?
+
+    private String getPathAndQuery(URI uri) {
+        String path = uri.getPath();
+        String query = uri.getQuery();
+        if (path == null || path.equals("")) {
+            path = "/";
+        }
+        if (query == null) {
+            query = "";
+        }
+        if (query.equals("")) {
+            return path;
+        } else {
+            return path + "?" + query;
+        }
+    }
+
+    private String authorityString(InetSocketAddress addr) {
+        return addr.getHostString() + ":" + addr.getPort();
+    }
+
+    private String requestURI() {
+        URI uri = request.uri();
+        String method = request.method();
+
+        if ((request.proxy() == null && !method.equals("CONNECT"))
+                || request.isWebSocket()) {
+            return getPathAndQuery(uri);
+        }
+        if (request.secure()) {
+            if (request.method().equals("CONNECT")) {
+                // use authority for connect itself
+                return authorityString(request.authority());
+            } else {
+                // requests over tunnel do not require full URL
+                return getPathAndQuery(uri);
+            }
+        }
+        return uri == null? authorityString(request.authority()) : uri.toString();
+    }
+
+    void sendHeadersOnly() throws IOException {
+        collectHeaders();
+        chan.write(buffers, 0, 2);
+    }
+
+    void sendRequest() throws IOException {
+        collectHeaders();
+        if (contentLength == 0) {
+            chan.write(buffers, 0, 2);
+        } else if (contentLength > 0) {
+            writeFixedContent(true);
+        } else {
+            writeStreamedContent(true);
+        }
+        setFinished();
+    }
+
+    private boolean finished;
+
+    synchronized boolean finished() {
+        return  finished;
+    }
+
+    synchronized void setFinished() {
+        finished = true;
+    }
+
+    private void collectHeaders() throws IOException {
+        if (Log.requests() && request != null) {
+            Log.logRequest(request.toString());
+        }
+        String uriString = requestURI();
+        StringBuilder sb = new StringBuilder(64);
+        sb.append(request.method())
+          .append(' ')
+          .append(uriString)
+          .append(" HTTP/1.1\r\n");
+        String cmd = sb.toString();
+
+        buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII));
+        URI uri = request.uri();
+        if (uri != null) {
+            systemHeaders.setHeader("Host", uri.getHost());
+        }
+        if (request == null) {
+            // this is not a user request. No content
+            contentLength = 0;
+        } else {
+            contentLength = requestProc.onRequestStart(request, flowController);
+        }
+
+        if (contentLength == 0) {
+            systemHeaders.setHeader("Content-Length", "0");
+            collectHeaders0();
+        } else if (contentLength > 0) {
+            /* [0] request line [1] headers [2] body  */
+            systemHeaders.setHeader("Content-Length",
+                                    Integer.toString((int) contentLength));
+            streaming = false;
+            collectHeaders0();
+            buffers[2] = chan.getBuffer();
+        } else {
+            /* Chunked:
+             *
+             * [0] request line [1] headers [2] chunk header [3] chunk data [4]
+             * final chunk header and trailing CRLF of previous chunks
+             *
+             * 2,3,4 used repeatedly */
+            streaming = true;
+            systemHeaders.setHeader("Transfer-encoding", "chunked");
+            collectHeaders0();
+            buffers[3] = chan.getBuffer();
+        }
+    }
+
+    // The following two methods used by Http1Exchange to handle expect continue
+
+    void continueRequest() throws IOException {
+        if (streaming) {
+            writeStreamedContent(false);
+        } else {
+            writeFixedContent(false);
+        }
+        setFinished();
+    }
+
+    /* Entire request is sent, or just body only  */
+    private void writeStreamedContent(boolean includeHeaders)
+        throws IOException
+    {
+        if (requestProc instanceof HttpRequest.BodyProcessor) {
+            HttpRequest.BodyProcessor pullproc = requestProc;
+            int startbuf, nbufs;
+
+            if (includeHeaders) {
+                startbuf = 0;
+                nbufs = 5;
+            } else {
+                startbuf = 2;
+                nbufs = 3;
+            }
+            try {
+                // TODO: currently each write goes out as one chunk
+                // TODO: should be collecting data and buffer it.
+
+                buffers[3].clear();
+                boolean done = pullproc.onRequestBodyChunk(buffers[3]);
+                int chunklen = buffers[3].position();
+                buffers[2] = getHeader(chunklen);
+                buffers[3].flip();
+                buffers[4] = CRLF_BUFFER();
+                chan.write(buffers, startbuf, nbufs);
+                while (!done) {
+                    buffers[3].clear();
+                    done = pullproc.onRequestBodyChunk(buffers[3]);
+                    if (done)
+                        break;
+                    buffers[3].flip();
+                    chunklen = buffers[3].remaining();
+                    buffers[2] = getHeader(chunklen);
+                    buffers[4] = CRLF_BUFFER();
+                    chan.write(buffers, 2, 3);
+                }
+                buffers[3] = EMPTY_CHUNK_HEADER();
+                buffers[4] = CRLF_BUFFER();
+                chan.write(buffers, 3, 2);
+            } catch (IOException e) {
+                requestProc.onRequestError(e);
+                throw e;
+            }
+        }
+    }
+    /* Entire request is sent, or just body only */
+    private void writeFixedContent(boolean includeHeaders)
+        throws IOException
+    {
+        try {
+            int startbuf, nbufs;
+
+            if (contentLength == 0) {
+                return;
+            }
+            if (includeHeaders) {
+                startbuf = 0;
+                nbufs = 3;
+            } else {
+                startbuf = 2;
+                nbufs = 1;
+                buffers[0].clear().flip();
+                buffers[1].clear().flip();
+            }
+            buffers[2] = chan.getBuffer();
+            if (requestProc instanceof HttpRequest.BodyProcessor) {
+                HttpRequest.BodyProcessor pullproc = requestProc;
+
+                boolean done = pullproc.onRequestBodyChunk(buffers[2]);
+                buffers[2].flip();
+                long headersLength = buffers[0].remaining() + buffers[1].remaining();
+                long contentWritten = buffers[2].remaining();
+                chan.checkWrite(headersLength + contentWritten,
+                                buffers,
+                                startbuf,
+                                nbufs);
+                while (!done) {
+                    buffers[2].clear();
+                    done = pullproc.onRequestBodyChunk(buffers[2]);
+                    buffers[2].flip();
+                    long len = buffers[2].remaining();
+                    if (contentWritten + len > contentLength) {
+                        break;
+                    }
+                    chan.checkWrite(len, buffers[2]);
+                    contentWritten += len;
+                }
+                if (contentWritten != contentLength) {
+                    throw new IOException("wrong content length");
+                }
+            }
+        } catch (IOException e) {
+            requestProc.onRequestError(e);
+            throw e;
+        }
+    }
+
+    private static final byte[] CRLF = {'\r', '\n'};
+    private static final byte[] EMPTY_CHUNK_BYTES = {'0', '\r', '\n'};
+
+    private ByteBuffer CRLF_BUFFER() {
+        return ByteBuffer.wrap(CRLF);
+    }
+
+    private ByteBuffer EMPTY_CHUNK_HEADER() {
+        return ByteBuffer.wrap(EMPTY_CHUNK_BYTES);
+    }
+
+    /* Returns a header for a particular chunk size */
+    private static ByteBuffer getHeader(int size){
+        String hexStr =  Integer.toHexString(size);
+        byte[] hexBytes = hexStr.getBytes(US_ASCII);
+        byte[] header = new byte[hexStr.length()+2];
+        System.arraycopy(hexBytes, 0, header, 0, hexBytes.length);
+        header[hexBytes.length] = CRLF[0];
+        header[hexBytes.length+1] = CRLF[1];
+        return ByteBuffer.wrap(header);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.LongConsumer;
+import static java.net.http.HttpClient.Version.HTTP_1_1;
+
+/**
+ * Handles a HTTP/1.1 response in two blocking calls. readHeaders() and
+ * readBody(). There can be more than one of these per Http exchange.
+ */
+class Http1Response {
+
+    private ResponseContent content;
+    private final HttpRequestImpl request;
+    HttpResponseImpl response;
+    private final HttpConnection connection;
+    private ResponseHeaders headers;
+    private int responseCode;
+    private ByteBuffer buffer; // same buffer used for reading status line and headers
+    private final Http1Exchange exchange;
+    private final boolean redirecting; // redirecting
+    private boolean return2Cache; // return connection to cache when finished
+
+    Http1Response(HttpConnection conn, Http1Exchange exchange) {
+        this.request = exchange.request();
+        this.exchange = exchange;
+        this.connection = conn;
+        this.redirecting = false;
+        buffer = connection.getRemaining();
+    }
+
+    // called when the initial read should come from a buffer left
+    // over from a previous response.
+    void setBuffer(ByteBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void readHeaders() throws IOException {
+        String statusline = readStatusLine();
+        if (statusline == null) {
+            if (Log.errors()) {
+                Log.logError("Connection closed. Retry");
+            }
+            connection.close();
+            // connection was closed
+            throw new IOException("Connection closed");
+        }
+        if (!statusline.startsWith("HTTP/1.")) {
+            throw new IOException("Invalid status line: " + statusline);
+        }
+        char c = statusline.charAt(7);
+        responseCode = Integer.parseInt(statusline.substring(9, 12));
+
+        headers = new ResponseHeaders(connection, buffer);
+        headers.initHeaders();
+        if (Log.headers()) {
+            logHeaders(headers);
+        }
+        response = new HttpResponseImpl(responseCode,
+                                        exchange.exchange,
+                                        headers,
+                                        null,
+                                        connection.sslParameters(),
+                                        HTTP_1_1,
+                                        connection);
+    }
+
+    private boolean finished;
+
+    synchronized void completed() {
+        finished = true;
+    }
+
+    synchronized boolean finished() {
+        return finished;
+    }
+
+    // Blocking flow controller implementation. Only works when a
+    // thread is dedicated to reading response body
+
+    static class FlowController implements LongConsumer {
+        long window ;
+
+        @Override
+        public synchronized void accept(long value) {
+            window += value;
+            notifyAll();
+        }
+
+        public synchronized void request(long value) throws InterruptedException {
+            while (window < value) {
+                wait();
+            }
+            window -= value;
+        }
+    }
+
+    FlowController flowController;
+
+    int fixupContentLen(int clen) {
+        if (request.method().equalsIgnoreCase("HEAD")) {
+            return 0;
+        }
+        if (clen == -1) {
+            if (headers.firstValue("Transfer-encoding").orElse("")
+                       .equalsIgnoreCase("chunked")) {
+                return -1;
+            }
+            return 0;
+        }
+        return clen;
+    }
+
+    private void returnBuffer(ByteBuffer buf) {
+        // not currently used, but will be when we change SSL to use fixed
+        // sized buffers and a single buffer pool for HttpClientImpl
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T readBody(java.net.http.HttpResponse.BodyProcessor<T> p,
+                          boolean return2Cache)
+        throws IOException
+    {
+        T body = null; // TODO: check null case below
+        this.return2Cache = return2Cache;
+        final java.net.http.HttpResponse.BodyProcessor<T> pusher = p;
+
+        int clen0 = headers.getContentLength();
+        final int clen = fixupContentLen(clen0);
+
+        flowController = new FlowController();
+
+        body = pusher.onResponseBodyStart(clen, headers, flowController);
+
+        ExecutorWrapper executor;
+        if (body == null) {
+            executor = ExecutorWrapper.callingThread();
+        } else {
+            executor = request.client().executorWrapper();
+        }
+
+        final ResponseHeaders h = headers;
+        if (body == null) {
+            content = new ResponseContent(connection,
+                                          clen,
+                                          h,
+                                          pusher,
+                                          flowController);
+            content.pushBody(headers.getResidue());
+            body = pusher.onResponseComplete();
+            completed();
+            onFinished();
+            return body;
+        } else {
+            executor.execute(() -> {
+                    try {
+                        content = new ResponseContent(connection,
+                                                      clen,
+                                                      h,
+                                                      pusher,
+                                                      flowController);
+                        content.pushBody(headers.getResidue());
+                        pusher.onResponseComplete();
+                        completed();
+                        onFinished();
+                    } catch (Throwable e) {
+                        pusher.onResponseError(e);
+                    }
+                },
+                () -> response.getAccessControlContext());
+        }
+        return body;
+    }
+
+    private void onFinished() {
+        connection.buffer = content.getResidue();
+        if (return2Cache) {
+            connection.returnToCache(headers);
+        }
+    }
+
+    private void logHeaders(ResponseHeaders headers) {
+        Map<String, List<String>> h = headers.mapInternal();
+        Set<String> keys = h.keySet();
+        Set<Map.Entry<String, List<String>>> entries = h.entrySet();
+        for (Map.Entry<String, List<String>> entry : entries) {
+            String key = entry.getKey();
+            StringBuilder sb = new StringBuilder();
+            sb.append(key).append(": ");
+            List<String> values = entry.getValue();
+            if (values != null) {
+                for (String value : values) {
+                    sb.append(value).append(' ');
+                }
+            }
+            Log.logHeaders(sb.toString());
+        }
+    }
+
+    HttpResponseImpl response() {
+        return response;
+    }
+
+    boolean redirecting() {
+        return redirecting;
+    }
+
+    HttpHeaders responseHeaders() {
+        return headers;
+    }
+
+    int responseCode() {
+        return responseCode;
+    }
+
+    static final char CR = '\r';
+    static final char LF = '\n';
+
+    private ByteBuffer getBuffer() throws IOException {
+        if (buffer == null || !buffer.hasRemaining()) {
+            buffer = connection.read();
+        }
+        return buffer;
+    }
+
+    ByteBuffer buffer() {
+        return buffer;
+    }
+
+    String readStatusLine() throws IOException {
+        boolean cr = false;
+        StringBuilder statusLine = new StringBuilder(128);
+        ByteBuffer b;
+        while ((b = getBuffer()) != null) {
+            byte[] buf = b.array();
+            int offset = b.position();
+            int len = b.limit() - offset;
+
+            for (int i = 0; i < len; i++) {
+                char c = (char) buf[i+offset];
+
+                if (cr) {
+                    if (c == LF) {
+                        b.position(i + 1 + offset);
+                        return statusLine.toString();
+                    } else {
+                        throw new IOException("invalid status line");
+                    }
+                }
+                if (c == CR) {
+                    cr = true;
+                } else {
+                    statusLine.append(c);
+                }
+            }
+            // unlikely, but possible, that multiple reads required
+            b.position(b.limit());
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+class Http2ClientImpl {
+    Http2ClientImpl(HttpClientImpl t) {}
+    String getSettingsString() {return "";}
+    void debugPrint() {}
+    Http2Connection getConnectionFor(HttpRequestImpl r) {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.net.URI;
+import static java.net.http.Utils.BUFSIZE;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import static java.nio.channels.SelectionKey.OP_CONNECT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import java.nio.channels.Selector;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+import java.security.NoSuchAlgorithmException;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+class Http2Connection {
+    static CompletableFuture<Http2Connection> createAsync(
+        HttpConnection connection, Http2ClientImpl client2, Exchange exchange) {
+            return null;
+        }
+
+    Http2Connection(HttpConnection connection, Http2ClientImpl client2,
+            Exchange exchange) throws IOException, InterruptedException {
+    }
+
+    Stream getStream(int i) {return null;}
+    Stream createStream(Exchange ex) {return null;}
+    void putConnection() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClient.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.InetSocketAddress;
+import java.net.NetPermission;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.util.Optional;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * A container for configuration information common to multiple {@link
+ * HttpRequest}s. All requests are associated with, and created from a {@code
+ * HttpClient}.
+ *
+ * <p> {@code HttpClient}s are immutable and created from a builder returned
+ * from {@link HttpClient#create()}. Request builders that are associated with
+ * an application created client, are created by calling {@link #request(URI) }.
+ * It is also possible to create a request builder directly which is associated
+ * with the <i>default</i> {@code HttpClient} by calling {@link
+ * HttpRequest#create(URI)}.
+ *
+ * <p> The HTTP API functions asynchronously (using {@link
+ * java.util.concurrent.CompletableFuture}) and also in a simple synchronous
+ * mode, where all work may be done on the calling thread. In asynchronous mode,
+ * work is done on the threads supplied by the client's {@link
+ * java.util.concurrent.ExecutorService}.
+ *
+ * <p> <a name="defaultclient"></a> The <i>default</i> {@code HttpClient} is
+ * used whenever a request is created without specifying a client explicitly
+ * (by calling {@link HttpRequest#create(java.net.URI) HttpRequest.create}).
+ * There is only one static instance of this {@code HttpClient}. A reference to
+ * the default client can be obtained by calling {@link #getDefault() }. If a
+ * security manager is set, then a permission is required for this.
+ *
+ * <p> See {@link HttpRequest} for examples of usage of this API.
+ *
+ * @since 9
+ */
+public abstract class HttpClient {
+
+    HttpClient() {}
+
+    private static HttpClient defaultClient;
+
+    /**
+     * Creates a new {@code HttpClient} builder.
+     *
+     * @return a {@code HttpClient.Builder}
+     */
+    public static Builder  create() {
+        return new HttpClientBuilderImpl();
+    }
+
+    //public abstract void debugPrint();
+
+    /**
+     * Returns the default {@code HttpClient} that is used when a {@link
+     * HttpRequest} is created without specifying a client. If a security
+     * manager is set, then its {@code checkPermission} method is called with a
+     * {@link java.net.NetPermission} specifying the name "getDefaultHttpClient".
+     * If the caller does not possess this permission a {@code SecurityException}
+     * is thrown.
+     *
+     * @implNote Code running under a security manager can avoid the security
+     * manager check by creating a {@code HttpClient} explicitly.
+     *
+     * @return the default {@code HttpClient}
+     * @throws SecurityException if the caller does not have the required
+     *                           permission
+     */
+    public synchronized static HttpClient getDefault() {
+        Utils.checkNetPermission("getDefaultHttpClient");
+        if (defaultClient == null) {
+            Builder b = create();
+            defaultClient = b.executorService(Executors.newCachedThreadPool())
+                             .build();
+        }
+        return defaultClient;
+    }
+
+    /**
+     * Creates a {@code HttpRequest} builder associated with this client.
+     *
+     * @return a new builder
+     */
+    public abstract HttpRequest.Builder request();
+
+    /**
+     * Creates a {@code HttpRequest} builder associated with this client and
+     * using the given request URI.
+     *
+     * @param uri the request URI
+     * @return a new builder
+     */
+    public abstract HttpRequest.Builder request(URI uri);
+
+    /**
+     * A builder of immutable {@link HttpClient}s. {@code HttpClient.Builder}s
+     * are created by calling {@link HttpClient#create()}.
+     *
+     * <p> Each of the setter methods in this class modifies the state of the
+     * builder and returns <i>this</i> (ie. the same instance). The methods are
+     * not synchronized and should not be called from multiple threads without
+     * external synchronization.
+     *
+     * <p> {@link #build() } returns a new {@code HttpClient} each time it is
+     * called.
+     *
+     * @since 9
+     */
+    public abstract static class Builder {
+
+        Builder() {}
+
+        /**
+         * Sets a cookie manager.
+         *
+         * @param manager the CookieManager
+         * @return this builder
+         * @throws NullPointerException if {@code manager} is null
+         */
+        public abstract Builder cookieManager(CookieManager manager);
+
+        /**
+         * Sets an SSLContext. If a security manager is set, then the caller
+         * must have the {@link java.net.NetPermission NetPermission}
+         * ("setSSLContext")
+         *
+         * <p> The effect of not calling this method, is that a default {@link
+         * javax.net.ssl.SSLContext} is used, which is normally adequate for
+         * client applications that do not need to specify protocols, or require
+         * client authentication.
+         *
+         * @param sslContext the SSLContext
+         * @return this builder
+         * @throws NullPointerException if {@code sslContext} is null
+         * @throws SecurityException if a security manager is set and the
+         *                           caller does not have any required permission
+         */
+        public abstract Builder sslContext(SSLContext sslContext);
+
+        /**
+         * Sets an SSLParameters. If this method is not called, then a default
+         * set of parameters are used. The contents of the given object are
+         * copied. Some parameters which are used internally by the HTTP protocol
+         * implementation (such as application protocol list) should not be set
+         * by callers, as they are ignored.
+         *
+         * @param sslParameters the SSLParameters
+         * @return this builder
+         * @throws NullPointerException if {@code sslParameters} is null
+         */
+        public abstract Builder sslParameters(SSLParameters sslParameters);
+
+        /**
+         * Sets the ExecutorService to be used for sending and receiving
+         * asynchronous requests. If this method is not called, a default
+         * executor service is set, which is the one returned from {@link
+         * java.util.concurrent.Executors#newCachedThreadPool()
+         * Executors.newCachedThreadPool}.
+         *
+         * @param s the ExecutorService
+         * @return this builder
+         * @throws NullPointerException if {@code s} is null
+         */
+        public abstract Builder executorService(ExecutorService s);
+
+        /**
+         * Specifies whether requests will automatically follow redirects issued
+         * by the server. This setting can be overridden on each request. The
+         * default value for this setting is {@link Redirect#NEVER NEVER}
+         *
+         * @param policy the redirection policy
+         * @return this builder
+         * @throws NullPointerException if {@code policy} is null
+         */
+        public abstract Builder followRedirects(Redirect policy);
+
+        /**
+         * Requests a specific HTTP protocol version where possible. If not set,
+         * the version defaults to {@link HttpClient.Version#HTTP_1_1}. If
+         * {@link HttpClient.Version#HTTP_2} is set, then each request will
+         * attempt to upgrade to HTTP/2.  If the upgrade succeeds, then the
+         * response to this request will use HTTP/2 and all subsequent requests
+         * and responses to the same
+         * <a href="https://tools.ietf.org/html/rfc6454#section-4">origin server</a>
+         * will use HTTP/2. If the upgrade fails, then the response will be
+         * handled using HTTP/1.1
+         *
+         * <p>This setting can be over-ridden per request.
+         *
+         * @param version the requested HTTP protocol version
+         * @return this builder
+         * @throws NullPointerException if {@code version} is null
+         */
+        public abstract Builder version(HttpClient.Version version);
+
+        /**
+         * Sets the default priority for any HTTP/2 requests sent from this
+         * client. The value provided must be between {@code 1} and {@code 255}.
+         *
+         * @param priority the priority weighting
+         * @return this builder
+         * @throws IllegalArgumentException if the given priority is out of range
+         */
+        public abstract Builder priority(int priority);
+
+        /**
+         * Enables pipelining mode for HTTP/1.1 requests sent through this
+         * client. When pipelining is enabled requests to the same destination
+         * are sent over existing TCP connections that may already have requests
+         * outstanding. This reduces the number of connections, but may have
+         * a performance impact since responses must be delivered in the same
+         * order that they were sent. By default, pipelining is disabled.
+         *
+         * @param enable {@code true} enables pipelining
+         * @return this builder
+         * @throws UnsupportedOperationException if pipelining mode is not
+         *                                       supported by this implementation
+         */
+        public abstract Builder pipelining(boolean enable);
+
+        /**
+         * Sets a {@link java.net.ProxySelector} for this client. If no selector
+         * is set, then no proxies are used. If a {@code null} parameter is
+         * given then the system wide default proxy selector is used.
+         *
+         * @implNote {@link java.net.ProxySelector#of(InetSocketAddress)}
+         * provides a ProxySelector which uses one proxy for all requests.
+         *
+         * @param selector the ProxySelector
+         * @return this builder
+         */
+        public abstract Builder proxy(ProxySelector selector);
+
+        /**
+         * Sets an authenticator to use for HTTP authentication.
+         *
+         * @param a the Authenticator
+         * @return this builder
+         */
+        public abstract Builder authenticator(Authenticator a);
+
+        /**
+         * Returns a {@link HttpClient} built from the current state of this
+         * builder.
+         *
+         * @return this builder
+         */
+        public abstract HttpClient build();
+    }
+
+
+    /**
+     * Returns an {@code Optional} which contains this client's {@link
+     * CookieManager}. If no CookieManager was set in this client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's CookieManager
+     */
+    public abstract Optional<CookieManager> cookieManager();
+
+    /**
+     * Returns the follow-redirects setting for this client. The default value
+     * for this setting is {@link HttpClient.Redirect#NEVER}
+     *
+     * @return this client's follow redirects setting
+     */
+    public abstract Redirect followRedirects();
+
+    /**
+     * Returns an {@code Optional} containing the ProxySelector for this client.
+     * If no proxy is set then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's proxy selector
+     */
+    public abstract Optional<ProxySelector> proxy();
+
+    /**
+     * Returns the SSLContext, if one was set on this client. If a security
+     * manager is set then then caller must then the caller must have the
+     * {@link java.net.NetPermission NetPermission}("getSSLContext") permission.
+     * If no SSLContext was set, then the default context is returned.
+     *
+     * @return this client's SSLContext
+     */
+    public abstract SSLContext sslContext();
+
+    /**
+     * Returns an {@code Optional} containing the {@link SSLParameters} set on
+     * this client. If no {@code SSLParameters} were set in the client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's SSLParameters
+     */
+    public abstract Optional<SSLParameters> sslParameters();
+
+    /**
+     * Returns an {@code Optional} containing the {@link Authenticator} set on
+     * this client. If no {@code Authenticator} was set in the client's builder,
+     * then the {@code Optional} is empty.
+     *
+     * @return an {@code Optional} containing this client's Authenticator
+     */
+    public abstract Optional<Authenticator> authenticator();
+
+    /**
+     * Returns the HTTP protocol version requested for this client. The default
+     * value is {@link HttpClient.Version#HTTP_1_1}
+     *
+     * @return the HTTP protocol version requested
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * Returns whether this client supports HTTP/1.1 pipelining.
+     *
+     * @return whether pipelining allowed
+     */
+    public abstract boolean pipelining();
+
+    /**
+     * Returns the {@code ExecutorService} set on this client. If an {@code
+     * ExecutorService} was not set on the client's builder, then a default
+     * object is returned. The default ExecutorService is created independently
+     * for each client.
+     *
+     * @return this client's ExecutorService
+     */
+    public abstract ExecutorService executorService();
+
+    /**
+     * The HTTP protocol version.
+     *
+     * @since 9
+     */
+    public static enum Version {
+
+        /**
+         * HTTP version 1.1
+         */
+        HTTP_1_1,
+
+        /**
+         * HTTP version 2
+         */
+        HTTP_2
+    }
+
+    /**
+     * Defines automatic redirection policy. This is checked whenever a 3XX
+     * response code is received. If redirection does not happen automatically
+     * then the response is returned to the user, where it can be handled
+     * manually.
+     *
+     * <p> {@code Redirect} policy is set via the {@link
+     * HttpClient.Builder#followRedirects(HttpClient.Redirect)} method.
+     *
+     * @since 9
+     */
+    public static enum Redirect {
+
+        /**
+         * Never redirect.
+         */
+        NEVER,
+
+        /**
+         * Always redirect.
+         */
+        ALWAYS,
+
+        /**
+         * Redirect to same protocol only. Redirection may occur from HTTP URLs
+         * to other HTTP URLs, and from HTTPS URLs to other HTTPS URLs.
+         */
+        SAME_PROTOCOL,
+
+        /**
+         * Redirect always except from HTTPS URLs to HTTP URLs.
+         */
+        SECURE
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientBuilderImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.util.Objects;
+import java.util.concurrent.ExecutorService;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+class HttpClientBuilderImpl extends HttpClient.Builder {
+
+    CookieManager cookieManager;
+    HttpClient.Redirect followRedirects;
+    ProxySelector proxy;
+    Authenticator authenticator;
+    HttpClient.Version version = HttpClient.Version.HTTP_1_1;
+    ExecutorService executor;
+    // Security parameters
+    SSLContext sslContext;
+    SSLParameters sslParams;
+    int priority = -1;
+
+    @Override
+    public HttpClientBuilderImpl cookieManager(CookieManager manager) {
+        Objects.requireNonNull(manager);
+        this.cookieManager = manager;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl sslContext(SSLContext sslContext) {
+        Objects.requireNonNull(sslContext);
+        Utils.checkNetPermission("setSSLContext");
+        this.sslContext = sslContext;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl sslParameters(SSLParameters sslParameters) {
+        Objects.requireNonNull(sslParameters);
+        this.sslParams = sslParameters;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl executorService(ExecutorService s) {
+        Objects.requireNonNull(s);
+        this.executor = s;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl followRedirects(HttpClient.Redirect policy) {
+        Objects.requireNonNull(policy);
+        this.followRedirects = policy;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl version(HttpClient.Version version) {
+        Objects.requireNonNull(version);
+        this.version = version;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl priority(int priority) {
+        if (priority < 1 || priority > 255) {
+            throw new IllegalArgumentException("priority must be between 1 and 255");
+        }
+        this.priority = priority;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl pipelining(boolean enable) {
+        //To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl proxy(ProxySelector proxy) {
+        Objects.requireNonNull(proxy);
+        this.proxy = proxy;
+        return this;
+    }
+
+
+    @Override
+    public HttpClientBuilderImpl authenticator(Authenticator a) {
+        Objects.requireNonNull(a);
+        this.authenticator = a;
+        return this;
+    }
+
+    @Override
+    public HttpClient build() {
+        return HttpClientImpl.create(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.CookieManager;
+import java.net.ProxySelector;
+import java.net.URI;
+import static java.net.http.Utils.BUFSIZE;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import static java.nio.channels.SelectionKey.OP_CONNECT;
+import static java.nio.channels.SelectionKey.OP_READ;
+import static java.nio.channels.SelectionKey.OP_WRITE;
+import java.nio.channels.Selector;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.security.NoSuchAlgorithmException;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Client implementation. Contains all configuration information and also
+ * the selector manager thread which allows async events to be registered
+ * and delivered when they occur. See AsyncEvent.
+ */
+class HttpClientImpl extends HttpClient implements BufferHandler {
+
+    private final CookieManager cookieManager;
+    private final Redirect followRedirects;
+    private final ProxySelector proxySelector;
+    private final Authenticator authenticator;
+    private final Version version;
+    private boolean pipelining = false;
+    private final ConnectionPool connections;
+    private final ExecutorWrapper executor;
+    // Security parameters
+    private final SSLContext sslContext;
+    private final SSLParameters sslParams;
+    private final SelectorManager selmgr;
+    private final FilterFactory filters;
+    private final Http2ClientImpl client2;
+    private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
+    private final LinkedList<TimeoutEvent> timeouts;
+
+    //@Override
+    void debugPrint() {
+        selmgr.debugPrint();
+        client2.debugPrint();
+    }
+
+    public static HttpClientImpl create(HttpClientBuilderImpl builder) {
+        HttpClientImpl impl = new HttpClientImpl(builder);
+        impl.start();
+        return impl;
+    }
+
+    private HttpClientImpl(HttpClientBuilderImpl builder) {
+        if (builder.sslContext == null) {
+            try {
+                sslContext = SSLContext.getDefault();
+            } catch (NoSuchAlgorithmException ex) {
+                throw new InternalError(ex);
+            }
+        } else {
+            sslContext = builder.sslContext;
+        }
+        ExecutorService ex = builder.executor;
+        if (ex == null) {
+            ex = Executors.newCachedThreadPool((r) -> {
+                Thread t = defaultFactory.newThread(r);
+                t.setDaemon(true);
+                return t;
+            });
+        } else {
+            ex = builder.executor;
+        }
+        client2 = new Http2ClientImpl(this);
+        executor = ExecutorWrapper.wrap(ex);
+        cookieManager = builder.cookieManager;
+        followRedirects = builder.followRedirects == null ?
+                Redirect.NEVER : builder.followRedirects;
+        this.proxySelector = builder.proxy;
+        authenticator = builder.authenticator;
+        version = builder.version;
+        sslParams = builder.sslParams;
+        connections = new ConnectionPool();
+        connections.start();
+        timeouts = new LinkedList<>();
+        try {
+            selmgr = new SelectorManager();
+        } catch (IOException e) {
+            // unlikely
+            throw new InternalError(e);
+        }
+        selmgr.setDaemon(true);
+        selmgr.setName("HttpSelector");
+        filters = new FilterFactory();
+        initFilters();
+    }
+
+    private void start() {
+        selmgr.start();
+    }
+
+    /**
+     * Wait for activity on given exchange (assuming blocking = false).
+     * It's a no-op if blocking = true. In particular, the following occurs
+     * in the SelectorManager thread.
+     *
+     *  1) mark the connection non-blocking
+     *  2) add to selector
+     *  3) If selector fires for this exchange then
+     *  4)   - mark connection as blocking
+     *  5)   - call AsyncEvent.handle()
+     *
+     *  If exchange needs to block again, then call registerEvent() again
+     */
+    void registerEvent(AsyncEvent exchange) throws IOException {
+        selmgr.register(exchange);
+    }
+
+    Http2ClientImpl client2() {
+        return client2;
+    }
+
+    LinkedList<ByteBuffer> freelist = new LinkedList<>();
+
+    @Override
+    public synchronized ByteBuffer getBuffer() {
+        if (freelist.isEmpty()) {
+            return ByteBuffer.allocate(BUFSIZE);
+        }
+        return freelist.removeFirst();
+    }
+
+    @Override
+    public synchronized void returnBuffer(ByteBuffer buffer) {
+        buffer.clear();
+        freelist.add(buffer);
+    }
+
+
+    // Main loop for this client's selector
+
+    class SelectorManager extends Thread {
+
+        final Selector selector;
+        boolean closed;
+
+        final List<AsyncEvent> readyList;
+        final List<AsyncEvent> registrations;
+
+        List<AsyncEvent> debugList;
+
+        SelectorManager() throws IOException {
+            readyList = new LinkedList<>();
+            registrations = new LinkedList<>();
+            debugList = new LinkedList<>();
+            selector = Selector.open();
+        }
+
+        // This returns immediately. So caller not allowed to send/receive
+        // on connection.
+
+        synchronized void register(AsyncEvent e) throws IOException {
+            registrations.add(e);
+            selector.wakeup();
+        }
+
+        void wakeupSelector() {
+            selector.wakeup();
+        }
+
+        synchronized void shutdown() {
+            closed = true;
+            try {
+                selector.close();
+            } catch (IOException e) {}
+        }
+
+        private List<AsyncEvent> copy(List<AsyncEvent> list) {
+            LinkedList<AsyncEvent> c = new LinkedList<>();
+            for (AsyncEvent e : list) {
+                c.add(e);
+            }
+            return c;
+        }
+
+        synchronized void debugPrint() {
+            System.err.println("Selecting on:");
+            for (AsyncEvent e : debugList) {
+                System.err.println(opvals(e.interestOps()));
+            }
+        }
+
+        String opvals(int i) {
+            StringBuilder sb = new StringBuilder();
+            if ((i & OP_READ) != 0)
+                sb.append("OP_READ ");
+            if ((i & OP_CONNECT) != 0)
+                sb.append("OP_CONNECT ");
+            if ((i & OP_WRITE) != 0)
+                sb.append("OP_WRITE ");
+            return sb.toString();
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    synchronized (this) {
+                        debugList = copy(registrations);
+                        for (AsyncEvent exchange : registrations) {
+                            SelectableChannel c = exchange.channel();
+                            try {
+                                c.configureBlocking(false);
+                                c.register(selector,
+                                           exchange.interestOps(),
+                                           exchange);
+                            } catch (IOException e) {
+                                Log.logError("HttpClientImpl: " + e);
+                                c.close();
+                                // let the exchange deal with it
+                                handleEvent(exchange);
+                            }
+                        }
+                        registrations.clear();
+                    }
+                    long timeval = getTimeoutValue();
+                    long now = System.currentTimeMillis();
+                    int n = selector.select(timeval);
+                    if (n == 0) {
+                        signalTimeouts(now);
+                        continue;
+                    }
+                    Set<SelectionKey> keys = selector.selectedKeys();
+
+                    for (SelectionKey key : keys) {
+                        if (key.isReadable() || key.isConnectable() || key.isWritable()) {
+                            key.cancel();
+                            AsyncEvent exchange = (AsyncEvent) key.attachment();
+                            readyList.add(exchange);
+                        }
+                    }
+                    selector.selectNow(); // complete cancellation
+                    selector.selectedKeys().clear();
+
+                    for (AsyncEvent exchange : readyList) {
+                        if (exchange instanceof AsyncEvent.Blocking) {
+                            exchange.channel().configureBlocking(true);
+                        } else {
+                            assert exchange instanceof AsyncEvent.NonBlocking;
+                        }
+                        executor.synchronize();
+                        handleEvent(exchange); // will be delegated to executor
+                    }
+                    readyList.clear();
+                }
+            } catch (Throwable e) {
+                if (!closed) {
+                    System.err.println("HttpClientImpl terminating on error");
+                    // This terminates thread. So, better just print stack trace
+                    String err = Utils.stackTrace(e);
+                    Log.logError("HttpClientImpl: fatal error: " + err);
+                }
+            }
+        }
+
+        void handleEvent(AsyncEvent e) {
+            if (closed) {
+                e.abort();
+            } else {
+                e.handle();
+            }
+        }
+    }
+
+    /**
+     * Creates a HttpRequest associated with this group.
+     *
+     * @throws IllegalStateException if the group has been stopped
+     */
+    @Override
+    public HttpRequestBuilderImpl request() {
+        return new HttpRequestBuilderImpl(this, null);
+    }
+
+    /**
+     * Creates a HttpRequest associated with this group.
+     *
+     * @throws IllegalStateException if the group has been stopped
+     */
+    @Override
+    public HttpRequestBuilderImpl request(URI uri) {
+        return new HttpRequestBuilderImpl(this, uri);
+    }
+
+    @Override
+    public SSLContext sslContext() {
+        Utils.checkNetPermission("getSSLContext");
+        return sslContext;
+    }
+
+    @Override
+    public Optional<SSLParameters> sslParameters() {
+        return Optional.ofNullable(sslParams);
+    }
+
+    @Override
+    public Optional<Authenticator> authenticator() {
+        return Optional.ofNullable(authenticator);
+    }
+
+    @Override
+    public ExecutorService executorService() {
+        return executor.userExecutor();
+    }
+
+    ExecutorWrapper executorWrapper() {
+        return executor;
+    }
+
+    @Override
+    public boolean pipelining() {
+        return this.pipelining;
+    }
+
+    ConnectionPool connectionPool() {
+        return connections;
+    }
+
+    @Override
+    public Redirect followRedirects() {
+        return followRedirects;
+    }
+
+
+    @Override
+    public Optional<CookieManager> cookieManager() {
+        return Optional.ofNullable(cookieManager);
+    }
+
+    @Override
+    public Optional<ProxySelector> proxy() {
+        return Optional.ofNullable(this.proxySelector);
+    }
+
+    @Override
+    public Version version() {
+        return version;
+    }
+
+    //private final HashMap<String, Boolean> http2NotSupported = new HashMap<>();
+
+    boolean getHttp2Allowed() {
+        return version.equals(Version.HTTP_2);
+    }
+
+    //void setHttp2NotSupported(String host) {
+        //http2NotSupported.put(host, false);
+    //}
+
+    final void initFilters() {
+        addFilter(AuthenticationFilter.class);
+        addFilter(RedirectFilter.class);
+    }
+
+    final void addFilter(Class<? extends HeaderFilter> f) {
+        filters.addFilter(f);
+    }
+
+    final List<HeaderFilter> filterChain() {
+        return filters.getFilterChain();
+    }
+
+    // Timer controls. Timers are implemented through timed Selector.select()
+    // calls.
+    synchronized void registerTimer(TimeoutEvent event) {
+        long elapse = event.timevalMillis();
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        long listval = 0;
+        event.delta = event.timeval; // in case list empty
+        TimeoutEvent next;
+        while (iter.hasNext()) {
+            next = iter.next();
+            listval += next.delta;
+            if (elapse < listval) {
+                listval -= next.delta;
+                event.delta = elapse - listval;
+                next.delta -= event.delta;
+                iter.previous();
+                break;
+            } else if (!iter.hasNext()) {
+                event.delta = event.timeval - listval ;
+            }
+        }
+        iter.add(event);
+        //debugPrintList("register");
+        selmgr.wakeupSelector();
+    }
+
+    void debugPrintList(String s) {
+        System.err.printf("%s: {", s);
+        for (TimeoutEvent e : timeouts) {
+            System.err.printf("(%d,%d) ", e.delta, e.timeval);
+        }
+        System.err.println("}");
+    }
+
+    synchronized void signalTimeouts(long then) {
+        if (timeouts.isEmpty()) {
+            return;
+        }
+        long now = System.currentTimeMillis();
+        long duration = now - then;
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        TimeoutEvent event = iter.next();
+        long delta = event.delta;
+        if (duration < delta) {
+            event.delta -= duration;
+            return;
+        }
+        event.handle();
+        iter.remove();
+        while (iter.hasNext()) {
+            event = iter.next();
+            if (event.delta == 0) {
+                event.handle();
+                iter.remove();
+            } else {
+                event.delta += delta;
+                break;
+            }
+        }
+        //debugPrintList("signalTimeouts");
+    }
+
+    synchronized void cancelTimer(TimeoutEvent event) {
+        ListIterator<TimeoutEvent> iter = timeouts.listIterator();
+        while (iter.hasNext()) {
+            TimeoutEvent ev = iter.next();
+            if (event == ev) {
+                if (iter.hasNext()) {
+                    // adjust
+                    TimeoutEvent next = iter.next();
+                    next.delta += ev.delta;
+                    iter.previous();
+                }
+                iter.remove();
+            }
+        }
+    }
+
+    // used for the connection window
+    int getReceiveBufferSize() {
+        return Utils.getIntegerNetProperty(
+                "sun.net.httpclient.connectionWindowSize", 256 * 1024
+        );
+    }
+
+    // returns 0 meaning block forever, or a number of millis to block for
+    synchronized long getTimeoutValue() {
+        if (timeouts.isEmpty()) {
+            return 0;
+        } else {
+            return timeouts.get(0).delta;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Wraps socket channel layer and takes care of SSL also.
+ *
+ * Subtypes are:
+ *      PlainHttpConnection: regular direct TCP connection to server
+ *      PlainProxyConnection: plain text proxy connection
+ *      PlainTunnelingConnection: opens plain text (CONNECT) tunnel to server
+ *      SSLConnection: TLS channel direct to server
+ *      SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel
+ */
+abstract class HttpConnection implements BufferHandler {
+
+    // address we are connected to. Could be a server or a proxy
+    final InetSocketAddress address;
+    final HttpClientImpl client;
+    protected volatile ByteBuffer buffer;
+
+    HttpConnection(InetSocketAddress address, HttpClientImpl client) {
+        this.address = address;
+        this.client = client;
+    }
+
+    /**
+     * Public API to this class. addr is the ultimate destination. Any proxies
+     * etc are figured out from the request. Returns an instance of one of the
+     * following
+     *      PlainHttpConnection
+     *      PlainTunnelingConnection
+     *      SSLConnection
+     *      SSLTunnelConnection
+     *
+     * When object returned, connect() or connectAsync() must be called, which
+     * when it returns/completes, the connection is usable for requests.
+     */
+    public static HttpConnection getConnection(InetSocketAddress addr,
+                                               HttpRequestImpl request) {
+        return getConnectionImpl(addr, request);
+    }
+
+    public abstract void connect() throws IOException, InterruptedException;
+
+    public abstract CompletableFuture<Void> connectAsync();
+
+    /**
+     * Returns whether this connection is connected to its destination
+     */
+    abstract boolean connected();
+
+    abstract boolean isSecure();
+
+    abstract boolean isProxied();
+
+    /**
+     * Completes when the first byte of the response is available to be read.
+     */
+    abstract CompletableFuture<Void> whenReceivingResponse();
+
+    // must be called before reading any data off connection
+    // at beginning of response.
+    ByteBuffer getRemaining() {
+        ByteBuffer b = buffer;
+        buffer = null;
+        return b;
+    }
+
+    final boolean isOpen() {
+        return channel().isOpen();
+    }
+
+    /* Returns either a plain HTTP connection or a plain tunnelling connection
+     * for proxied websockets */
+    private static HttpConnection getPlainConnection(InetSocketAddress addr,
+                                                     InetSocketAddress proxy,
+                                                     HttpRequestImpl request) {
+        HttpClientImpl client = request.client();
+
+        if (request.isWebSocket() && proxy != null) {
+            return new PlainTunnelingConnection(addr,
+                                                proxy,
+                                                client,
+                                                request.getAccessControlContext());
+        } else {
+            if (proxy == null) {
+                return new PlainHttpConnection(addr, client);
+            } else {
+                return new PlainProxyConnection(proxy, client);
+            }
+        }
+    }
+
+    private static HttpConnection getSSLConnection(InetSocketAddress addr,
+                                                   InetSocketAddress proxy,
+                                                   HttpRequestImpl request,
+                                                   String[] alpn) {
+        HttpClientImpl client = request.client();
+        if (proxy != null) {
+            return new SSLTunnelConnection(addr,
+                                           client,
+                                           proxy,
+                                           request.getAccessControlContext());
+        } else {
+            return new SSLConnection(addr, client, alpn);
+        }
+    }
+
+    /**
+     * Main factory method.   Gets a HttpConnection, either cached or new if
+     * none available.
+     */
+    private static HttpConnection getConnectionImpl(InetSocketAddress addr,
+                                                    HttpRequestImpl request) {
+        HttpConnection c;
+        HttpClientImpl client = request.client();
+        InetSocketAddress proxy = request.proxy();
+        boolean secure = request.secure();
+        ConnectionPool pool = client.connectionPool();
+        String[] alpn =  null;
+
+        if (secure && request.requestHttp2()) {
+            alpn = new String[1];
+            alpn[0] = "h2";
+        }
+
+        if (!secure) {
+            c = pool.getConnection(false, addr, proxy);
+            if (c != null) {
+                return c;
+            } else {
+                return getPlainConnection(addr, proxy, request);
+            }
+        } else {
+            c = pool.getConnection(true, addr, proxy);
+            if (c != null) {
+                return c;
+            } else {
+                return getSSLConnection(addr, proxy, request, alpn);
+            }
+        }
+    }
+
+    void returnToCache(HttpHeaders hdrs) {
+        if (hdrs == null) {
+            // the connection was closed by server
+            close();
+            return;
+        }
+        if (!isOpen()) {
+            return;
+        }
+        ConnectionPool pool = client.connectionPool();
+        boolean keepAlive = hdrs.firstValue("Connection")
+                .map((s) -> !s.equalsIgnoreCase("close"))
+                .orElse(true);
+
+        if (keepAlive) {
+            pool.returnToPool(this);
+        } else {
+            close();
+        }
+    }
+
+    /**
+     * Also check that the number of bytes written is what was expected. This
+     * could be different if the buffer is user-supplied and its internal
+     * pointers were manipulated in a race condition.
+     */
+    final void checkWrite(long expected, ByteBuffer buffer) throws IOException {
+        long written = write(buffer);
+        if (written != expected) {
+            throw new IOException("incorrect number of bytes written");
+        }
+    }
+
+    final void checkWrite(long expected,
+                          ByteBuffer[] buffers,
+                          int start,
+                          int length)
+        throws IOException
+    {
+        long written = write(buffers, start, length);
+        if (written != expected) {
+            throw new IOException("incorrect number of bytes written");
+        }
+    }
+
+    abstract SocketChannel channel();
+
+    final InetSocketAddress address() {
+        return address;
+    }
+
+    void configureBlocking(boolean mode) throws IOException {
+        channel().configureBlocking(mode);
+    }
+
+    abstract ConnectionPool.CacheKey cacheKey();
+
+    /*
+    static PrintStream ps;
+
+    static {
+        try {
+            String propval = Utils.getNetProperty("java.net.httpclient.showData");
+            if (propval != null && propval.equalsIgnoreCase("true")) {
+                ps = new PrintStream(new FileOutputStream("/tmp/httplog.txt"), false);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    synchronized final void debugPrint(String s, ByteBuffer b) {
+        ByteBuffer[] bufs = new ByteBuffer[1];
+        bufs[0] = b;
+        debugPrint(s, bufs, 0, 1);
+    }
+
+    synchronized final void debugPrint(String s,
+                                       ByteBuffer[] bufs,
+                                       int start,
+                                       int number) {
+        if (ps == null) {
+            return;
+        }
+
+        ps.printf("\n%s:\n", s);
+
+        for (int i=start; i<start+number; i++) {
+            ByteBuffer b = bufs[i].duplicate();
+            while (b.hasRemaining()) {
+                int c = b.get();
+                if (c == 10) {
+                    ps.printf("LF \n");
+                } else if (c == 13) {
+                    ps.printf(" CR ");
+                } else if (c == 0x20) {
+                    ps.printf("_");
+                } else if (c > 0x20 && c <= 0x7F) {
+                    ps.printf("%c", (char)c);
+                } else {
+                    ps.printf("0x%02x ", c);
+                }
+            }
+        }
+        ps.printf("\n---------------------\n");
+    }
+
+    */
+
+    // overridden in SSL only
+    SSLParameters sslParameters() {
+        return null;
+    }
+
+    // Methods to be implemented for Plain TCP and SSL
+
+    abstract long write(ByteBuffer[] buffers, int start, int number)
+        throws IOException;
+
+    abstract long write(ByteBuffer buffer) throws IOException;
+
+    /**
+     * Closes this connection, by returning the socket to its connection pool.
+     */
+    abstract void close();
+
+    /**
+     * Returns a ByteBuffer with data, or null if EOF.
+     */
+    final ByteBuffer read() throws IOException {
+        return read(-1);
+    }
+
+    /**
+     * Puts position to limit and limit to capacity so we can resume reading
+     * into this buffer, but if required > 0 then limit may be reduced so that
+     * no more than required bytes are read next time.
+     */
+    static void resumeChannelRead(ByteBuffer buf, int required) {
+        int limit = buf.limit();
+        buf.position(limit);
+        int capacity = buf.capacity() - limit;
+        if (required > 0 && required < capacity) {
+            buf.limit(limit + required);
+        } else {
+            buf.limit(buf.capacity());
+        }
+    }
+
+    /**
+     * Blocks ands return requested amount.
+     */
+    final ByteBuffer read(int length) throws IOException {
+        if (length <= 0) {
+            buffer = readImpl(length);
+            return buffer;
+        }
+        buffer = readImpl(length);
+        int required = length - buffer.remaining();
+        while (buffer.remaining() < length) {
+            resumeChannelRead(buffer, required);
+            int n = readImpl(buffer);
+            required -= n;
+        }
+        return buffer;
+    }
+
+    final int read(ByteBuffer buffer) throws IOException {
+        int n = readImpl(buffer);
+        return n;
+    }
+
+    /** Reads up to length bytes. */
+    protected abstract ByteBuffer readImpl(int length) throws IOException;
+
+    /** Reads as much as possible into given buffer and returns amount read. */
+    protected abstract int readImpl(ByteBuffer buffer) throws IOException;
+
+    @Override
+    public String toString() {
+        return "HttpConnection: " + channel().toString();
+    }
+
+    @Override
+    public final ByteBuffer getBuffer() {
+        return client.getBuffer();
+    }
+
+    @Override
+    public final void returnBuffer(ByteBuffer buffer) {
+        client.returnBuffer(buffer);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeaders.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A read-only view of a set of received HTTP headers.
+ *
+ * @since 9
+ */
+public interface HttpHeaders {
+
+    /**
+     * Returns an {@link java.util.Optional} containing the first value of the
+     * given named (and possibly multi-valued) header. If the header is not
+     * present, then the returned {@code Optional} is empty.
+     *
+     * @param name the header name
+     * @return an {@code Optional<String>} for the first named value
+     */
+    public Optional<String> firstValue(String name);
+
+    /**
+     * Returns an {@link java.util.Optional} containing the first value of the
+     * named header field as an {@literal Optional<Long>}. If the header is not
+     * present, then the Optional is empty. If the header is present but
+     * contains a value that does not parse as a {@code Long} value, then an
+     * exception is thrown.
+     *
+     * @param name the header name
+     * @return  an {@code Optional<Long>}
+     * @throws NumberFormatException if a value is found, but does not parse as
+     *                               a Long
+     */
+    public Optional<Long> firstValueAsLong(String name);
+
+    /**
+     * Returns an unmodifiable List of all of the values of the given named
+     * header. Always returns a List, which may be empty if the header is not
+     * present.
+     *
+     * @param name the header name
+     * @return a List of String values
+     */
+    public List<String> allValues(String name);
+
+    /**
+     * Returns an unmodifiable multi Map view of this HttpHeaders. This
+     * interface should only be used when it is required to iterate over the
+     * entire set of headers.
+     *
+     * @return the Map
+     */
+    public Map<String,List<String>> map();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeaders1.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+public interface HttpHeaders1 extends HttpHeaders {
+    public void makeUnmodifiable();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Implementation of HttpHeaders.
+ */
+class HttpHeadersImpl implements HttpHeaders1 {
+
+    private final HashMap<String,List<String>> headers;
+    private boolean isUnmodifiable = false;
+
+    public HttpHeadersImpl() {
+        headers = new HashMap<>();
+    }
+
+    /**
+     * Replace all List<String> in headers with unmodifiable Lists. Call
+     * this only after all headers are added. The headers HashMap
+     * is wrapped with an unmodifiable HashMap in map()
+     */
+    @Override
+    public void makeUnmodifiable() {
+        if (isUnmodifiable)
+            return;
+
+        Set<String> keys = new HashSet<>(headers.keySet());
+        for (String key : keys) {
+            List<String> values = headers.remove(key);
+            if (values != null) {
+                headers.put(key, Collections.unmodifiableList(values));
+            }
+        }
+        isUnmodifiable = true;
+    }
+
+    @Override
+    public Optional<String> firstValue(String name) {
+        List<String> l = headers.get(name);
+        return Optional.ofNullable(l == null ? null : l.get(0));
+    }
+
+    @Override
+    public List<String> allValues(String name) {
+        return headers.get(name);
+    }
+
+    @Override
+    public Map<String, List<String>> map() {
+        return Collections.unmodifiableMap(headers);
+    }
+
+    Map<String, List<String>> directMap() {
+        return headers;
+    }
+
+    // package private mutators
+
+    public HttpHeadersImpl deepCopy() {
+        HttpHeadersImpl h1 = new HttpHeadersImpl();
+        HashMap<String,List<String>> headers1 = h1.headers;
+        Set<String> keys = headers.keySet();
+        for (String key : keys) {
+            List<String> vals = headers.get(key);
+            LinkedList<String> vals1 = new LinkedList<>(vals);
+            headers1.put(key, vals1);
+        }
+        return h1;
+    }
+
+    private List<String> getOrCreate(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = new LinkedList<>();
+            headers.put(name, l);
+        }
+        return l;
+    }
+
+    void addHeader(String name, String value) {
+        List<String> l = getOrCreate(name);
+        l.add(value);
+    }
+
+    void setHeader(String name, String value) {
+        List<String> l = getOrCreate(name);
+        l.clear();
+        l.add(value);
+    }
+
+    @Override
+    public Optional<Long> firstValueAsLong(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            return Optional.ofNullable(null);
+        } else {
+            String v = l.get(0);
+            Long lv = Long.parseLong(v);
+            return Optional.of(lv);
+        }
+    }
+
+    void clear() {
+        headers.clear();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRedirectImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.net.*;
+
+interface HttpRedirectImpl {
+
+    static HttpRedirectImpl getRedirects(java.net.http.HttpClient.Redirect redir) {
+        switch (redir) {
+            case NEVER:
+                return HttpRedirectImpl.NEVER;
+            case ALWAYS:
+                return HttpRedirectImpl.ALWAYS;
+            case SECURE:
+                return HttpRedirectImpl.SECURE;
+            case SAME_PROTOCOL:
+                return HttpRedirectImpl.SAME_PROTOCOL;
+        }
+        return HttpRedirectImpl.NEVER;
+    }
+
+    static HttpClient.Redirect getRedirects(HttpRedirectImpl redir) {
+        if (redir == HttpRedirectImpl.NEVER) {
+            return HttpClient.Redirect.NEVER;
+        } else if (redir == HttpRedirectImpl.ALWAYS) {
+            return HttpClient.Redirect.ALWAYS;
+        } else if (redir == HttpRedirectImpl.SECURE) {
+            return HttpClient.Redirect.SECURE;
+        } else {
+            return HttpClient.Redirect.SAME_PROTOCOL;
+        }
+    }
+
+    /**
+     * Called to determine whether the given intermediate response
+     * with a redirection response code should be redirected. The target URI
+     * can be obtained from the "Location" header in the given response object.
+     *
+     * @param rsp the response from the redirected resource
+     * @return {@code true} if the redirect should be attempted automatically
+     * or {@code false} if not.
+     */
+    boolean redirect(HttpResponse rsp);
+
+    /**
+     * Never redirect.
+     */
+    static HttpRedirectImpl NEVER = (HttpResponse rsp) -> false;
+
+    /**
+     * Always redirect.
+     */
+    static HttpRedirectImpl ALWAYS = (HttpResponse rsp) -> true;
+
+    /**
+     * Redirect to same protocol only. Redirection may occur from HTTP URLs to
+     * other THHP URLs and from HTTPS URLs to other HTTPS URLs.
+     */
+    static HttpRedirectImpl SAME_PROTOCOL = (HttpResponse rsp) -> {
+        String orig = rsp.request().uri().getScheme().toLowerCase();
+        String redirect = URI.create(
+                rsp.headers().firstValue("Location").orElse(""))
+                .getScheme().toLowerCase();
+        return orig.equals(redirect);
+    };
+
+    /**
+     * Redirect always except from HTTPS URLs to HTTP URLs.
+     */
+    static HttpRedirectImpl SECURE = (HttpResponse rsp) -> {
+        String orig = rsp.request().uri().getScheme().toLowerCase();
+        String redirect = URI.create(
+                rsp.headers().firstValue("Location").orElse(""))
+                .getScheme().toLowerCase();
+        if (orig.equals("https")) {
+            return redirect.equals("https");
+        }
+        return true;
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.ProxySelector;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.*;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.LongConsumer;
+
+/**
+ * Represents one HTTP request which can be sent to a server. {@code
+ * HttpRequest}s are built from {@code HttpRequest} {@link HttpRequest.Builder
+ * builder}s. {@code HttpRequest} builders are obtained from a {@link HttpClient}
+ * by calling {@link HttpClient#request(java.net.URI) HttpClient.request}, or
+ * by calling {@link #create(java.net.URI) HttpRequest.create} which returns a
+ * builder on the <a href="HttpClient.html#defaultclient">default</a> client.
+ * A request's {@link java.net.URI}, headers and body can be set. Request bodies
+ * are provided through a {@link BodyProcessor} object. Once all required
+ * parameters have been set in the builder, one of the builder methods should be
+ * called, which sets the request method and returns a {@code HttpRequest}.
+ * These methods are {@link Builder#GET() GET}, {@link HttpRequest.Builder#POST()
+ * POST} and {@link HttpRequest.Builder#PUT() PUT} which return a GET, POST or
+ * PUT request respectively. Alternatively, {@link
+ * HttpRequest.Builder#method(String) method} can be called to set an arbitrary
+ * method type (and return a {@code HttpRequest}). Builders can also be copied
+ * and modified multiple times in order to build multiple related requests that
+ * differ in some parameters.
+ *
+ * <p> Two simple, example HTTP interactions are shown below:
+ * <pre>
+ * {@code
+ *      // GET
+ *      HttpResponse response = HttpRequest
+ *          .create(new URI("http://www.foo.com"))
+ *          .headers("Foo", "foovalue", "Bar", "barvalue")
+ *          .GET()
+ *          .response();
+ *
+ *      int statusCode = response.statusCode();
+ *      String responseBody = response.body(asString());
+ *
+ *      // POST
+ *      response = HttpRequest
+ *          .create(new URI("http://www.foo.com"))
+ *          .body(fromString("param1=foo,param2=bar"))
+ *          .POST()
+ *          .response();}
+ * </pre>
+ *
+ * <p> The request is sent and the response obtained by calling one of the
+ * following methods.
+ * <ul><li>{@link #response() response} blocks until the entire request has been
+ * sent and the response status code and headers have been received.</li>
+ * <li>{@link #responseAsync() responseAsync} sends the request and receives the
+ * response asynchronously. Returns immediately with a
+ * {@link java.util.concurrent.CompletableFuture CompletableFuture}&lt;{@link
+ * HttpResponse}&gt;.</li>
+ * <li>{@link #multiResponseAsync(HttpResponse.MultiProcessor) multiResponseAsync}
+ * sends the request asynchronously, expecting multiple responses. This
+ * capability is of most relevance to HTTP/2 server push, but can be used for
+ * single responses (HTTP/1.1 or HTTP/2) also.</li>
+ * </ul>
+ *
+ * <p> Once a request has been sent, it is an error to try and send it again.
+ *
+ * <p> Once a {@code HttpResponse} is received, the headers and response code are
+ * available. The body can then be received by calling one of the body methods
+ * on {@code HttpResponse}.
+ *
+ * <p> See below for discussion of synchronous versus asynchronous usage.
+ *
+ * <p> <b>Request bodies</b>
+ *
+ * <p> Request bodies are sent using one of the request processor implementations
+ * below provided in {@code HttpRequest}, or else a custom implementation can be
+ * used.
+ * <ul>
+ * <li>{@link #fromByteArray(byte[]) } from byte array</li>
+ * <li>{@link #fromByteArrays(java.util.Iterator) fromByteArrays(Iterator)}
+ *      from an iterator of byte arrays</li>
+ * <li>{@link #fromFile(java.nio.file.Path) fromFile(Path)} from the file located
+ *     at the given Path</li>
+ * <li>{@link #fromString(java.lang.String) fromString(String)} from a String </li>
+ * <li>{@link #fromInputStream(java.io.InputStream) fromInputStream(InputStream)}
+ *      request body from InputStream</li>
+ * <li>{@link #noBody() } no request body is sent</li>
+ * </ul>
+ *
+ * <p> <b>Response bodies</b>
+ *
+ * <p> Responses bodies are handled by the {@link HttpResponse.BodyProcessor}
+ * {@code <T>} supplied to the {@link HttpResponse#body(HttpResponse.BodyProcessor)
+ * HttpResponse.body} and {@link HttpResponse#bodyAsync(HttpResponse.BodyProcessor)
+ * HttpResponse.bodyAsync} methods. Some implementations of {@code
+ * HttpResponse.BodyProcessor} are provided in {@link HttpResponse}:
+ * <ul>
+ * <li>{@link HttpResponse#asByteArray() } stores the body in a byte array</li>
+ * <li>{@link HttpResponse#asString()} stores the body as a String </li>
+ * <li>{@link HttpResponse#asFile(java.nio.file.Path) } stores the body in a
+ * named file</li>
+ * <li>{@link HttpResponse#ignoreBody() } ignores any received response body</li>
+ * </ul>
+ *
+ * <p> The output of a response processor is the response body, and its
+ * parameterized type {@code T} determines the type of the body object returned
+ * from {@code HttpResponse.body} and {@code HttpResponse.bodyAsync}. Therefore,
+ * as an example, the second response processor in the list above has the type
+ * {@code HttpResponse.BodyProcessor<String>} which means the type returned by
+ * {@code HttpResponse.body()} is a String. Response processors can be defined
+ * to return potentially any type as body.
+ *
+ * <p> <b>Multi responses</b>
+ *
+ * <p> With HTTP/2 it is possible for a server to return a main response and zero
+ * or more additional responses (known as server pushes) to a client-initiated
+ * request. These are handled using a special response processor called {@link
+ * HttpResponse.MultiProcessor}.
+ *
+ * <p> <b>Blocking/asynchronous behavior and thread usage</b>
+ *
+ * <p> There are two styles of request sending: <i>synchronous</i> and
+ * <i>asynchronous</i>. {@link #response() response} blocks the calling thread
+ * until the request has been sent and the response received.
+ *
+ * <p> {@link #responseAsync() responseAsync} is asynchronous and returns
+ * immediately with a {@link java.util.concurrent.CompletableFuture}&lt;{@link
+ * HttpResponse}&gt; and when this object completes (in a background thread) the
+ * response has been received.
+ *
+ * <p> {@link #multiResponseAsync(HttpResponse.MultiProcessor) multiResponseAsync}
+ * is the variant for multi responses and is also asynchronous.
+ *
+ * <p> CompletableFutures can be combined in different ways to declare the
+ * dependencies among several asynchronous tasks, while allowing for the maximum
+ * level of parallelism to be utilized.
+ *
+ * <p> <b>Security checks</b>
+ *
+ * <p> If a security manager is present then security checks are performed by
+ * the {@link #response() } and {@link #responseAsync() } methods. A {@link
+ * java.net.URLPermission} or {@link java.net.SocketPermission} is required to
+ * access any destination origin server and proxy server utilised. URLPermissions
+ * should be preferred in policy files over SocketPermissions given the more
+ * limited scope of URLPermission. Permission is always implicitly granted to a
+ * system's default proxies. The URLPermission form used to access proxies uses
+ * a method parameter of "CONNECT" (for all kinds of proxying) and a url string
+ * of the form "socket://host:port" where host and port specify the proxy's
+ * address.
+ *
+ * <p> <b>Examples</b>
+ * <pre>
+ *     import static java.net.http.HttpRequest.*;
+ *     import static java.net.http.HttpResponse.*;
+ *
+ *     //Simple blocking
+ *
+ *     HttpResponse r1 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .GET()
+ *                                 .response();
+ *     int responseCode = r1.statusCode());
+ *     String body = r1.body(asString());
+ *
+ *     HttpResponse r2 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .GET()
+ *                                  .response();
+ *
+ *     System.out.println("Response was " + r1.statusCode());
+ *     Path body1 = r2.body(asFile(Paths.get("/tmp/response.txt")));
+ *     // Content stored in /tmp/response.txt
+ *
+ *     HttpResponse r3 = HttpRequest.create(new URI("http://www.foo.com/"))
+ *                                  .body(fromString("param1=1, param2=2"))
+ *                                  .POST()
+ *                                  .response();
+ *
+ *     Void body2 = r3.body(ignoreBody()); // body is Void in this case
+ * </pre>
+ *
+ * <p><b>Asynchronous Example</b>
+ *
+ * <p> All of the above examples will work asynchronously, if {@link
+ * #responseAsync()} is used instead of {@link #response()} in which case the
+ * returned object is a {@code CompletableFuture<HttpResponse>} instead of
+ * {@code HttpResponse}. The following example shows how multiple requests can
+ * be sent asynchronously. It also shows how dependent asynchronous operations
+ * (receiving response, and receiving response body) can be chained easily using
+ * one of the many methods in {@code CompletableFuture}.
+ * <pre>
+ * {@code
+ *      // fetch a list of target URIs asynchronously and store them in Files.
+ *
+ *      List<URI> targets = ...
+ *
+ *      List<CompletableFuture<File>> futures = targets
+ *          .stream()
+ *          .map(target -> {
+ *              return HttpRequest
+ *                  .create(target)
+ *                  .GET()
+ *                  .responseAsync()
+ *                  .thenCompose(response -> {
+ *                      Path dest = Paths.get("base", target.getPath());
+ *                      if (response.statusCode() == 200) {
+ *                          return response.bodyAsync(asFile(dest));
+ *                      } else {
+ *                          return CompletableFuture.completedFuture(dest);
+ *                      }
+ *                  })
+ *                  // convert Path -> File
+ *                  .thenApply((Path dest) -> {
+ *                      return dest.toFile();
+ *                  });
+ *              })
+ *          .collect(Collectors.toList());
+ *
+ *      // all async operations waited for here
+ *
+ *      CompletableFuture.allOf(futures.toArray(new CompletableFuture<?>[0]))
+ *          .join();
+ *
+ *      // all elements of futures have completed and can be examined.
+ *      // Use File.exists() to check whether file was successfully downloaded
+ * }
+ * </pre>
+ *
+ * @since 9
+ */
+public abstract class HttpRequest {
+
+    HttpRequest() {}
+
+    /**
+     * A builder of {@link HttpRequest}s. {@code HttpRequest.Builder}s are
+     * created by calling {@link HttpRequest#create(URI)} or {@link
+     * HttpClient#request(URI)}.
+     *
+     * <p> Each of the setter methods in this class modifies the state of the
+     * builder and returns <i>this</i> (ie. the same instance). The methods are
+     * not synchronized and should not be called from multiple threads without
+     * external synchronization.
+     *
+     * <p> The build methods return a new {@code HttpRequest} each time they are
+     * called.
+     *
+     * @since 9
+     */
+    public abstract static class Builder {
+
+        Builder() {}
+
+        /**
+         * Sets this HttpRequest's request URI.
+         *
+         * @param uri the request URI
+         * @return this request builder
+         */
+        public abstract Builder uri(URI uri);
+
+        /**
+         * Specifies whether this request will automatically follow redirects
+         * issued by the server. The default value for this setting is the value
+         * of {@link HttpClient#followRedirects() }
+         *
+         * @param policy the redirection policy
+         * @return this request builder
+         */
+        public abstract Builder followRedirects(HttpClient.Redirect policy);
+
+        /**
+         * Request server to acknowledge request before sending request
+         * body. This is disabled by default. If enabled, the server is requested
+         * to send an error response or a 100-Continue response before the client
+         * sends the request body. This means the request processor for the
+         * request will not be invoked until this interim response is received.
+         *
+         * @param enable {@code true} if Expect continue to be sent
+         * @return this request builder
+         */
+        public abstract Builder expectContinue(boolean enable);
+
+        /**
+         * Overrides the {@link HttpClient#version()  } setting for this
+         * request.
+         *
+         * @param version the HTTP protocol version requested
+         * @return this request builder
+         */
+        public abstract Builder version(HttpClient.Version version);
+
+        /**
+         * Adds the given name value pair to the set of headers for this request.
+         *
+         * @param name the header name
+         * @param value the header value
+         * @return this request builder
+         */
+        public abstract Builder header(String name, String value);
+
+        /**
+         * Overrides the ProxySelector set on the request's client for this
+         * request.
+         *
+         * @param proxy the ProxySelector to use
+         * @return this request builder
+         */
+        public abstract Builder proxy(ProxySelector proxy);
+
+        /**
+         * Adds the given name value pairs to the set of headers for this
+         * request. The supplied Strings must alternate as names and values.
+         *
+         * @param headers the list of String name value pairs
+         * @return this request builder
+         * @throws IllegalArgumentException if there is an odd number of
+         *                                  parameters
+         */
+        public abstract Builder headers(String... headers);
+
+        /**
+         * Sets a timeout for this request. If the response is not received
+         * within the specified timeout then a {@link HttpTimeoutException} is
+         * thrown from {@link #response() } or {@link #responseAsync() }
+         * completes exceptionally with a {@code HttpTimeoutException}.
+         *
+         * @param unit the timeout units
+         * @param timeval the number of units to wait for
+         * @return this request builder
+         */
+        public abstract Builder timeout(TimeUnit unit, long timeval);
+
+        /**
+         * Sets the given name value pair to the set of headers for this
+         * request. This overwrites any previously set values for name.
+         *
+         * @param name the header name
+         * @param value the header value
+         * @return this request builder
+         */
+        public abstract Builder setHeader(String name, String value);
+
+        /**
+         * Sets a request body for this builder. See {@link HttpRequest}
+         * for example {@code BodyProcessor} implementations.
+         * If no body is specified, then no body is sent with the request.
+         *
+         * @param reqproc the request body processor
+         * @return this request builder
+         */
+        public abstract Builder body(BodyProcessor reqproc);
+
+        /**
+         * Builds and returns a GET {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest GET();
+
+        /**
+         * Builds and returns a POST {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest POST();
+
+        /**
+         * Builds and returns a PUT {@link HttpRequest} from this builder.
+         *
+         * @return a {@code HttpRequest}
+         */
+        public abstract HttpRequest PUT();
+
+        /**
+         * Builds and returns a {@link HttpRequest} from this builder using
+         * the given method String. The method string is case-sensitive, and
+         * may be rejected if an upper-case string is not used.
+         *
+         * @param method the method to use
+         * @return a {@code HttpRequest}
+         * @throws IllegalArgumentException if an unrecognised method is used
+         */
+        public abstract HttpRequest method(String method);
+
+        /**
+         * Returns an exact duplicate copy of this Builder based on current
+         * state. The new builder can then be modified independently of this
+         * builder.
+         *
+         * @return an exact copy of this Builder
+         */
+        public abstract Builder copy();
+    }
+
+    /**
+     * Creates a HttpRequest builder from the <i>default</i> HttpClient.
+     *
+     * @param uri the request URI
+     * @return a new request builder
+     */
+    public static HttpRequest.Builder create(URI uri) {
+        return HttpClient.getDefault().request(uri);
+    }
+
+    /**
+     * Returns the follow-redirects setting for this request.
+     *
+     * @return follow redirects setting
+     */
+    public abstract HttpClient.Redirect followRedirects();
+
+    /**
+     * Returns the response to this request, by sending it and blocking if
+     * necessary to get the response. The {@link HttpResponse} contains the
+     * response status and headers.
+     *
+     * @return a HttpResponse for this request
+     * @throws IOException if an I/O error occurs
+     * @throws InterruptedException if the operation was interrupted
+     * @throws SecurityException if the caller does not have the required
+     *                           permission
+     * @throws IllegalStateException if called more than once or if
+     *                               responseAsync() called previously
+     */
+    public abstract HttpResponse response()
+        throws IOException, InterruptedException;
+
+    /**
+     * Sends the request and returns the response asynchronously. This method
+     * returns immediately with a {@link CompletableFuture}&lt;{@link
+     * HttpResponse}&gt;
+     *
+     * @return a {@code CompletableFuture<HttpResponse>}
+     * @throws IllegalStateException if called more than once or if response()
+     *                               called previously.
+     */
+    public abstract CompletableFuture<HttpResponse> responseAsync();
+
+    /**
+     * Sends the request asynchronously expecting multiple responses.
+     *
+     * <p> This method must be given a {@link HttpResponse.MultiProcessor} to
+     * handle the multiple responses.
+     *
+     * <p> If a security manager is set, the caller must possess a {@link
+     * java.net.URLPermission} for the request's URI, method and any user set
+     * headers. The security manager is also checked for each incoming
+     * additional server generated request/response. Any request that fails the
+     * security check, is canceled and ignored.
+     *
+     * <p> This method can be used for both HTTP/1.1 and HTTP/2, but in cases
+     * where multiple responses are not supported, the MultiProcessor
+     * only receives the main response.
+     *
+     * <p> The aggregate {@code CompletableFuture} returned from this method
+     * returns a {@code <U>} defined by the {@link HttpResponse.MultiProcessor}
+     * implementation supplied. This will typically be a Collection of
+     * HttpResponses or of some response body type.
+     *
+     * @param <U> the aggregate response type
+     * @param rspproc the MultiProcessor for the request
+     * @return a {@code CompletableFuture<U>}
+     * @throws IllegalStateException if the request has already been sent.
+     */
+    public abstract <U> CompletableFuture<U>
+    multiResponseAsync(HttpResponse.MultiProcessor<U> rspproc);
+
+    /**
+     * Returns the request method for this request. If not set explicitly,
+     * the default method for any request is "GET".
+     *
+     * @return this request's method
+     */
+    public abstract String method();
+
+    /**
+     * Returns this request's {@link HttpRequest.Builder#expectContinue(boolean)
+     * expect continue } setting.
+     *
+     * @return this request's expect continue setting
+     */
+    public abstract boolean expectContinue();
+
+    /**
+     * Returns this request's request URI.
+     *
+     * @return this request's URI
+     */
+    public abstract URI uri();
+
+    /**
+     * Returns this request's {@link HttpClient}.
+     *
+     * @return this request's HttpClient
+     */
+    public abstract HttpClient client();
+
+    /**
+     * Returns the HTTP protocol version that this request will use or used.
+     *
+     * @return HTTP protocol version
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * The (user-accessible) request headers that this request was (or will be)
+     * sent with.
+     *
+     * @return this request's HttpHeaders
+     */
+    public abstract HttpHeaders headers();
+
+    /**
+     * Returns a request processor whose body is the given String, converted
+     * using the {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1}
+     * character set.
+     *
+     * @param body the String containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromString(String body) {
+        return fromString(body, StandardCharsets.ISO_8859_1);
+    }
+
+    /**
+     * A request processor that takes data from the contents of a File.
+     *
+     * @param path the path to the file containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromFile(Path path) {
+        FileChannel fc;
+        long size;
+
+        try {
+            fc = FileChannel.open(path);
+            size = fc.size();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                // could return exact file length, but for now -1
+                this.flow = flow;
+                flow.accept(1);
+                if (size != 0) {
+                    return size;
+                } else {
+                    return -1;
+                }
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer) throws IOException {
+                int n = fc.read(buffer);
+                if (n == -1) {
+                    fc.close();
+                    return true;
+                }
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                try {
+                    fc.close();
+                } catch (IOException ex) {
+                    Log.logError(ex.toString());
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns a request processor whose body is the given String, converted
+     * using the given character set.
+     *
+     * @param s the String containing the body
+     * @param charset the character set to convert the string to bytes
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromString(String s, Charset charset) {
+        return fromByteArray(s.getBytes(charset));
+    }
+
+    /**
+     * Returns a request processor whose body is the given byte array.
+     *
+     * @param buf the byte array containing the body
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArray(byte[] buf) {
+        return fromByteArray(buf, 0, buf.length);
+    }
+
+    /**
+     * Returns a request processor whose body is the content of the given byte
+     * array length bytes starting from the specified offset.
+     *
+     * @param buf the byte array containing the body
+     * @param offset the offset of the first byte
+     * @param length the number of bytes to use
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArray(byte[] buf, int offset, int length) {
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+            byte[] barray;
+            int index;
+            int sent;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                barray = buf;
+                index = offset;
+                return length;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                if (sent == length) {
+                    return true;
+                }
+
+                int remaining = buffer.remaining();
+                int left = length - sent;
+                int n = remaining > left ? left : remaining;
+                buffer.put(barray, index, n);
+                index += n;
+                sent += n;
+                flow.accept(1);
+                return sent == length;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor that takes data from an Iterator of byte arrays.
+     *
+     * @param iter an Iterator of byte arrays
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromByteArrays(Iterator<byte[]> iter) {
+
+        return new BodyProcessor() {
+            LongConsumer flow;
+            byte[] current;
+            int curIndex;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                return -1;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                int remaining;
+
+                while ((remaining = buffer.remaining()) > 0) {
+                    if (current == null) {
+                        if (!iter.hasNext()) {
+                            return true;
+                        }
+                        current = iter.next();
+                        curIndex = 0;
+                    }
+                    int n = Math.min(remaining, current.length - curIndex);
+                    buffer.put(current, curIndex, n);
+                    curIndex += n;
+
+                    if (curIndex == current.length) {
+                        current = null;
+                        flow.accept(1);
+                        return false;
+                    }
+                }
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor that reads its data from an InputStream.
+     *
+     * @param stream an InputStream
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor fromInputStream(InputStream stream) {
+        // for now, this blocks. It could be offloaded to a separate thread
+        // to do reading and guarantee that onRequestBodyChunk() won't block
+        return new BodyProcessor() {
+            LongConsumer flow;
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                this.flow = flow;
+                flow.accept(1);
+                return -1;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                int remaining = buffer.remaining();
+                int n = stream.read(buffer.array(), buffer.arrayOffset(), remaining);
+                if (n == -1) {
+                    stream.close();
+                    return true;
+                }
+                buffer.position(buffer.position() + n);
+                flow.accept(1);
+                return false;
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor which sends no request body.
+     *
+     * @return a BodyProcessor
+     */
+    public static BodyProcessor noBody() {
+        return new BodyProcessor() {
+
+            @Override
+            public long onRequestStart(HttpRequest hr, LongConsumer flow) {
+                return 0;
+            }
+
+            @Override
+            public boolean onRequestBodyChunk(ByteBuffer buffer)
+                throws IOException
+            {
+                throw new InternalError("should never reach here");
+            }
+
+            @Override
+            public void onRequestError(Throwable t) {
+                Log.logError(t.toString());
+            }
+        };
+    }
+
+    /**
+     * A request processor which obtains the request body from some source.
+     * Implementations of this interface are provided which allow request bodies
+     * to be supplied from standard types, such as {@code String, byte[], File,
+     * InputStream}. Other implementations can be provided.
+     *
+     * <p> The methods of this interface may be called from multiple threads,
+     * but only one method is invoked at a time, and behaves as if called from
+     * one thread.
+     *
+     * <p> See {@link HttpRequest} for implementations that take request bodies
+     * from {@code byte arrays, Strings, Paths} etc.
+     *
+     * @since 9
+     */
+    public interface BodyProcessor {
+
+        /**
+         * Called before a request is sent. Is expected to return the content
+         * length of the request body. Zero means no content. Less than zero
+         * means an unknown positive content-length, and the body will be
+         * streamed.
+         *
+         * <p> The flowController object must be used to manage the flow of
+         * calls to {@link #onRequestBodyChunk(ByteBuffer)}. The typical usage
+         * for a non-blocking processor is to call it once inside
+         * onRequestStart() and once during each call to onRequestBodyChunk().
+         *
+         * @param hr the request
+         * @param flowController the HttpFlowController
+         * @return the content length
+         * @throws IOException if an I/O error occurs
+         */
+        long onRequestStart(HttpRequest hr, LongConsumer flowController)
+            throws IOException;
+
+        /**
+         * Called if sending a request body fails.
+         *
+         * @implSpec The default implementation does nothing.
+         *
+         * @param t the Throwable that caused the failure
+         */
+        default void onRequestError(Throwable t) { }
+
+        /**
+         * Called to obtain a buffer of data to send. The data must be placed
+         * in the provided buffer. The implementation should not block. The
+         * boolean return code notifies the protocol implementation if the
+         * supplied buffer is the final one (or not).
+         *
+         * @param buffer a ByteBuffer to write data into
+         * @return whether or not this is the last buffer
+         * @throws IOException if an I/O error occurs
+         */
+        boolean onRequestBodyChunk(ByteBuffer buffer) throws IOException;
+
+        /**
+         * Called when the request body has been completely sent.
+         *
+         * @implSpec The default implementation does nothing
+         */
+        default void onComplete() {
+            // TODO: need to call this
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.net.URI;
+import java.net.ProxySelector;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+class HttpRequestBuilderImpl extends HttpRequest.Builder {
+
+    private HttpHeadersImpl userHeaders;
+    private URI uri;
+    private String method;
+    private HttpClient.Redirect followRedirects;
+    private boolean expectContinue;
+    private HttpRequest.BodyProcessor body;
+    private HttpClient.Version version;
+    private final HttpClientImpl client;
+    private ProxySelector proxy;
+    private long timeval = 0;
+
+    public HttpRequestBuilderImpl(HttpClientImpl client, URI uri) {
+        this.client = client;
+        this.uri = uri;
+        this.version = client.version();
+        this.userHeaders = new HttpHeadersImpl();
+    }
+
+    @Override
+    public HttpRequestBuilderImpl body(HttpRequest.BodyProcessor reqproc) {
+        Objects.requireNonNull(reqproc);
+        this.body = reqproc;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl uri(URI uri) {
+        Objects.requireNonNull(uri);
+        this.uri = uri;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl followRedirects(HttpClient.Redirect follow) {
+        Objects.requireNonNull(follow);
+        this.followRedirects = follow;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl header(String name, String value) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(value);
+        Utils.validateToken(name, "invalid header name");
+        userHeaders.addHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl headers(String... params) {
+        Objects.requireNonNull(params);
+        if (params.length % 2 != 0) {
+            throw new IllegalArgumentException("wrong number of parameters");
+        }
+        for (int i=0; i<params.length; ) {
+            String name = params[i];
+            String value = params[i+1];
+            header(name, value);
+            i+=2;
+        }
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl proxy(ProxySelector proxy) {
+        Objects.requireNonNull(proxy);
+        this.proxy = proxy;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl copy() {
+        HttpRequestBuilderImpl b = new HttpRequestBuilderImpl(this.client, this.uri);
+        b.userHeaders = this.userHeaders.deepCopy();
+        b.method = this.method;
+        b.followRedirects = this.followRedirects;
+        b.expectContinue = this.expectContinue;
+        b.body = body;
+        b.uri = uri;
+        b.proxy = proxy;
+        return b;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl setHeader(String name, String value) {
+        Objects.requireNonNull(name);
+        Objects.requireNonNull(value);
+        userHeaders.setHeader(name, value);
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl expectContinue(boolean enable) {
+        expectContinue = enable;
+        return this;
+    }
+
+    @Override
+    public HttpRequestBuilderImpl version(HttpClient.Version version) {
+        Objects.requireNonNull(version);
+        this.version = version;
+        return this;
+    }
+
+    HttpHeadersImpl headers() {  return userHeaders; }
+
+    URI uri() { return uri; }
+
+    String method() { return method; }
+
+    HttpClient.Redirect followRedirects() { return followRedirects; }
+
+    ProxySelector proxy() { return proxy; }
+
+    boolean expectContinue() { return expectContinue; }
+
+    HttpRequest.BodyProcessor body() { return body; }
+
+    HttpClient.Version version() { return version; }
+
+    @Override
+    public HttpRequest GET() { return method("GET"); }
+
+    @Override
+    public HttpRequest POST() { return method("POST"); }
+
+    @Override
+    public HttpRequest PUT() { return method("PUT"); }
+
+    @Override
+    public HttpRequest method(String method) {
+        Objects.requireNonNull(method);
+        this.method = method;
+        return new HttpRequestImpl(client, method, this);
+    }
+
+    @Override
+    public HttpRequest.Builder timeout(TimeUnit timeunit, long timeval) {
+        Objects.requireNonNull(timeunit);
+        this.timeval = timeunit.toMillis(timeval);
+        return this;
+    }
+
+    long timeval() { return timeval; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.http.HttpClient.Version;
+import java.net.http.HttpResponse.MultiProcessor;
+import java.util.concurrent.CompletableFuture;
+import java.net.SocketPermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.Set;
+import static java.net.http.HttpRedirectImpl.getRedirects;
+import java.util.Locale;
+
+class HttpRequestImpl extends HttpRequest {
+
+    private final HttpHeadersImpl userHeaders;
+    private final HttpHeadersImpl systemHeaders;
+    private final URI uri;
+    private InetSocketAddress authority; // only used when URI not specified
+    private final String method;
+    private final HttpClientImpl client;
+    private final HttpRedirectImpl followRedirects;
+    private final ProxySelector proxy;
+    final BodyProcessor requestProcessor;
+    final boolean secure;
+    final boolean expectContinue;
+    private final java.net.http.HttpClient.Version version;
+    private boolean isWebSocket;
+    final MultiExchange exchange;
+    private boolean receiving;
+    private AccessControlContext acc;
+    private final long timeval;
+
+    public HttpRequestImpl(HttpClientImpl client,
+                           String method,
+                           HttpRequestBuilderImpl builder) {
+        this.client = client;
+        this.method = method == null? "GET" : method;
+        this.userHeaders = builder.headers() == null ?
+                new HttpHeadersImpl() : builder.headers();
+        dropDisallowedHeaders();
+        this.followRedirects = getRedirects(builder.followRedirects() == null ?
+                client.followRedirects() : builder.followRedirects());
+        this.systemHeaders = new HttpHeadersImpl();
+        this.uri = builder.uri();
+        this.proxy = builder.proxy();
+        this.expectContinue = builder.expectContinue();
+        this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
+        this.version = builder.version();
+        if (builder.body() == null) {
+            this.requestProcessor = HttpRequest.noBody();
+        } else {
+            this.requestProcessor = builder.body();
+        }
+        this.exchange = new MultiExchange(this);
+        this.timeval = builder.timeval();
+    }
+
+    /** Creates a HttpRequestImpl using fields of an existing request impl. */
+    public HttpRequestImpl(URI uri,
+                           HttpRequest request,
+                           HttpClientImpl client,
+                           String method,
+                           HttpRequestImpl other) {
+        this.client = client;
+        this.method = method == null? "GET" : method;
+        this.userHeaders = other.userHeaders == null ?
+                new HttpHeadersImpl() : other.userHeaders;
+        dropDisallowedHeaders();
+        this.followRedirects = getRedirects(other.followRedirects() == null ?
+                client.followRedirects() : other.followRedirects());
+        this.systemHeaders = other.systemHeaders;
+        this.uri = uri;
+        this.expectContinue = other.expectContinue;
+        this.secure = other.secure;
+        this.requestProcessor = other.requestProcessor;
+        this.proxy = other.proxy;
+        this.version = other.version;
+        this.acc = other.acc;
+        this.exchange = new MultiExchange(this);
+        this.timeval = other.timeval;
+    }
+
+    /* used for creating CONNECT requests  */
+    HttpRequestImpl(HttpClientImpl client,
+                    String method,
+                    InetSocketAddress authority) {
+        this.client = client;
+        this.method = method;
+        this.followRedirects = getRedirects(client.followRedirects());
+        this.systemHeaders = new HttpHeadersImpl();
+        this.userHeaders = new HttpHeadersImpl();
+        this.uri = null;
+        this.proxy = null;
+        this.requestProcessor = HttpRequest.noBody();
+        this.version = java.net.http.HttpClient.Version.HTTP_1_1;
+        this.authority = authority;
+        this.secure = false;
+        this.expectContinue = false;
+        this.exchange = new MultiExchange(this);
+        this.timeval = 0; // block TODO: fix
+    }
+
+    @Override
+    public HttpClientImpl client() {
+        return client;
+    }
+
+
+    @Override
+    public String toString() {
+        return (uri == null ? "" : uri.toString()) + "/" + method + "("
+                + hashCode() + ")";
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        userHeaders.makeUnmodifiable();
+        return userHeaders;
+    }
+
+    InetSocketAddress authority() { return authority; }
+
+    void setH2Upgrade() {
+        Http2ClientImpl h2client = client.client2();
+        systemHeaders.setHeader("Connection", "Upgrade, HTTP2-Settings");
+        systemHeaders.setHeader("Upgrade", "h2c");
+        systemHeaders.setHeader("HTTP2-Settings", h2client.getSettingsString());
+    }
+
+    private static final Set<String>  DISALLOWED_HEADERS_SET = Set.of(
+        "authorization", "connection", "cookie", "content-length",
+        "date", "expect", "from", "host", "origin", "proxy-authorization",
+        "referer", "user-agent", "upgrade", "via", "warning");
+
+
+    // we silently drop headers that are disallowed
+    private void dropDisallowedHeaders() {
+        Set<String> hdrnames = userHeaders.directMap().keySet();
+
+        hdrnames.removeIf((s) ->
+              DISALLOWED_HEADERS_SET.contains(s.toLowerCase())
+        );
+    }
+
+    private synchronized void receiving() {
+        if (receiving) {
+            throw new IllegalStateException("already receiving response");
+        }
+        receiving = true;
+    }
+
+    /*
+     * Response filters may result in a new HttpRequestImpl being created
+     * (but still associated with the same API HttpRequest) and the process
+     * is repeated.
+     */
+    @Override
+    public HttpResponse response() throws IOException, InterruptedException {
+        receiving(); // TODO: update docs
+        if (System.getSecurityManager() != null) {
+            acc = AccessController.getContext();
+        }
+        return exchange.response();
+    }
+
+    @Override
+    public synchronized CompletableFuture<HttpResponse> responseAsync() {
+        receiving(); // TODO: update docs
+        if (System.getSecurityManager() != null) {
+            acc = AccessController.getContext();
+        }
+        return exchange.responseAsync(null)
+            .thenApply((r) -> (HttpResponse)r);
+    }
+
+    public <U> CompletableFuture<U>
+    sendAsyncMulti(HttpResponse.MultiProcessor<U> rspproc) {
+        // To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public boolean expectContinue() { return expectContinue; }
+
+    public boolean requestHttp2() {
+        return version.equals(HttpClient.Version.HTTP_2);
+        //return client.getHttp2Allowed();
+    }
+
+    AccessControlContext getAccessControlContext() { return acc; }
+
+    InetSocketAddress proxy() {
+        ProxySelector ps = this.proxy;
+        if (ps == null) {
+            ps = client.proxy().orElse(null);
+        }
+        if (ps == null || method.equalsIgnoreCase("CONNECT")) {
+            return null;
+        }
+        return (InetSocketAddress)ps.select(uri).get(0).address();
+    }
+
+    boolean secure() { return secure; }
+
+    void isWebSocket(boolean is) {
+        isWebSocket = is;
+    }
+
+    boolean isWebSocket() {
+        return isWebSocket;
+    }
+
+    /** Returns the follow-redirects setting for this request. */
+    @Override
+    public java.net.http.HttpClient.Redirect followRedirects() {
+        return getRedirects(followRedirects);
+    }
+
+    HttpRedirectImpl followRedirectsImpl() { return followRedirects; }
+
+    /**
+     * Returns the request method for this request. If not set explicitly,
+     * the default method for any request is "GET".
+     */
+    @Override
+    public String method() { return method; }
+
+    @Override
+    public URI uri() { return uri; }
+
+    HttpHeadersImpl getUserHeaders() { return userHeaders; }
+
+    HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
+
+    HttpClientImpl getClient() { return client; }
+
+    BodyProcessor requestProcessor() { return requestProcessor; }
+
+    @Override
+    public Version version() { return version; }
+
+    void addSystemHeader(String name, String value) {
+        systemHeaders.addHeader(name, value);
+    }
+
+    void setSystemHeader(String name, String value) {
+        systemHeaders.setHeader(name, value);
+    }
+
+    long timeval() { return timeval; }
+
+    @Override
+    public <U> CompletableFuture<U>
+    multiResponseAsync(MultiProcessor<U> rspproc) {
+        //To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,977 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.LongConsumer;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * Represents a response to a {@link HttpRequest}. A {@code HttpResponse} is
+ * available when the response status code and headers have been received, but
+ * before the response body is received.
+ *
+ * <p> Methods are provided in this class for accessing the response headers,
+ * and status code immediately and also methods for retrieving the response body.
+ * Static methods are provided which implement {@link BodyProcessor} for
+ * standard body types such as {@code String, byte arrays, files}.
+ *
+ * <p> The {@link #body(BodyProcessor) body} or {@link #bodyAsync(BodyProcessor)
+ * bodyAsync} which retrieve any response body must be called to ensure that the
+ * TCP connection can be re-used subsequently, and any response trailers
+ * accessed, if they exist, unless it is known that no response body was received.
+ *
+ * @since 9
+ */
+public abstract class HttpResponse {
+
+    HttpResponse() { }
+
+    /**
+     * Returns the status code for this response.
+     *
+     * @return the response code
+     */
+    public abstract int statusCode();
+
+    /**
+     * Returns the {@link HttpRequest} for this response.
+     *
+     * @return the request
+     */
+    public abstract HttpRequest request();
+
+    /**
+     * Returns the received response headers.
+     *
+     * @return the response headers
+     */
+    public abstract HttpHeaders headers();
+
+    /**
+     * Returns the received response trailers, if there are any. This must only
+     * be called after the response body has been received.
+     *
+     * @return the response trailers (may be empty)
+     * @throws IllegalStateException if the response body has not been received
+     *                               yet
+     */
+    public abstract HttpHeaders trailers();
+
+    /**
+     * Returns the body, blocking if necessary. The type T is determined by the
+     * {@link BodyProcessor} implementation supplied. The body object will be
+     * returned immediately if it is a type (such as {@link java.io.InputStream}
+     * which reads the data itself. If the body object represents the fully read
+     * body then it blocks until it is fully read.
+     *
+     * @param <T> the type of the returned body object
+     * @param processor the processor to handle the response body
+     * @return the body
+     * @throws java.io.UncheckedIOException if an I/O error occurs reading the
+     *                                      response
+     */
+    public abstract <T> T body(BodyProcessor<T> processor);
+
+    /**
+     * Returns a {@link java.util.concurrent.CompletableFuture} of type T. This
+     * always returns immediately and the future completes when the body object
+     * is available. The body will be available immediately if it is a type
+     * (such as {@link java.io.InputStream} which reads the data itself. If the
+     * body object represents the fully read body then it will not be available
+     * until it is fully read.
+     *
+     * @param <T> the type of the returned body object
+     * @param processor the processor to handle the response body
+     * @return a CompletableFuture
+     */
+    public abstract <T> CompletableFuture<T> bodyAsync(BodyProcessor<T> processor);
+
+    /**
+     * Returns the {@link javax.net.ssl.SSLParameters} in effect for this
+     * response. Returns {@code null} if this is not a https response.
+     *
+     * @return the SSLParameters associated with the response
+     */
+    public abstract SSLParameters sslParameters();
+
+    /**
+     * Returns the URI that the response was received from. This may be
+     * different from the request URI if redirection occurred.
+     *
+     * @return the URI of the response
+     */
+    public abstract URI uri();
+
+    /**
+     * Returns the HTTP protocol version that was used for this response.
+     *
+     * @return HTTP protocol version
+     */
+    public abstract HttpClient.Version version();
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt; where
+     * the file is created if it does not already exist. When the Path object is
+     * returned, the body has been completely written to the file.
+     *
+     * @param file the file to store the body in
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFile(Path file) {
+        return asFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt; where
+     * the download directory is specified, but the filename is obtained from
+     * the Content-Disposition response header. The Content-Disposition header
+     * must specify the <i>attachment</i> type and must also contain a
+     * <i>filename</i> parameter. If the filename specifies multiple path
+     * components only the final component is used as the filename (with the
+     * given directory name). When the Path object is returned, the body has
+     * been completely written to the file. The returned Path is the combination
+     * of the supplied directory name and the file name supplied by the server.
+     * If the destination directory does not exist or cannot be written to, then
+     * the response will fail with an IOException.
+     *
+     * @param directory the directory to store the file in
+     * @param openOptions open options
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFileDownload(Path directory,
+                                                     OpenOption... openOptions) {
+        return new AbstractResponseProcessor<Path>() {
+
+            FileChannel fc;
+            Path file;
+
+            @Override
+            public Path onResponseBodyStartImpl(long contentLength,
+                                                HttpHeaders headers)
+                throws IOException
+            {
+                String dispoHeader = headers.firstValue("Content-Disposition")
+                        .orElseThrow(() -> new IOException("No Content-Disposition"));
+                if (!dispoHeader.startsWith("attachment;")) {
+                    throw new IOException("Unknown Content-Disposition type");
+                }
+                int n = dispoHeader.indexOf("filename=");
+                if (n == -1) {
+                    throw new IOException("Bad Content-Disposition type");
+                }
+                String disposition = dispoHeader.substring(n + 9,
+                                                           dispoHeader.lastIndexOf(';'));
+                file = Paths.get(directory.toString(), disposition);
+                fc = FileChannel.open(file, openOptions);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                fc.write(b);
+            }
+
+            @Override
+            public Path onResponseComplete() throws IOException {
+                fc.close();
+                return file;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                try {
+                    if (fc != null) {
+                        fc.close();
+                    }
+                } catch (IOException e) {
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link java.nio.file.Path}&gt;.
+     *
+     * <p> {@link HttpResponse}s returned using this response processor complete
+     * after the entire response, including body has been read.
+     *
+     * @param file the filename to store the body in
+     * @param openOptions any options to use when opening/creating the file
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Path> asFile(Path file,
+                                             OpenOption... openOptions) {
+        return new AbstractResponseProcessor<Path>() {
+
+            FileChannel fc;
+
+            @Override
+            public Path onResponseBodyStartImpl(long contentLength,
+                                                HttpHeaders headers)
+                throws IOException
+            {
+                fc = FileChannel.open(file, openOptions);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b)
+                throws IOException
+            {
+                fc.write(b);
+            }
+
+            @Override
+            public Path onResponseComplete() throws IOException {
+                fc.close();
+                return file;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                try {
+                    if (fc != null) {
+                        fc.close();
+                    }
+                } catch (IOException e) {
+                }
+            }
+        };
+    }
+
+    static class ByteArrayResponseProcessor {
+
+        static final int INITIAL_BUFLEN = 1024;
+
+        byte[] buffer;
+        int capacity;
+        boolean knownLength;
+        int position;
+
+        ByteArrayResponseProcessor() { }
+
+        public byte[] onStart(long contentLength) throws IOException {
+            if (contentLength > Integer.MAX_VALUE) {
+                throw new IllegalArgumentException(
+                        "byte array response limited to MAX_INT size");
+            }
+            capacity = (int) contentLength;
+            if (capacity != -1) {
+                buffer = new byte[capacity];
+                knownLength = true;
+            } else {
+                buffer = new byte[INITIAL_BUFLEN];
+                capacity = INITIAL_BUFLEN;
+                knownLength = false;
+            }
+            position = 0;
+            return null;
+        }
+
+        public void onBodyContent(ByteBuffer b) throws IOException {
+            int toCopy = b.remaining();
+            int size = capacity;
+            if (toCopy > capacity - position) {
+                // resize
+                size += toCopy * 2;
+            }
+            if (size != capacity) {
+                if (knownLength) {
+                    // capacity should have been right from start
+                    throw new IOException("Inconsistent content length");
+                }
+                byte[] newbuf = new byte[size];
+                System.arraycopy(buffer, 0, newbuf, 0, position);
+                buffer = newbuf;
+                capacity = size;
+            }
+            int srcposition = b.arrayOffset() + b.position();
+            System.arraycopy(b.array(), srcposition, buffer, position, toCopy);
+            b.position(b.limit());
+            position += toCopy;
+        }
+
+        public byte[] onComplete() throws IOException {
+            if (knownLength) {
+                if (position != capacity) {
+                    throw new IOException("Wrong number of bytes received");
+                }
+                return buffer;
+            }
+            byte[] buf1 = new byte[position];
+            System.arraycopy(buffer, 0, buf1, 0, position);
+            return buf1;
+        }
+
+        public void onError(Throwable t) {
+            // TODO:
+        }
+    }
+
+    static final byte[] EMPTY = new byte[0];
+
+    /**
+     * Returns a response processor which supplies the response body to the
+     * given Consumer. Each time data is received the consumer is invoked with a
+     * byte[] containing at least one byte of data. After the final buffer is
+     * received, the consumer is invoked one last time, with an empty byte
+     * array.
+     *
+     * @param consumer a Consumer to accept the response body
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Void> asByteArrayConsumer(Consumer<byte[]> consumer) {
+        return new AbstractResponseProcessor<Void>() {
+            @Override
+            public Void onResponseBodyStartImpl(long clen,
+                                                HttpHeaders h)
+                throws IOException
+            {
+                return null;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                if (!b.hasRemaining()) {
+                    return;
+                }
+                byte[] buf = new byte[b.remaining()];
+                b.get(buf);
+                consumer.accept(buf);
+            }
+
+            @Override
+            public Void onResponseComplete() throws IOException {
+                consumer.accept(EMPTY);
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Returns a BodyProcessor which delivers the response data to a
+     * {@link java.util.concurrent.Flow.Subscriber}{@code ByteBuffer}.
+     * <p>
+     * The given {@code Supplier<U>} is invoked when the Flow is completed in
+     * order to convert the flow data into the U object that is returned as the
+     * response body.
+     *
+     * @param <U> the response body type
+     * @param subscriber the Flow.Subscriber
+     * @param bufferSize the maximum number of bytes of data to be supplied in
+     * each ByteBuffer
+     * @param bodySupplier an object that converts the received data to the body
+     * type U.
+     * @return a BodyProcessor
+     *
+     * public static <U> BodyProcessor<Flow.Subscriber<ByteBuffer>>
+     * asFlowSubscriber() {
+     *
+     * return new BodyProcessor<U>() { Flow.Subscriber<ByteBuffer> subscriber;
+     * LongConsumer flowController; FlowSubscription subscription; Supplier<U>
+     * bodySupplier; int bufferSize; // down-stream Flow window. long
+     * buffersWindow; // upstream window long bytesWindow;
+     * LinkedList<ByteBuffer> buffers = new LinkedList<>();
+     *
+     * class FlowSubscription implements Subscription { int recurseLevel = 0;
+     * @Override public void request(long n) { boolean goodToGo = recurseLevel++
+     * == 0;
+     *
+     * while (goodToGo && buffers.size() > 0 && n > 0) { ByteBuffer buf =
+     * buffers.get(0); subscriber.onNext(buf); n--; } buffersWindow += n;
+     * flowController.accept(n * bufferSize); recurseLevel--; }
+     *
+     * @Override public void cancel() { // ?? set flag and throw exception on
+     * next receipt of buffer } }
+     *
+     * @Override public U onResponseBodyStart(long contentLength, HttpHeaders
+     * responseHeaders, LongConsumer flowController) throws IOException {
+     * this.subscriber = subscriber; this.flowController = flowController;
+     * this.subscription = new FlowSubscription(); this.bufferSize = bufferSize;
+     * subscriber.onSubscribe(subscription); return null; }
+     *
+     * @Override public void onResponseError(Throwable t) {
+     * subscriber.onError(t); }
+     *
+     * @Override public void onResponseBodyChunk(ByteBuffer b) throws
+     * IOException { if (buffersWindow > 0) { buffersWindow --;
+     * subscriber.onNext(b); } else { buffers.add(b); // or could combine
+     * buffers? } }
+     *
+     * @Override public U onResponseComplete() throws IOException {
+     * subscriber.onComplete(); return bodySupplier.get(); } }; }
+     */
+    private static final ByteBuffer EOF = ByteBuffer.allocate(0);
+    private static final ByteBuffer CLOSED = ByteBuffer.allocate(0);
+
+    // prototype using ByteBuffer based flow control. InputStream feeds off a
+    // BlockingQueue. Size of Q is determined from the the bufsize (bytes) and
+    // the default ByteBuffer size. bufsize should be a reasonable multiple of
+    // ByteBuffer size to prevent underflow/starvation. The InputStream updates
+    // the flowControl window by one as each ByteBuffer is fully consumed.
+    // Special sentinels are used to indicate stream closed and EOF.
+    /**
+     * Returns a response body processor which provides an InputStream to read
+     * the body.
+     *
+     * @implNote This mechanism is provided primarily for backwards
+     * compatibility for code that expects InputStream. It is recommended for
+     * better performance to use one of the other response processor
+     * implementations.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<InputStream> asInputStream() {
+        return new BodyProcessor<InputStream>() {
+            int queueSize = 2;
+            private volatile Throwable throwable;
+
+            BlockingQueue<ByteBuffer> queue  = new LinkedBlockingQueue<>();
+
+            private void closeImpl() {
+                try {
+                    queue.put(CLOSED);
+                } catch (InterruptedException e) { }
+            }
+
+            @Override
+            public InputStream onResponseBodyStart(long contentLength,
+                                                   HttpHeaders responseHeaders,
+                                                   LongConsumer flowController)
+                throws IOException
+            {
+                flowController.accept(queueSize);
+
+                return new InputStream() {
+                    ByteBuffer buffer;
+
+                    @Override
+                    public int read() throws IOException {
+                        byte[] bb = new byte[1];
+                        int n = read(bb, 0, 1);
+                        if (n == -1) {
+                            return -1;
+                        } else {
+                            return bb[0];
+                        }
+                    }
+
+                    @Override
+                    public int read(byte[] bb) throws IOException {
+                        return read(bb, 0, bb.length);
+                    }
+
+                    @Override
+                    public int read(byte[] bb, int offset, int length)
+                        throws IOException
+                    {
+                        int n;
+                        if (getBuffer()) {
+                            return -1; // EOF
+                        } else {
+                            int remaining = buffer.remaining();
+                            if (length >= remaining) {
+                                buffer.get(bb, offset, remaining);
+                                return remaining;
+                            } else {
+                                buffer.get(bb, offset, length);
+                                return length;
+                            }
+                        }
+                    }
+
+                    @Override
+                    public void close() {
+                        closeImpl();
+                    }
+
+                    private boolean getBuffer() throws IOException {
+                        while (buffer == null || (buffer != EOF &&
+                                buffer != CLOSED && !buffer.hasRemaining())) {
+                            try {
+                                buffer = queue.take();
+                                flowController.accept(1);
+                            } catch (InterruptedException e) {
+                                throw new IOException(e);
+                            }
+                        }
+                        if (buffer == CLOSED) {
+                            if (throwable != null) {
+                                if (throwable instanceof IOException) {
+                                    throw (IOException) throwable;
+                                } else {
+                                    throw new IOException(throwable);
+                                }
+                            }
+                            throw new IOException("Closed");
+                        }
+
+                        if (buffer == EOF) {
+                            return true; // EOF
+                        }
+                        return false; // not EOF
+                    }
+
+                };
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                throwable = t;
+                closeImpl();
+            }
+
+            @Override
+            public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+                try {
+                    queue.put(Utils.copy(b));
+                } catch (InterruptedException e) {
+                    // shouldn't happen as queue should never block
+                    throw new IOException(e);
+                }
+            }
+
+            @Override
+            public InputStream onResponseComplete() throws IOException {
+                try {
+                    queue.put(EOF);
+                } catch (InterruptedException e) {
+                    throw new IOException(e); // can't happen
+                }
+                return null;
+            }
+
+        };
+    }
+
+    /**
+     * Common super class that takes care of flow control
+     *
+     * @param <T>
+     */
+    private static abstract class AbstractResponseProcessor<T>
+        implements BodyProcessor<T>
+    {
+        LongConsumer flowController;
+
+        @Override
+        public final T onResponseBodyStart(long contentLength,
+                                           HttpHeaders responseHeaders,
+                                           LongConsumer flowController)
+            throws IOException
+        {
+            this.flowController = flowController;
+            flowController.accept(1);
+            return onResponseBodyStartImpl(contentLength, responseHeaders);
+        }
+
+        public abstract T onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders responseHeaders)
+            throws IOException;
+
+        public abstract void onResponseBodyChunkImpl(ByteBuffer b)
+            throws IOException;
+
+        @Override
+        public final void onResponseBodyChunk(ByteBuffer b) throws IOException {
+            onResponseBodyChunkImpl(b);
+            flowController.accept(1);
+        }
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;byte[]&gt; which returns the response
+     * body as a {@code byte array}.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<byte[]> asByteArray() {
+        ByteArrayResponseProcessor brp = new ByteArrayResponseProcessor();
+
+        return new AbstractResponseProcessor<byte[]>() {
+
+            @Override
+            public byte[] onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders h)
+                throws IOException
+            {
+                brp.onStart(contentLength);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b)
+                throws IOException
+            {
+                brp.onBodyContent(b);
+            }
+
+            @Override
+            public byte[] onResponseComplete() throws IOException {
+                return brp.onComplete();
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                brp.onError(t);
+            }
+        };
+    }
+
+    /**
+     * Returns a response processor which decodes the body using the character
+     * set specified in the {@code Content-encoding} response header. If there
+     * is no such header, or the character set is not supported, then
+     * {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1} is used.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<String> asString() {
+        return asString(null);
+    }
+
+    /**
+     * Returns a MultiProcessor that handles multiple responses, writes the
+     * response bodies to files and which returns an aggregate response object
+     * that is a {@code Map<URI,Path>}. The keyset of the Map represents the
+     * URIs of the original request and any additional requests generated by the
+     * server. The values are the paths of the destination files. Each path uses
+     * the URI path of the request offset from the destination parent directory
+     * provided.
+     *
+     * <p> All incoming additional requests (push promises) are accepted by this
+     * multi response processor. Errors are effectively ignored and any failed
+     * responses are simply omitted from the result Map. Other implementations
+     * of MultiProcessor can handle these situations
+     *
+     * <p><b>Example usage</b>
+     * <pre>
+     * {@code
+     *    CompletableFuture<Map<URI,Path>> cf =
+     *    HttpRequest.create(new URI("https://www.foo.com/"))
+     *               .version(Version.HTTP2)
+     *               .GET()
+     *               .sendAsyncMulti(HttpResponse.multiFile("/usr/destination"));
+     *
+     *    Map<URI,Path> results = cf.join();
+     * }
+     * </pre>
+     *
+     * @param destination the destination parent directory of all response
+     * bodies
+     * @return a MultiProcessor
+     */
+    public static MultiProcessor<Map<URI, Path>> multiFile(Path destination) {
+
+        return new MultiProcessor<Map<URI, Path>>() {
+            Map<URI, CompletableFuture<Path>> bodyCFs = new HashMap<>();
+
+            Map<URI, Path> results = new HashMap<>();
+
+            @Override
+            public BiFunction<HttpRequest, CompletableFuture<HttpResponse>, Boolean>
+            onStart(HttpRequest mainRequest,
+                    CompletableFuture<HttpResponse> response) {
+                bodyCFs.put(mainRequest.uri(), getBody(mainRequest, response));
+                return (HttpRequest additional, CompletableFuture<HttpResponse> cf) -> {
+                    CompletableFuture<Path> bcf = getBody(additional, cf);
+                    bodyCFs.put(additional.uri(), bcf);
+                    // we accept all comers
+                    return true;
+                };
+            }
+
+            private CompletableFuture<Path> getBody(HttpRequest req,
+                                                    CompletableFuture<HttpResponse> cf) {
+                URI u = req.uri();
+                String path = u.getPath();
+                return cf.thenCompose((HttpResponse resp) -> {
+                    return resp.bodyAsync(HttpResponse.asFile(destination.resolve(path)));
+                });
+            }
+
+            @Override
+            public Map<URI, Path> onComplete() {
+                // all CFs have completed normally or in error.
+                Set<Map.Entry<URI, CompletableFuture<Path>>> entries = bodyCFs.entrySet();
+                for (Map.Entry<URI, CompletableFuture<Path>> entry : entries) {
+                    CompletableFuture<Path> v = entry.getValue();
+                    URI uri = entry.getKey();
+                    if (v.isDone() && !v.isCompletedExceptionally()) {
+                        results.put(uri, v.join());
+                    }
+                }
+                return results;
+            }
+        };
+    }
+
+    /**
+     * Returns a {@link BodyProcessor}&lt;{@link String}&gt;.
+     *
+     * @param charset the name of the charset to interpret the body as. If
+     * {@code null} then the processor tries to determine the character set from
+     * the {@code Content-encoding} header. If that charset is not supported
+     * then {@link java.nio.charset.StandardCharsets#ISO_8859_1 ISO_8859_1} is
+     * used.
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<String> asString(Charset charset) {
+
+        ByteArrayResponseProcessor brp = new ByteArrayResponseProcessor();
+
+        return new AbstractResponseProcessor<String>() {
+            Charset cs = charset;
+            HttpHeaders headers;
+
+            @Override
+            public String onResponseBodyStartImpl(long contentLength,
+                                                  HttpHeaders h)
+                throws IOException
+            {
+                headers = h;
+                brp.onStart(contentLength);
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunkImpl(ByteBuffer b) throws IOException {
+                brp.onBodyContent(b);
+            }
+
+            @Override
+            public String onResponseComplete() throws IOException {
+                byte[] buf = brp.onComplete();
+                if (cs == null) {
+                    cs = headers.firstValue("Content-encoding")
+                                .map((String s) -> Charset.forName(s))
+                                .orElse(StandardCharsets.ISO_8859_1);
+                }
+                return new String(buf, cs);
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+                brp.onError(t);
+            }
+
+        };
+    }
+
+    /**
+     * Returns a response processor which ignores the response body.
+     *
+     * @return a {@code BodyProcessor}
+     */
+    public static BodyProcessor<Void> ignoreBody() {
+        return asByteArrayConsumer((byte[] buf) -> { /* ignore */ });
+    }
+
+    /**
+     * A processor for response bodies, which determines the type of the
+     * response body returned from {@link HttpResponse}. Response processors can
+     * either return an object that represents the body itself (after it has
+     * been read) or else an object that is used to read the body (such as an
+     * {@code InputStream}). The parameterized type {@code <T>} is the type of
+     * the returned body object from
+     * {@link HttpResponse#body(BodyProcessor) HttpResponse.body} and
+     * (indirectly) from {@link HttpResponse#bodyAsync(BodyProcessor)
+     * HttpResponse.bodyAsync}.
+     *
+     * <p> Implementations of this interface are provided in {@link HttpResponse}
+     * which write responses to {@code String, byte[], File, Consumer<byte[]>}.
+     * Custom implementations can also be used.
+     *
+     * <p> The methods of this interface may be called from multiple threads,
+     * but only one method is invoked at a time, and behaves as if called from
+     * one thread.
+     *
+     * @param <T> the type of the response body
+     *
+     * @since 9
+     */
+    public interface BodyProcessor<T> {
+
+        /**
+         * Called immediately before the response body is read. If {@code <T>}
+         * is an object used to read or accept the response body, such as a
+         * {@code Consumer} or {@code InputStream} then it should be returned
+         * from this method, and the body object will be returned before any
+         * data is read. If {@code <T>} represents the body itself after being
+         * read, then this method must return {@code null} and the body will be
+         * returned from {@link #onResponseComplete()}. In both cases, the
+         * actual body data is provided by the
+         * {@link #onResponseBodyChunk(ByteBuffer) onResponseBodyChunk} method
+         * in exactly the same way.
+         *
+         * <p> flowController is a consumer of long values and is used for
+         * updating a flow control window as follows. The window represents the
+         * number of times
+         * {@link #onResponseBodyChunk(java.nio.ByteBuffer) onResponseBodyChunk}
+         * may be called before receiving further updates to the window. Each
+         * time it is called, the window is reduced by {@code 1}. When the
+         * window reaches zero {@code onResponseBodyChunk()} will not be called
+         * again until the window has opened again with further calls to
+         * flowController.accept().
+         * {@link java.util.function.LongConsumer#accept(long) flowcontroller.accept()}
+         * must be called to open (increase) the window by the specified amount.
+         * The initial value is zero. This implies that if {@code
+         * onResponseBodyStart()} does not call {@code flowController.accept()}
+         * with a positive value no data will ever be delivered.
+         *
+         * @param contentLength {@code -1} signifies unknown content length.
+         *                      Otherwise, a positive integer, or zero.
+         * @param responseHeaders the response headers
+         * @param flowController a LongConsumer used to update the flow control
+         *                       window
+         * @return {@code null} or an object that can be used to read the
+         *         response body.
+         * @throws IOException if an exception occurs starting the response
+         *                     body receive
+         */
+        T onResponseBodyStart(long contentLength,
+                              HttpHeaders responseHeaders,
+                              LongConsumer flowController)
+            throws IOException;
+
+        /**
+         * Called if an error occurs while reading the response body. This
+         * terminates the operation and no further calls will occur after this.
+         *
+         * @param t the Throwable
+         */
+        void onResponseError(Throwable t);
+
+        /**
+         * Called for each buffer of data received for this response.
+         * ByteBuffers can be reused as soon as this method returns.
+         *
+         * @param b a ByteBuffer whose position is at the first byte that can be
+         *          read, and whose limit is after the last byte that can be read
+         * @throws IOException in case of I/O error
+         */
+        void onResponseBodyChunk(ByteBuffer b) throws IOException;
+
+        /**
+         * Called after the last time
+         * {@link #onResponseBodyChunk(java.nio.ByteBuffer)} has been called and
+         * returned indicating that the entire content has been read. This
+         * method must return an object that represents or contains the response
+         * body just received, but only if an object was not returned from
+         * {@link #onResponseBodyStart(long, HttpHeaders, LongConsumer)
+         * onResponseBodyStart}.
+         *
+         * @return a T, or {@code null} if an object was already returned
+         * @throws IOException in case of I/O error
+         */
+        T onResponseComplete() throws IOException;
+    }
+
+    /**
+     * A response processor for a HTTP/2 multi response. A multi response
+     * comprises a main response, and zero or more additional responses. Each
+     * additional response is sent by the server in response to requests that
+     * the server also generates. Additional responses are typically resources
+     * that the server guesses the client will need which are related to the
+     * initial request.
+     *
+     * <p>The server generated requests are also known as <i>push promises</i>.
+     * The server is permitted to send any number of these requests up to the
+     * point where the main response is fully received. Therefore, after
+     * completion of the main response body, the final number of additional
+     * responses is known. Additional responses may be cancelled, but given that
+     * the server does not wait for any acknowledgment before sending the
+     * response, this must be done quickly to avoid unnecessary data transmission.
+     *
+     * <p> {@code MultiProcessor}s are parameterised with a type {@code T} which
+     * represents some meaningful aggregate of the responses received. This
+     * would typically be a Collection of response or response body objects. One
+     * example implementation can be found at {@link
+     * HttpResponse#multiFile(java.nio.file.Path)}.
+     *
+     * @param <T> a type representing the aggregated results
+     *
+     * @since 9
+     */
+    public interface MultiProcessor<T> {
+
+        /**
+         * Called before or soon after a multi request is sent. The request that
+         * initiated the multi response is supplied, as well as a
+         * CompletableFuture for the main response. The implementation of this
+         * method must return a BiFunction which is called once for each push
+         * promise received.
+         *
+         * <p> The parameters to the {@code BiFunction} are the {@code HttpRequest}
+         * for the push promise and a {@code CompletableFuture} for its
+         * response. The function must return a Boolean indicating whether the
+         * push promise has been accepted (true) or should be canceled (false).
+         * The CompletableFutures for any canceled pushes are themselves
+         * completed exceptionally soon after the function returns.
+         *
+         * @param mainRequest the main request
+         * @param response a CompletableFuture for the main response
+         * @return a BiFunction that is called for each push promise
+         */
+        BiFunction<HttpRequest, CompletableFuture<HttpResponse>, Boolean>
+        onStart(HttpRequest mainRequest,
+                CompletableFuture<HttpResponse> response);
+
+        /**
+         * Called after all responses associated with the multi response have
+         * been fully processed, including response bodies.
+         *
+         * <p> Example types for {@code T} could be Collections of response body
+         * types or {@code Map}s from request {@code URI} to a response body
+         * type.
+         *
+         * @return the aggregate response object
+         */
+        T onComplete();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.LongConsumer;
+import javax.net.ssl.SSLParameters;
+
+/**
+ * The implementation class for HttpResponse
+ */
+class HttpResponseImpl extends HttpResponse {
+
+    int responseCode;
+    Exchange exchange;
+    HttpRequestImpl request;
+    HttpHeaders1 headers;
+    HttpHeaders1 trailers;
+    SSLParameters sslParameters;
+    URI uri;
+    HttpClient.Version version;
+    AccessControlContext acc;
+    RawChannel rawchan;
+    HttpConnection connection;
+
+    public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders1 headers,
+            HttpHeaders1 trailers, SSLParameters sslParameters,
+            HttpClient.Version version, HttpConnection connection) {
+        this.responseCode = responseCode;
+        this.exchange = exch;
+        this.request = exchange.request();
+        this.headers = headers;
+        this.trailers = trailers;
+        this.sslParameters = sslParameters;
+        this.uri = request.uri();
+        this.version = version;
+        this.connection = connection;
+    }
+
+    @Override
+    public int statusCode() {
+        return responseCode;
+    }
+
+    @Override
+    public HttpRequestImpl request() {
+        return request;
+    }
+
+    @Override
+    public HttpHeaders headers() {
+        headers.makeUnmodifiable();
+        return headers;
+    }
+
+    @Override
+    public HttpHeaders trailers() {
+        trailers.makeUnmodifiable();
+        return trailers;
+    }
+
+
+    @Override
+    public <T> T body(java.net.http.HttpResponse.BodyProcessor<T> processor) {
+        return exchange.responseBody(processor);
+    }
+
+    @Override
+    public <T> CompletableFuture<T> bodyAsync(java.net.http.HttpResponse.BodyProcessor<T> processor) {
+        acc = AccessController.getContext();
+        return exchange.responseBodyAsync(processor);
+    }
+
+    @Override
+    public SSLParameters sslParameters() {
+        return sslParameters;
+    }
+
+    public AccessControlContext getAccessControlContext() {
+        return acc;
+    }
+
+    @Override
+    public URI uri() {
+        return uri;
+    }
+
+    @Override
+    public HttpClient.Version version() {
+        return version;
+    }
+    // keepalive flag determines whether connection is closed or kept alive
+    // by reading/skipping data
+
+    public static java.net.http.HttpResponse.BodyProcessor<Void> ignoreBody(boolean keepalive) {
+        return new java.net.http.HttpResponse.BodyProcessor<Void>() {
+
+            @Override
+            public Void onResponseBodyStart(long clen, HttpHeaders h,
+                    LongConsumer flowController) throws IOException {
+                return null;
+            }
+
+            @Override
+            public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+            }
+
+            @Override
+            public Void onResponseComplete() throws IOException {
+                return null;
+            }
+
+            @Override
+            public void onResponseError(Throwable t) {
+            }
+        };
+    }
+
+    /**
+     *
+     * @return
+     */
+    RawChannel rawChannel() {
+        if (rawchan == null) {
+            rawchan = new RawChannel(request.client(), connection);
+        }
+        return rawchan;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpTimeoutException.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a response is not received within a specified time period.
+ */
+public class HttpTimeoutException extends IOException {
+
+    private static final long serialVersionUID = 981344271622632951L;
+
+    public HttpTimeoutException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.util.Locale;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * -Djava.net.HttpClient.log=errors,requests,headers,frames[:type:type2:..],content
+ *
+ * Any of errors, requests, headers or content are optional.
+ *
+ * Other handlers may be added. All logging is at level INFO
+ *
+ * Logger name is "java.net.http.HttpClient"
+ */
+class Log {
+
+    final static String logProp = "java.net.http.HttpClient.log";
+
+    public static final int OFF = 0;
+    public static final int ERRORS = 0x1;
+    public static final int REQUESTS = 0x2;
+    public static final int HEADERS = 0x4;
+    public static final int CONTENT = 0x8;
+    public static final int FRAMES = 0x10;
+    public static final int SSL = 0x20;
+    static int logging;
+
+    // Frame types: "control", "data", "window", "all"
+    public static final int CONTROL = 1; // all except DATA and WINDOW_UPDATES
+    public static final int DATA = 2;
+    public static final int WINDOW_UPDATES = 4;
+    public static final int ALL = CONTROL| DATA | WINDOW_UPDATES;
+    static int frametypes;
+
+    static sun.util.logging.PlatformLogger logger;
+
+    static {
+        String s = Utils.getNetProperty(logProp);
+        if (s == null) {
+            logging = OFF;
+        } else {
+            String[] vals = s.split(",");
+            for (String val : vals) {
+                switch (val.toLowerCase(Locale.US)) {
+                    case "errors":
+                        logging |= ERRORS;
+                        break;
+                    case "requests":
+                        logging |= REQUESTS;
+                        break;
+                    case "headers":
+                        logging |= HEADERS;
+                        break;
+                    case "content":
+                        logging |= CONTENT;
+                        break;
+                    case "ssl":
+                        logging |= SSL;
+                        break;
+                    case "all":
+                        logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS;
+                        break;
+                }
+                if (val.startsWith("frames")) {
+                    logging |= FRAMES;
+                    String[] types = val.split(":");
+                    if (types.length == 1) {
+                        frametypes = CONTROL | DATA | WINDOW_UPDATES;
+                    } else {
+                        for (String type : types) {
+                            switch (type.toLowerCase()) {
+                                case "control":
+                                    frametypes |= CONTROL;
+                                    break;
+                                case "data":
+                                    frametypes |= DATA;
+                                    break;
+                                case "window":
+                                    frametypes |= WINDOW_UPDATES;
+                                    break;
+                                case "all":
+                                    frametypes = ALL;
+                                    break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (logging != OFF) {
+            logger = PlatformLogger.getLogger("java.net.http.HttpClient");
+        }
+    }
+
+    static boolean errors() {
+        return (logging & ERRORS) != 0;
+    }
+
+    static boolean requests() {
+        return (logging & REQUESTS) != 0;
+    }
+
+    static boolean headers() {
+        return (logging & HEADERS) != 0;
+    }
+
+    static boolean ssl() {
+        return (logging & SSL) != 0;
+    }
+
+    static boolean frames() {
+        return (logging & FRAMES) != 0;
+    }
+
+    static void logError(String s) {
+        if (errors())
+            logger.info("ERROR: " + s);
+    }
+
+    static void logError(Throwable t) {
+        if (errors()) {
+            String s = Utils.stackTrace(t);
+            logger.info("ERROR: " + s);
+        }
+    }
+
+    static void logSSL(String s) {
+        if (ssl())
+            logger.info("SSL: " + s);
+    }
+
+    static void logRequest(String s) {
+        if (requests())
+            logger.info("REQUEST: " + s);
+    }
+
+    static void logResponse(String s) {
+        if (requests())
+            logger.info("RESPONSE: " + s);
+    }
+
+    static void logHeaders(String s) {
+        if (headers())
+            logger.info("HEADERS: " + s);
+    }
+// END HTTP2
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.function.BiFunction;
+
+import static java.net.http.Pair.pair;
+
+/**
+ * Encapsulates multiple Exchanges belonging to one HttpRequestImpl.
+ * - manages filters
+ * - retries due to filters.
+ * - I/O errors and most other exceptions get returned directly to user
+ *
+ * Creates a new Exchange for each request/response interaction
+ */
+class MultiExchange {
+
+    final HttpRequestImpl request; // the user request
+    final HttpClientImpl client;
+    HttpRequestImpl currentreq; // used for async only
+    Exchange exchange; // the current exchange
+    Exchange previous;
+    int attempts;
+    // Maximum number of times a request will be retried/redirected
+    // for any reason
+
+    final static int DEFAULT_MAX_ATTEMPTS = 5;
+    final static int max_attempts = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS
+    );
+
+    private final List<HeaderFilter> filters;
+    TimedEvent td;
+    boolean cancelled = false;
+
+    /**
+     * Filter fields. These are attached as required by filters
+     * and only used by the filter implementations. This could be
+     * generalised into Objects that are passed explicitly to the filters
+     * (one per MultiExchange object, and one per Exchange object possibly)
+     */
+    volatile AuthenticationFilter.AuthInfo serverauth, proxyauth;
+    // RedirectHandler
+    volatile int numberOfRedirects = 0;
+
+    /**
+     */
+    MultiExchange(HttpRequestImpl request) {
+        this.exchange = new Exchange(request);
+        this.previous = null;
+        this.request = request;
+        this.currentreq = request;
+        this.attempts = 0;
+        this.client = request.client();
+        this.filters = client.filterChain();
+    }
+
+    public HttpResponseImpl response() throws IOException, InterruptedException {
+        HttpRequestImpl r = request;
+        if (r.timeval() != 0) {
+            // set timer
+            td = new TimedEvent(r.timeval());
+            client.registerTimer(td);
+        }
+        while (attempts < max_attempts) {
+            try {
+                attempts++;
+                Exchange currExchange = getExchange();
+                requestFilters(r);
+                HttpResponseImpl response = currExchange.response();
+                Pair<HttpResponse, HttpRequestImpl> filterResult = responseFilters(response);
+                HttpRequestImpl newreq = filterResult.second;
+                if (newreq == null) {
+                    if (attempts > 1) {
+                        Log.logError("Succeeded on attempt: " + attempts);
+                    }
+                    cancelTimer();
+                    return response;
+                }
+                response.body(HttpResponse.ignoreBody());
+                setExchange(new Exchange(newreq, currExchange.getAccessControlContext() ));
+                r = newreq;
+            } catch (IOException e) {
+                if (cancelled) {
+                    throw new HttpTimeoutException("Request timed out");
+                }
+                throw e;
+            }
+        }
+        cancelTimer();
+        throw new IOException("Retry limit exceeded");
+    }
+
+    private synchronized Exchange getExchange() {
+        return exchange;
+    }
+
+    private synchronized void setExchange(Exchange exchange) {
+        this.exchange = exchange;
+    }
+
+    private void cancelTimer() {
+        if (td != null) {
+            client.cancelTimer(td);
+        }
+    }
+
+    private void requestFilters(HttpRequestImpl r) throws IOException {
+        for (HeaderFilter filter : filters) {
+            filter.request(r);
+        }
+    }
+
+    // Filters are assumed to be non-blocking so the async
+    // versions of these methods just call the blocking ones
+
+    private CompletableFuture<Void> requestFiltersAsync(HttpRequestImpl r) {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        try {
+            requestFilters(r);
+            cf.complete(null);
+        } catch(Throwable e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+
+    private Pair<HttpResponse,HttpRequestImpl>
+    responseFilters(HttpResponse response) throws IOException
+    {
+        for (HeaderFilter filter : filters) {
+            HttpRequestImpl newreq = filter.response((HttpResponseImpl)response);
+            if (newreq != null) {
+                return pair(null, newreq);
+            }
+        }
+        return pair(response, null);
+    }
+
+    private CompletableFuture<Pair<HttpResponse,HttpRequestImpl>>
+    responseFiltersAsync(HttpResponse response)
+    {
+        CompletableFuture<Pair<HttpResponse,HttpRequestImpl>> cf = new CompletableFuture<>();
+        try {
+            Pair<HttpResponse,HttpRequestImpl> n = responseFilters(response); // assumed to be fast
+            cf.complete(n);
+        } catch (Throwable e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+    public void cancel() {
+        cancelled = true;
+        getExchange().cancel();
+    }
+
+    public CompletableFuture<HttpResponseImpl> responseAsync(Void v) {
+        CompletableFuture<HttpResponseImpl> cf;
+        if (++attempts > max_attempts) {
+            cf = new CompletableFuture<>();
+            cf.completeExceptionally(new IOException("Too many retries"));
+        } else {
+            if (currentreq.timeval() != 0) {
+                // set timer
+                td = new TimedEvent(currentreq.timeval());
+                client.registerTimer(td);
+            }
+            Exchange exch = getExchange();
+            cf = requestFiltersAsync(currentreq)
+                .thenCompose(exch::responseAsync)
+                .thenCompose(this::responseFiltersAsync)
+                .thenCompose((Pair<HttpResponse,HttpRequestImpl> pair) -> {
+                    HttpResponseImpl resp = (HttpResponseImpl)pair.first;
+                    if (resp != null) {
+                        if (attempts > 1) {
+                            Log.logError("Succeeded on attempt: " + attempts);
+                        }
+                        return CompletableFuture.completedFuture(resp);
+                    } else {
+                        currentreq = pair.second;
+                        Exchange previous = exch;
+                        setExchange(new Exchange(currentreq,
+                                                 currentreq.getAccessControlContext()));
+                        //reads body off previous, and then waits for next response
+                        return previous
+                                .responseBodyAsync(HttpResponse.ignoreBody())
+                                .thenCompose(this::responseAsync);
+                    }
+                })
+            .handle((BiFunction<HttpResponse, Throwable, Pair<HttpResponse, Throwable>>) Pair::new)
+            .thenCompose((Pair<HttpResponse,Throwable> obj) -> {
+                HttpResponseImpl response = (HttpResponseImpl)obj.first;
+                if (response != null) {
+                    return CompletableFuture.completedFuture(response);
+                }
+                // all exceptions thrown are handled here
+                CompletableFuture<HttpResponseImpl> error = getExceptionalCF(obj.second);
+                if (error == null) {
+                    cancelTimer();
+                    return responseAsync(null);
+                } else {
+                    return error;
+                }
+            });
+        }
+        return cf;
+    }
+
+    /**
+     * Take a Throwable and return a suitable CompletableFuture that is
+     * completed exceptionally.
+     */
+    private CompletableFuture<HttpResponseImpl> getExceptionalCF(Throwable t) {
+        CompletableFuture<HttpResponseImpl> error = new CompletableFuture<>();
+        if ((t instanceof CompletionException) || (t instanceof ExecutionException)) {
+            if (t.getCause() != null) {
+                t = t.getCause();
+            }
+        }
+        if (cancelled && t instanceof IOException) {
+            t = new HttpTimeoutException("request timed out");
+        }
+        error.completeExceptionally(t);
+        return error;
+    }
+
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) {
+        return getExchange().responseBody(processor);
+    }
+
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+        return getExchange().responseBodyAsync(processor);
+    }
+
+    class TimedEvent extends TimeoutEvent {
+        TimedEvent(long timeval) {
+            super(timeval);
+        }
+        @Override
+        public void handle() {
+            cancel();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General  License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General  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  License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net.http;
+
+/**
+ * A simple paired value class
+ */
+final class Pair<T, U> {
+
+    Pair(T first, U second) {
+        this.second = second;
+        this.first = first;
+    }
+
+    final T first;
+    final U second;
+
+    // Because 'pair()' is shorter than 'new Pair<>()'.
+    // Sometimes this difference might be very significant (especially in a
+    // 80-ish characters boundary). Sorry diamond operator.
+    static <T, U> Pair<T, U> pair(T first, U second) {
+        return new Pair<>(first, second);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Plain raw TCP connection direct to destination
+ */
+class PlainHttpConnection extends HttpConnection {
+
+    protected SocketChannel chan;
+    private volatile boolean connected;
+    private boolean closed;
+
+    class ConnectEvent extends AsyncEvent implements AsyncEvent.Blocking {
+        CompletableFuture<Void> cf;
+
+        ConnectEvent(CompletableFuture<Void> cf) {
+            this.cf = cf;
+        }
+
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_CONNECT;
+        }
+
+        @Override
+        public void handle() {
+            try {
+                chan.finishConnect();
+            } catch (IOException e) {
+                cf.completeExceptionally(e);
+            }
+            connected = true;
+            cf.complete(null);
+        }
+
+        @Override
+        public void abort() {
+            close();
+        }
+    }
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        CompletableFuture<Void> plainFuture = new CompletableFuture<>();
+        try {
+            chan.configureBlocking(false);
+            chan.connect(address);
+            client.registerEvent(new ConnectEvent(plainFuture));
+        } catch (IOException e) {
+            plainFuture.completeExceptionally(e);
+        }
+        return plainFuture;
+    }
+
+    @Override
+    public void connect() throws IOException {
+        chan.connect(address);
+        connected = true;
+    }
+
+    @Override
+    SocketChannel channel() {
+        return chan;
+    }
+
+    PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client) {
+        super(addr, client);
+        try {
+            this.chan = SocketChannel.open();
+            int bufsize = client.getReceiveBufferSize();
+            chan.setOption(StandardSocketOptions.SO_RCVBUF, bufsize);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        return chan.write(buffers, start, number);
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        return chan.write(buffer);
+    }
+
+    @Override
+    public String toString() {
+        return "PlainHttpConnection: " + super.toString();
+    }
+
+    /**
+     * Close this connection
+     */
+    @Override
+    synchronized void close() {
+        if (closed)
+            return;
+        closed = true;
+        try {
+            Log.logError("Closing: " + toString());
+            //System.out.println("Closing: " + this);
+            chan.close();
+        } catch (IOException e) {}
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = getBuffer(); // TODO not using length
+        int n = chan.read(buf);
+        if (n == -1) {
+            return null;
+        }
+        buf.flip();
+        String s = "Receive (" + n + " bytes) ";
+        //debugPrint(s, buf);
+        return buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        int mark = buf.position();
+        int n = chan.read(buf);
+        if (n == -1) {
+            return -1;
+        }
+        Utils.flipToMark(buffer, mark);
+        String s = "Receive (" + n + " bytes) ";
+        //debugPrint(s, buf);
+        return n;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(address, null);
+    }
+
+    @Override
+    synchronized boolean connected() {
+        return connected;
+    }
+
+    class ReceiveResponseEvent extends AsyncEvent implements AsyncEvent.Blocking {
+        CompletableFuture<Void> cf;
+
+        ReceiveResponseEvent(CompletableFuture<Void> cf) {
+            this.cf = cf;
+        }
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public void handle() {
+            cf.complete(null);
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_READ;
+        }
+
+        @Override
+        public void abort() {
+            close();
+        }
+    }
+
+    @Override
+    boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    boolean isProxied() {
+        return false;
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        try {
+            client.registerEvent(new ReceiveResponseEvent(cf));
+        } catch (IOException e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainProxyConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.net.InetSocketAddress;
+
+class PlainProxyConnection extends PlainHttpConnection {
+
+    PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client) {
+        super(proxy, client);
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(null, address);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.security.AccessControlContext;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * A plain text socket tunnel through a proxy. Uses "CONNECT" but does not
+ * encrypt. Used by WebSockets. Subclassed in SSLTunnelConnection for encryption.
+ */
+class PlainTunnelingConnection extends HttpConnection {
+
+    final PlainHttpConnection delegate;
+    protected final InetSocketAddress proxyAddr;
+    private volatile boolean connected;
+    private final AccessControlContext acc;
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+            .thenCompose((Void v) -> {
+                HttpRequestImpl req = new HttpRequestImpl(client, "CONNECT", address);
+                Exchange connectExchange = new Exchange(req, acc);
+                return connectExchange
+                    .responseAsyncImpl(delegate)
+                    .thenCompose((HttpResponse r) -> {
+                        CompletableFuture<Void> cf = new CompletableFuture<>();
+                        if (r.statusCode() != 200) {
+                            cf.completeExceptionally(new IOException("Tunnel failed"));
+                        } else {
+                            connected = true;
+                            cf.complete(null);
+                        }
+                        return cf;
+                    });
+            });
+    }
+
+    @Override
+    public void connect() throws IOException, InterruptedException {
+        delegate.connect();
+        HttpRequestImpl req = new HttpRequestImpl(client, "CONNECT", address);
+        Exchange connectExchange = new Exchange(req, acc);
+        HttpResponse r = connectExchange.responseImpl(delegate);
+        if (r.statusCode() != 200) {
+            throw new IOException("Tunnel failed");
+        }
+        connected = true;
+    }
+
+    @Override
+    boolean connected() {
+        return connected;
+    }
+
+    protected PlainTunnelingConnection(InetSocketAddress addr,
+                                       InetSocketAddress proxy,
+                                       HttpClientImpl client,
+                                       AccessControlContext acc) {
+        super(addr, client);
+        this.proxyAddr = proxy;
+        this.acc = acc;
+        delegate = new PlainHttpConnection(proxy, client);
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return new ConnectionPool.CacheKey(null, proxyAddr);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        return delegate.write(buffers, start, number);
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        return delegate.write(buffer);
+    }
+
+    @Override
+    void close() {
+        delegate.close();
+        connected = false;
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        return delegate.readImpl(length);
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buffer) throws IOException {
+        return delegate.readImpl(buffer);
+    }
+
+    @Override
+    boolean isSecure() {
+        return false;
+    }
+
+    @Override
+    boolean isProxied() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.SelectableChannel;
+
+/**
+ * Used to implement WebSocket. Each RawChannel corresponds to
+ * a TCP connection (SocketChannel) but is connected to a Selector
+ * and an ExecutorService for invoking the send and receive callbacks
+ * Also includes SSL processing.
+ */
+class RawChannel implements ByteChannel, GatheringByteChannel {
+
+    private final HttpClientImpl client;
+    private final HttpConnection connection;
+    private boolean closed;
+
+    private interface RawEvent {
+
+        /** must return the selector interest op flags OR'd. */
+        int interestOps();
+
+        /** called when event occurs. */
+        void handle();
+    }
+
+    interface BlockingEvent extends RawEvent { }
+
+    interface NonBlockingEvent extends RawEvent { }
+
+    RawChannel(HttpClientImpl client, HttpConnection connection) {
+        this.client = client;
+        this.connection = connection;
+    }
+
+    private class RawAsyncEvent extends AsyncEvent {
+
+        private final RawEvent re;
+
+        RawAsyncEvent(RawEvent re) {
+            this.re = re;
+        }
+
+        public SelectableChannel channel() {
+            return connection.channel();
+        }
+
+        // must return the selector interest op flags OR'd
+        public int interestOps() {
+            return re.interestOps();
+        }
+
+        // called when event occurs
+        public void handle() {
+            re.handle();
+        }
+
+        public void abort() {}
+    }
+
+    private class BlockingRawAsyncEvent extends RawAsyncEvent
+            implements AsyncEvent.Blocking {
+
+        BlockingRawAsyncEvent(RawEvent re) {
+            super(re);
+        }
+    }
+
+    private class NonBlockingRawAsyncEvent extends RawAsyncEvent
+            implements AsyncEvent.NonBlocking {
+
+        NonBlockingRawAsyncEvent(RawEvent re) {
+            super(re);
+        }
+    }
+
+    /*
+     * Register given event whose callback will be called once only.
+     * (i.e. register new event for each callback)
+     */
+    public void registerEvent(RawEvent event) throws IOException {
+        if (event instanceof BlockingEvent) {
+            client.registerEvent(new BlockingRawAsyncEvent(event));
+        } else if (event instanceof NonBlockingEvent) {
+            client.registerEvent(new NonBlockingRawAsyncEvent(event));
+        } else {
+            throw new InternalError();
+        }
+    }
+
+    @Override
+    public int read(ByteBuffer dst) throws IOException {
+        return connection.read(dst);
+    }
+
+    @Override
+    public boolean isOpen() {
+        return !closed;
+    }
+
+    @Override
+    public void close() throws IOException {
+        closed = true;
+        connection.close();
+    }
+
+    @Override
+    public long write(ByteBuffer[] src) throws IOException {
+        return connection.write(src, 0, src.length);
+    }
+
+    @Override
+    public long write(ByteBuffer[] src, int offset, int len)
+            throws IOException {
+        return connection.write(src, offset, len);
+    }
+
+    @Override
+    public int write(ByteBuffer src) throws IOException {
+        return (int) connection.write(src);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+
+class RedirectFilter implements HeaderFilter {
+
+    HttpRequestImpl requestImpl;
+    HttpRequest request;
+    HttpClientImpl client;
+    String method;
+    final static int DEFAULT_MAX_REDIRECTS = 5;
+    URI uri;
+
+    final static int max_redirects = Utils.getIntegerNetProperty(
+            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS
+    );
+
+    @Override
+    public void request(HttpRequestImpl r) throws IOException {
+        this.request = r;
+        this.client = r.getClient();
+        this.method = r.method();
+        this.requestImpl = r;
+        this.uri = r.uri();
+    }
+
+    @Override
+    public HttpRequestImpl response(HttpResponseImpl r) throws IOException {
+        return handleResponse(r);
+    }
+
+    /**
+     * checks to see if new request needed and returns it.
+     * Null means response is ok to return to user.
+     */
+    private HttpRequestImpl handleResponse(HttpResponseImpl r) {
+        int rcode = r.statusCode();
+        if (rcode == 200) {
+            return null;
+        }
+        if (rcode >= 300 && rcode <= 399) {
+            URI redir = getRedirectedURI(r.headers());
+            if (canRedirect(r) && ++r.request.exchange.numberOfRedirects < max_redirects) {
+                //System.out.println("Redirecting to: " + redir);
+                return new HttpRequestImpl(redir, request, client, method, requestImpl);
+            } else {
+                //System.out.println("Redirect: giving up");
+                return null;
+            }
+        }
+        return null;
+    }
+
+    private URI getRedirectedURI(HttpHeaders headers) {
+        URI redirectedURI;
+        redirectedURI = headers.firstValue("Location")
+                .map((s) -> URI.create(s))
+                .orElseThrow(() -> new UncheckedIOException(
+                        new IOException("Invalid redirection")));
+
+        // redirect could be relative to original URL, but if not
+        // then redirect is used.
+        redirectedURI = uri.resolve(redirectedURI);
+        return redirectedURI;
+    }
+
+    private boolean canRedirect(HttpResponse r) {
+        return requestImpl.followRedirectsImpl().redirect(r);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseContent.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Implements chunked/fixed transfer encodings of HTTP/1.1 responses.
+ */
+class ResponseContent {
+
+    final HttpResponse.BodyProcessor<?> userProcessor;
+    final HttpResponse.BodyProcessor<?> pusher;
+    final HttpConnection connection;
+    final int contentLength;
+    ByteBuffer buffer;
+    ByteBuffer lastBufferUsed;
+    final ResponseHeaders headers;
+    final Http1Response.FlowController flowController;
+
+    ResponseContent(HttpConnection connection,
+                    int contentLength,
+                    ResponseHeaders h,
+                    HttpResponse.BodyProcessor<?> userProcessor,
+                    Http1Response.FlowController flowController) {
+        this.userProcessor = userProcessor;
+        this.pusher = (HttpResponse.BodyProcessor)userProcessor;
+        this.connection = connection;
+        this.contentLength = contentLength;
+        this.headers = h;
+        this.flowController = flowController;
+    }
+
+    static final int LF = 10;
+    static final int CR = 13;
+    static final int SP = 0x20;
+    static final int BUF_SIZE = 1024;
+
+    boolean chunkedContent, chunkedContentInitialized;
+
+    private boolean contentChunked() throws IOException {
+        if (chunkedContentInitialized) {
+            return chunkedContent;
+        }
+        if (contentLength == -1) {
+            String tc = headers.firstValue("Transfer-Encoding")
+                               .orElse("");
+            if (!tc.equals("")) {
+                if (tc.equalsIgnoreCase("chunked")) {
+                    chunkedContent = true;
+                } else {
+                    throw new IOException("invalid content");
+                }
+            } else {
+                chunkedContent = false;
+            }
+        }
+        chunkedContentInitialized = true;
+        return chunkedContent;
+    }
+
+    /**
+     * Entry point for pusher. b is an initial ByteBuffer that may
+     * have some data in it. When this method returns, the body
+     * has been fully processed.
+     */
+    void pushBody(ByteBuffer b) throws IOException {
+        // TODO: check status
+        if (contentChunked()) {
+            pushBodyChunked(b);
+        } else {
+            pushBodyFixed(b);
+        }
+    }
+
+    // reads and returns chunklen. Position of chunkbuf is first byte
+    // of chunk on return. chunklen includes the CR LF at end of chunk
+    int readChunkLen() throws IOException {
+        chunklen = 0;
+        boolean cr = false;
+        while (true) {
+            getHunk();
+            int c = chunkbuf.get();
+            if (cr) {
+                if (c == LF) {
+                    return chunklen + 2;
+                } else {
+                    throw new IOException("invalid chunk header");
+                }
+            }
+            if (c == CR) {
+                cr = true;
+            } else {
+                int digit = toDigit(c);
+                chunklen = chunklen * 16 + digit;
+            }
+        }
+    }
+
+    int chunklen = -1;      // number of bytes in chunk (fixed)
+    int bytesremaining;     // number of bytes in chunk left to be read incl CRLF
+    int bytesread;
+    ByteBuffer chunkbuf;    // initialise
+
+    // make sure we have at least 1 byte to look at
+    private void getHunk() throws IOException {
+        while (chunkbuf == null || !chunkbuf.hasRemaining()) {
+
+            if (chunkbuf != null) {
+                connection.returnBuffer(chunkbuf);
+            }
+            chunkbuf = connection.read();
+        }
+    }
+
+    private void consumeBytes(int n) throws IOException {
+        getHunk();
+        while (n > 0) {
+            int e = Math.min(chunkbuf.remaining(), n);
+            chunkbuf.position(chunkbuf.position() + e);
+            n -= e;
+            if (n > 0)
+                getHunk();
+        }
+    }
+
+    /**
+     * Returns a ByteBuffer containing a chunk of data or a "hunk" of data
+     * (a chunk of a chunk if the chunk size is larger than our ByteBuffers).
+     */
+    ByteBuffer readChunkedBuffer() throws IOException {
+        if (chunklen == -1) {
+            // new chunk
+            bytesremaining = readChunkLen();
+            chunklen = bytesremaining - 2;
+            if (chunklen == 0) {
+                consumeBytes(2);
+                return null;
+            }
+        }
+
+        getHunk();
+        bytesread = chunkbuf.remaining();
+        ByteBuffer returnBuffer;
+
+        /**
+         * Cases. Always at least one byte is read by getHunk()
+         *
+         * 1) one read contains exactly 1 chunk. Strip off CRLF and pass buffer on
+         * 2) one read contains a hunk. If at end of chunk, consume CRLF.Pass buffer up.
+         * 3) read contains rest of chunk and more data. Copy buffer.
+         */
+        if (bytesread == bytesremaining) {
+            // common case: 1 read = 1 chunk (or final hunk of chunk)
+            chunkbuf.limit(chunkbuf.limit() - 2); // remove trailing CRLF
+            bytesremaining = 0;
+            returnBuffer = chunkbuf;
+            chunkbuf = null;
+            chunklen = -1;
+        } else if (bytesread < bytesremaining) {
+            // read a hunk, maybe including CR or LF or both
+            bytesremaining -= bytesread;
+            if (bytesremaining <= 2) {
+                // remove any trailing CR LF already read, and then read the rest
+                chunkbuf.limit(chunkbuf.limit() - (2 - bytesremaining));
+                consumeBytes(bytesremaining);
+                chunklen = -1;
+            }
+            returnBuffer = chunkbuf;
+            chunkbuf = null;
+        } else {
+            // bytesread > bytesremaining
+            returnBuffer = splitChunkedBuffer(bytesremaining-2);
+            bytesremaining = 0;
+            chunklen = -1;
+            consumeBytes(2);
+        }
+        return returnBuffer;
+    }
+
+    ByteBuffer initialBuffer;
+    int fixedBytesReturned;
+
+    ByteBuffer getResidue() {
+        return lastBufferUsed;
+    }
+
+    private void compactBuffer(ByteBuffer buf) {
+        buf.compact()
+           .flip();
+    }
+
+    /**
+     * Copies inbuf (numBytes from its position) to new buffer. The returned
+     * buffer's position is zero and limit is at end (numBytes)
+     */
+    private ByteBuffer copyBuffer(ByteBuffer inbuf, int numBytes) {
+        ByteBuffer b1 = connection.getBuffer();
+        assert b1.remaining() >= numBytes;
+        byte[] b = b1.array();
+        inbuf.get(b, 0, numBytes);
+        b1.limit(numBytes);
+        return b1;
+    }
+
+    /**
+     * Split numBytes of data out of chunkbuf from the remainder,
+     * copying whichever part is smaller. chunkbuf points to second part
+     * of buffer on return. The returned buffer is the data from position
+     * to position + numBytes. Both buffers positions are reset so same
+     * data can be re-read.
+     */
+    private ByteBuffer splitChunkedBuffer(int numBytes) {
+        ByteBuffer newbuf = connection.getBuffer();
+        byte[] b = newbuf.array();
+        int midpoint = chunkbuf.position() + numBytes;
+        int remainder = chunkbuf.limit() - midpoint;
+
+        if (numBytes < remainder) {
+            // copy first part of chunkbuf to new buf
+            chunkbuf.get(b, 0, numBytes);
+            newbuf.limit(numBytes);
+            return newbuf;
+        } else {
+            // copy remainder of chunkbuf to newbuf and make newbuf chunkbuf
+            chunkbuf.mark();
+            chunkbuf.position(midpoint);
+            chunkbuf.get(b, 0, remainder);
+            chunkbuf.reset();
+            chunkbuf.limit(midpoint);
+            newbuf.limit(remainder);
+            newbuf.position(0);
+            ByteBuffer tmp = chunkbuf;
+            chunkbuf = newbuf;
+            return tmp;
+        }
+    }
+
+    private void pushBodyChunked(ByteBuffer b) throws IOException {
+        chunkbuf = b;
+        while (true) {
+            ByteBuffer b1 = readChunkedBuffer();
+            if (b1 != null) {
+                if (b1.hasRemaining()) {
+                    request(1); // wait till we can send
+                    pusher.onResponseBodyChunk(b1);
+                    lastBufferUsed = b1;
+                }
+            } else {
+                return;
+            }
+        }
+    }
+
+    private int toDigit(int b) throws IOException {
+        if (b >= 0x30 && b <= 0x39) {
+            return b - 0x30;
+        }
+        if (b >= 0x41 && b <= 0x46) {
+            return b - 0x41 + 10;
+        }
+        if (b >= 0x61 && b <= 0x66) {
+            return b - 0x61 + 10;
+        }
+        throw new IOException("Invalid chunk header byte " + b);
+    }
+
+    private void request(long value) throws IOException {
+        try {
+            flowController.request(value);
+        } catch (InterruptedException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private void pushBodyFixed(ByteBuffer b) throws IOException {
+        lastBufferUsed = b;
+        for (int remaining = contentLength; remaining > 0;) {
+            int bufsize = b.remaining();
+            if (bufsize > remaining) {
+                // more data available than required, must copy
+                lastBufferUsed = b;
+                b = copyBuffer(b, remaining);
+                remaining = 0;
+            } else {
+                // pass entire buffer up to user
+                remaining -= bufsize;
+                compactBuffer(b);
+            }
+            request(1); // wait till we can send
+            pusher.onResponseBodyChunk(b);
+            if (remaining > 0) {
+                b = connection.read();
+                if (b == null) {
+                    throw new IOException("Error reading response");
+                }
+                lastBufferUsed = b;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Reads response headers off channel, in blocking mode. Entire header
+ * block is collected in a byte[]. The offset location of the start of
+ * each header name is recorded in an array to facilitate later searching.
+ *
+ * The location of "Content-length" is recorded explicitly. Similar approach
+ * could be taken for other common headers.
+ *
+ * This class is not thread-safe
+ */
+class ResponseHeaders implements HttpHeaders1 {
+
+    static final int DATA_SIZE = 16 * 1024;  // initial space for headers
+    static final int NUM_HEADERS = 50; // initial expected max number of headers
+
+    final HttpConnection connection;
+    byte[] data;
+    int contentlen = -2; // means not initialized
+    ByteBuffer buffer;
+
+    /**
+     * Following used for scanning the array looking for:
+     *      - well known headers
+     *      - end of header block
+     */
+    int[] headerOffsets; // index into data
+    int numHeaders;
+    int count;
+
+    ByteBuffer residue; // after headers processed, data may be here
+
+    ResponseHeaders(HttpConnection connection, ByteBuffer buffer) {
+        this.connection = connection;
+        initOffsets();
+        this.buffer = buffer;
+        data = new byte[DATA_SIZE];
+    }
+
+    int getContentLength() throws IOException {
+        if (contentlen != -2) {
+            return contentlen;
+        }
+        int[] search = findHeaderValue("Content-length");
+        if (search[0] == -1) {
+            contentlen = -1;
+            return -1;
+        }
+
+        int i = search[0];
+
+        while (data[i] == ' ' || data[i] == '\t') {
+            i++;
+            if (i == data.length || data[i] == CR || data[i] == LF) {
+                throw new IOException("Bad header");
+            }
+        }
+        contentlen = 0;
+        int digit = data[i++] - 0x30;
+        while (digit >= 0 && digit <= 9) {
+            contentlen = contentlen * 10 + digit;
+            digit = data[i++] - 0x30;
+        }
+        return contentlen;
+    }
+
+    void log() {
+        populateMap(false);
+    }
+
+    void  populateMap(boolean clearOffsets) {
+        StringBuilder sb;
+
+        for (int i = 0; i < numHeaders; i++) {
+            sb = new StringBuilder(32);
+            int offset = headerOffsets[i];
+            if (offset == -1) {
+                continue;
+            }
+            int j;
+            for (j=0; data[offset+j] != ':'; j++) {
+                // byte to char promotion ok for US-ASCII
+                sb.append((char)data[offset+j]);
+            }
+            String name = sb.toString();
+            List<String> l = getOrCreate(name);
+            addEntry(l, name, offset + j + 1);
+            // clear the offset
+            if (clearOffsets)
+                headerOffsets[i] = -1;
+        }
+    }
+
+    void addEntry(List<String> l, String name, int j) {
+
+        while (data[j] == ' ' || data[j] == '\t') {
+            j++;
+        }
+
+        int vstart = j;
+            // TODO: back slash ??
+
+        while (data[j] != CR) {
+            j++;
+        }
+        try {
+            String value = new String(data, vstart, j - vstart, "US-ASCII");
+            l.add(value);
+        } catch (UnsupportedEncodingException e) {
+            // can't happen
+            throw new InternalError(e);
+        }
+    }
+
+    // returns an int[2]: [0] = offset of value in data[]
+    // [1] = offset in headerOffsets. Both are -1 in error
+
+    private int[] findHeaderValue(String name) {
+        int[] result = new int[2];
+        byte[] namebytes = getBytes(name);
+
+ outer: for (int i = 0; i < numHeaders; i++) {
+            int offset = headerOffsets[i];
+            if (offset == -1) {
+                continue;
+            }
+
+            for (int j=0; j<namebytes.length; j++) {
+                if (namebytes[j] != lowerCase(data[offset+j])) {
+                    continue outer;
+                }
+            }
+            // next char must be ':'
+            if (data[offset+namebytes.length] != ':') {
+                continue;
+            }
+            result[0] = offset+namebytes.length + 1;
+            result[1] = i;
+            return result;
+        }
+        result[0] = -1;
+        result[1] = -1;
+        return result;
+    }
+
+    /**
+     * Populates the map for header values with the given name.
+     * The offsets are cleared for any that are found, so they don't
+     * get repeatedly searched.
+     */
+    List<String> populateMapEntry(String name) {
+        List<String> l = getOrCreate(name);
+        int[] search = findHeaderValue(name);
+        if (search[0] != -1) {
+            addEntry(l, name, search[0]);
+            // clear the offset
+            headerOffsets[search[1]] = -1;
+        }
+        return l;
+    }
+
+    static final Locale usLocale = Locale.US;
+    static final Charset ascii = StandardCharsets.US_ASCII;
+
+    private byte[] getBytes(String name) {
+        return name.toLowerCase(usLocale).getBytes(ascii);
+    }
+
+    /*
+     * We read buffers in a loop until we detect end of headers
+     * CRLFCRLF. Each byte received is copied into the byte[] data
+     * The position of the first byte of each header (after a CRLF)
+     * is recorded in a separate array showing the location of
+     * each header name.
+     */
+    void initHeaders() throws IOException {
+
+        inHeaderName = true;
+        endOfHeader = true;
+
+        for (int numBuffers = 0; true; numBuffers++) {
+
+            if (numBuffers > 0) {
+                buffer = connection.read();
+            }
+
+            if (buffer == null) {
+                throw new IOException("Error reading headers");
+            }
+
+            if (!buffer.hasRemaining()) {
+                continue;
+            }
+
+            // Position set to first byte
+            int start = buffer.position();
+            byte[] backing = buffer.array();
+            int len = buffer.limit() - start;
+
+            for (int i = 0; i < len; i++) {
+                byte b = backing[i + start];
+                if (inHeaderName) {
+                    b = lowerCase(b);
+                }
+                if (b == ':') {
+                    inHeaderName = false;
+                }
+                data[count++] = b;
+                checkByte(b);
+                if (firstChar) {
+                    recordHeaderOffset(count-1);
+                    firstChar = false;
+                }
+                if (endOfHeader && numHeaders == 0) {
+                    // empty headers
+                    endOfAllHeaders = true;
+                }
+                if (endOfAllHeaders) {
+                    int newposition = i + 1 + start;
+                    if (newposition <= buffer.limit()) {
+                        buffer.position(newposition);
+                        residue = buffer;
+                    } else {
+                        residue = null;
+                    }
+                    return;
+                }
+
+                if (count == data.length) {
+                    resizeData();
+                }
+            }
+        }
+    }
+
+    static final int CR = 13;
+    static final int LF = 10;
+    int crlfCount = 0;
+
+    // results of checkByte()
+    boolean endOfHeader; // just seen LF after CR before
+    boolean endOfAllHeaders; // just seen LF after CRLFCR before
+    boolean firstChar; //
+    boolean inHeaderName; // examining header name
+
+    void checkByte(byte b) throws IOException {
+        if (endOfHeader &&  b != CR && b != LF)
+            firstChar = true;
+        endOfHeader = false;
+        endOfAllHeaders = false;
+        switch (crlfCount) {
+            case 0:
+                crlfCount = b == CR ? 1 : 0;
+                break;
+            case 1:
+                crlfCount = b == LF ? 2 : 0;
+                endOfHeader = true;
+                inHeaderName = true;
+                break;
+            case 2:
+                crlfCount = b == CR ? 3 : 0;
+                break;
+            case 3:
+                if (b != LF) {
+                    throw new IOException("Bad header block termination");
+                }
+                endOfAllHeaders = true;
+                break;
+        }
+    }
+
+    byte lowerCase(byte b) {
+        if (b >= 0x41 && b <= 0x5A)
+            b = (byte)(b + 32);
+        return b;
+    }
+
+    void resizeData() {
+        int oldlen = data.length;
+        int newlen = oldlen * 2;
+        byte[] newdata = new byte[newlen];
+        System.arraycopy(data, 0, newdata, 0, oldlen);
+        data = newdata;
+    }
+
+    final void initOffsets() {
+        headerOffsets = new int[NUM_HEADERS];
+        numHeaders = 0;
+    }
+
+    ByteBuffer getResidue() {
+        return residue;
+    }
+
+    void recordHeaderOffset(int index) {
+        if (numHeaders >= headerOffsets.length) {
+            int oldlen = headerOffsets.length;
+            int newlen = oldlen * 2;
+            int[] new1 = new int[newlen];
+            System.arraycopy(headerOffsets, 0, new1, 0, oldlen);
+            headerOffsets = new1;
+        }
+        headerOffsets[numHeaders++] = index;
+    }
+
+    /**
+     * As entries are read from the byte[] they are placed in here
+     * So we always check this map first
+     */
+    Map<String,List<String>> headers = new HashMap<>();
+
+    @Override
+    public Optional<String> firstValue(String name) {
+        List<String> l =  allValues(name);
+        if (l == null || l.isEmpty()) {
+            return Optional.ofNullable(null);
+        } else {
+            return Optional.of(l.get(0));
+        }
+    }
+
+    @Override
+    public List<String> allValues(String name) {
+        name = name.toLowerCase(usLocale);
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = populateMapEntry(name);
+        }
+        return Collections.unmodifiableList(l);
+    }
+
+    @Override
+    public void makeUnmodifiable() {
+    }
+
+    // Delegates map to HashMap but converts keys to lower case
+
+    static class HeaderMap implements Map<String,List<String>> {
+        Map<String,List<String>> inner;
+
+        HeaderMap(Map<String,List<String>> inner) {
+            this.inner = inner;
+        }
+        @Override
+        public int size() {
+            return inner.size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return inner.isEmpty();
+        }
+
+        @Override
+        public boolean containsKey(Object key) {
+            if (!(key instanceof String)) {
+                return false;
+            }
+            String s = ((String)key).toLowerCase(usLocale);
+            return inner.containsKey(s);
+        }
+
+        @Override
+        public boolean containsValue(Object value) {
+            return inner.containsValue(value);
+        }
+
+        @Override
+        public List<String> get(Object key) {
+            String s = ((String)key).toLowerCase(usLocale);
+            return inner.get(s);
+        }
+
+        @Override
+        public List<String> put(String key, List<String> value) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public List<String> remove(Object key) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public void putAll(Map<? extends String, ? extends List<String>> m) {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException("Not supported");
+        }
+
+        @Override
+        public Set<String> keySet() {
+            return inner.keySet();
+        }
+
+        @Override
+        public Collection<List<String>> values() {
+            return inner.values();
+        }
+
+        @Override
+        public Set<Entry<String, List<String>>> entrySet() {
+            return inner.entrySet();
+        }
+    }
+
+    @Override
+    public Map<String, List<String>> map() {
+        populateMap(true);
+        return new HeaderMap(headers);
+    }
+
+    Map<String, List<String>> mapInternal() {
+        populateMap(false);
+        return new HeaderMap(headers);
+    }
+
+    private List<String> getOrCreate(String name) {
+        List<String> l = headers.get(name);
+        if (l == null) {
+            l = new LinkedList<>();
+            headers.put(name, l);
+        }
+        return l;
+    }
+
+    @Override
+    public Optional<Long> firstValueAsLong(String name) {
+        List<String> l =  allValues(name);
+        if (l == null) {
+            return Optional.ofNullable(null);
+        } else {
+            String v = l.get(0);
+            Long lv = Long.parseLong(v);
+            return Optional.of(lv);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import java.net.http.SSLDelegate.BufType;
+import java.net.http.SSLDelegate.WrapperResult;
+
+/**
+ * An SSL connection built on a Plain TCP connection.
+ */
+class SSLConnection extends HttpConnection {
+
+    PlainHttpConnection delegate;
+    SSLDelegate sslDelegate;
+    final String[] alpn;
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+                .thenCompose((Void v) -> {
+                    CompletableFuture<Void> cf = new CompletableFuture<>();
+                    try {
+                        this.sslDelegate = new SSLDelegate(delegate.channel(),
+                                                           client,
+                                                           alpn);
+                        cf.complete(null);
+                    } catch (IOException e) {
+                        cf.completeExceptionally(e);
+                    }
+                    return cf;
+                });
+    }
+
+    @Override
+    public void connect() throws IOException {
+        delegate.connect();
+        this.sslDelegate = new SSLDelegate(delegate.channel(), client, alpn);
+    }
+
+    SSLConnection(InetSocketAddress addr, HttpClientImpl client, String[] ap) {
+        super(addr, client);
+        this.alpn = ap;
+        delegate = new PlainHttpConnection(addr, client);
+    }
+
+    @Override
+    SSLParameters sslParameters() {
+        return sslDelegate.getSSLParameters();
+    }
+
+    @Override
+    public String toString() {
+        return "SSLConnection: " + super.toString();
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int length) {
+        long c = 0;
+        for (int i=0; i<length; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return ConnectionPool.cacheKey(address, null);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        long l = countBytes(buffers, start, number);
+        WrapperResult r = sslDelegate.sendData(buffers, start, number);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        long l = buffer.remaining();
+        WrapperResult r = sslDelegate.sendData(buffer);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    void close() {
+        try {
+            //System.err.println ("Closing: " + this);
+            delegate.channel().close(); // TODO: proper close
+        } catch (IOException ex) {
+            Log.logError(ex.toString());
+        }
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = sslDelegate.allocate(BufType.PACKET, length);
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        // TODO: need to ensure that buf is big enough for application data
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.result.bytesProduced();
+    }
+
+    @Override
+    boolean connected() {
+        return delegate.connected();
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    boolean isSecure() {
+        return true;
+    }
+
+    @Override
+    boolean isProxied() {
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
+
+/**
+ * Implements the mechanics of SSL by managing an SSLEngine object.
+ * One of these is associated with each SSLConnection.
+ */
+class SSLDelegate {
+
+    final SSLEngine engine;
+    final EngineWrapper wrapper;
+    final Lock handshaking = new ReentrantLock();
+    final SSLParameters sslParameters;
+    final SocketChannel chan;
+    final HttpClientImpl client;
+
+    // alpn[] may be null
+    SSLDelegate(SocketChannel chan, HttpClientImpl client, String[] alpn)
+        throws IOException
+    {
+        SSLContext context = client.sslContext();
+        engine = context.createSSLEngine();
+        engine.setUseClientMode(true);
+        SSLParameters sslp = client.sslParameters().orElse(null);
+        if (sslp == null) {
+            sslp = context.getDefaultSSLParameters();
+        }
+        sslParameters = Utils.copySSLParameters(sslp);
+        if (alpn != null) {
+            sslParameters.setApplicationProtocols(alpn);
+            Log.logSSL("Setting application protocols: " + Arrays.toString(alpn));
+        } else {
+            Log.logSSL("Warning no application protocols proposed!");
+        }
+        engine.setSSLParameters(sslParameters);
+        wrapper = new EngineWrapper(chan, engine);
+        this.chan = chan;
+        this.client = client;
+    }
+
+    SSLParameters getSSLParameters() {
+        return sslParameters;
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int number) {
+        long c = 0;
+        for (int i=0; i<number; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+
+    static class WrapperResult {
+        static WrapperResult createOK() {
+            WrapperResult r = new WrapperResult();
+            r.buf = null;
+            r.result = new SSLEngineResult(Status.OK, NOT_HANDSHAKING, 0, 0);
+            return r;
+        }
+        SSLEngineResult result;
+
+        /* if passed in buffer was not big enough then the a reallocated buffer
+         * is returned here  */
+        ByteBuffer buf;
+    }
+
+    int app_buf_size;
+    int packet_buf_size;
+
+    enum BufType {
+        PACKET,
+        APPLICATION
+    };
+
+    ByteBuffer allocate (BufType type) {
+        return allocate (type, -1);
+    }
+
+    // TODO: Use buffer pool for this
+    ByteBuffer allocate (BufType type, int len) {
+        assert engine != null;
+        synchronized (this) {
+            int size;
+            if (type == BufType.PACKET) {
+                if (packet_buf_size == 0) {
+                    SSLSession sess = engine.getSession();
+                    packet_buf_size = sess.getPacketBufferSize();
+                }
+                if (len > packet_buf_size) {
+                    packet_buf_size = len;
+                }
+                size = packet_buf_size;
+            } else {
+                if (app_buf_size == 0) {
+                    SSLSession sess = engine.getSession();
+                    app_buf_size = sess.getApplicationBufferSize();
+                }
+                if (len > app_buf_size) {
+                    app_buf_size = len;
+                }
+                size = app_buf_size;
+            }
+            return ByteBuffer.allocate (size);
+        }
+    }
+
+    /* reallocates the buffer by :-
+     * 1. creating a new buffer double the size of the old one
+     * 2. putting the contents of the old buffer into the new one
+     * 3. set xx_buf_size to the new size if it was smaller than new size
+     *
+     * flip is set to true if the old buffer needs to be flipped
+     * before it is copied.
+     */
+    private ByteBuffer realloc (ByteBuffer b, boolean flip, BufType type) {
+        synchronized (this) {
+            int nsize = 2 * b.capacity();
+            ByteBuffer n = allocate (type, nsize);
+            if (flip) {
+                b.flip();
+            }
+            n.put(b);
+            b = n;
+        }
+        return b;
+    }
+
+    /**
+     * This is a thin wrapper over SSLEngine and the SocketChannel, which
+     * guarantees the ordering of wraps/unwraps with respect to the underlying
+     * channel read/writes. It handles the UNDER/OVERFLOW status codes
+     * It does not handle the handshaking status codes, or the CLOSED status code
+     * though once the engine is closed, any attempt to read/write to it
+     * will get an exception.  The overall result is returned.
+     * It functions synchronously/blocking
+     */
+    class EngineWrapper {
+
+        SocketChannel chan;
+        SSLEngine engine;
+        Object wrapLock, unwrapLock;
+        ByteBuffer unwrap_src, wrap_dst;
+        boolean closed = false;
+        int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
+
+        EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
+            this.chan = chan;
+            this.engine = engine;
+            wrapLock = new Object();
+            unwrapLock = new Object();
+            unwrap_src = allocate(BufType.PACKET);
+            wrap_dst = allocate(BufType.PACKET);
+        }
+
+        void close () throws IOException {
+        }
+
+        WrapperResult wrapAndSend(ByteBuffer src, boolean ignoreClose)
+            throws IOException
+        {
+            ByteBuffer[] buffers = new ByteBuffer[1];
+            buffers[0] = src;
+            return wrapAndSend(buffers, 0, 1, ignoreClose);
+        }
+
+        /* try to wrap and send the data in src. Handles OVERFLOW.
+         * Might block if there is an outbound blockage or if another
+         * thread is calling wrap(). Also, might not send any data
+         * if an unwrap is needed.
+         */
+        WrapperResult wrapAndSend(ByteBuffer[] src,
+                                  int offset,
+                                  int len,
+                                  boolean ignoreClose)
+            throws IOException
+        {
+            if (closed && !ignoreClose) {
+                throw new IOException ("Engine is closed");
+            }
+            Status status;
+            WrapperResult r = new WrapperResult();
+            synchronized (wrapLock) {
+                wrap_dst.clear();
+                do {
+                    r.result = engine.wrap (src, offset, len, wrap_dst);
+                    status = r.result.getStatus();
+                    if (status == Status.BUFFER_OVERFLOW) {
+                        wrap_dst = realloc (wrap_dst, true, BufType.PACKET);
+                    }
+                } while (status == Status.BUFFER_OVERFLOW);
+                if (status == Status.CLOSED && !ignoreClose) {
+                    closed = true;
+                    return r;
+                }
+                if (r.result.bytesProduced() > 0) {
+                    wrap_dst.flip();
+                    int l = wrap_dst.remaining();
+                    assert l == r.result.bytesProduced();
+                    while (l>0) {
+                        l -= chan.write (wrap_dst);
+                    }
+                }
+            }
+            return r;
+        }
+
+        /* block until a complete message is available and return it
+         * in dst, together with the Result. dst may have been re-allocated
+         * so caller should check the returned value in Result
+         * If handshaking is in progress then, possibly no data is returned
+         */
+        WrapperResult recvAndUnwrap(ByteBuffer dst) throws IOException {
+            Status status;
+            WrapperResult r = new WrapperResult();
+            r.buf = dst;
+            if (closed) {
+                throw new IOException ("Engine is closed");
+            }
+            boolean needData;
+            if (u_remaining > 0) {
+                unwrap_src.compact();
+                unwrap_src.flip();
+                needData = false;
+            } else {
+                unwrap_src.clear();
+                needData = true;
+            }
+            synchronized (unwrapLock) {
+                int x;
+                do {
+                    if (needData) {
+                        do {
+                        x = chan.read (unwrap_src);
+                        } while (x == 0);
+                        if (x == -1) {
+                            throw new IOException ("connection closed for reading");
+                        }
+                        unwrap_src.flip();
+                    }
+                    r.result = engine.unwrap (unwrap_src, r.buf);
+                    status = r.result.getStatus();
+                    if (status == Status.BUFFER_UNDERFLOW) {
+                        if (unwrap_src.limit() == unwrap_src.capacity()) {
+                            /* buffer not big enough */
+                            unwrap_src = realloc (
+                                unwrap_src, false, BufType.PACKET
+                            );
+                        } else {
+                            /* Buffer not full, just need to read more
+                             * data off the channel. Reset pointers
+                             * for reading off SocketChannel
+                             */
+                            unwrap_src.position (unwrap_src.limit());
+                            unwrap_src.limit (unwrap_src.capacity());
+                        }
+                        needData = true;
+                    } else if (status == Status.BUFFER_OVERFLOW) {
+                        r.buf = realloc (r.buf, true, BufType.APPLICATION);
+                        needData = false;
+                    } else if (status == Status.CLOSED) {
+                        closed = true;
+                        r.buf.flip();
+                        return r;
+                    }
+                } while (status != Status.OK);
+            }
+            u_remaining = unwrap_src.remaining();
+            return r;
+        }
+    }
+
+    WrapperResult sendData (ByteBuffer src) throws IOException {
+        ByteBuffer[] buffers = new ByteBuffer[1];
+        buffers[0] = src;
+        return sendData(buffers, 0, 1);
+    }
+
+    /**
+     * send the data in the given ByteBuffer. If a handshake is needed
+     * then this is handled within this method. When this call returns,
+     * all of the given user data has been sent and any handshake has been
+     * completed. Caller should check if engine has been closed.
+     */
+    WrapperResult sendData (ByteBuffer[] src, int offset, int len) throws IOException {
+        WrapperResult r = WrapperResult.createOK();
+        while (countBytes(src, offset, len) > 0) {
+            r = wrapper.wrapAndSend(src, offset, len, false);
+            Status status = r.result.getStatus();
+            if (status == Status.CLOSED) {
+                doClosure ();
+                return r;
+            }
+            HandshakeStatus hs_status = r.result.getHandshakeStatus();
+            if (hs_status != HandshakeStatus.FINISHED &&
+                hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                doHandshake(hs_status);
+            }
+        }
+        return r;
+    }
+
+    /**
+     * read data thru the engine into the given ByteBuffer. If the
+     * given buffer was not large enough, a new one is allocated
+     * and returned. This call handles handshaking automatically.
+     * Caller should check if engine has been closed.
+     */
+    WrapperResult recvData (ByteBuffer dst) throws IOException {
+        /* we wait until some user data arrives */
+        int mark = dst.position();
+        WrapperResult r = null;
+        assert dst.position() == 0;
+        while (dst.position() == 0) {
+            r = wrapper.recvAndUnwrap (dst);
+            dst = (r.buf != dst) ? r.buf: dst;
+            Status status = r.result.getStatus();
+            if (status == Status.CLOSED) {
+                doClosure ();
+                return r;
+            }
+
+            HandshakeStatus hs_status = r.result.getHandshakeStatus();
+            if (hs_status != HandshakeStatus.FINISHED &&
+                hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                doHandshake (hs_status);
+            }
+        }
+        Utils.flipToMark(dst, mark);
+        return r;
+    }
+
+    /* we've received a close notify. Need to call wrap to send
+     * the response
+     */
+    void doClosure () throws IOException {
+        try {
+            handshaking.lock();
+            ByteBuffer tmp = allocate(BufType.APPLICATION);
+            WrapperResult r;
+            do {
+                tmp.clear();
+                tmp.flip ();
+                r = wrapper.wrapAndSend(tmp, true);
+            } while (r.result.getStatus() != Status.CLOSED);
+        } finally {
+            handshaking.unlock();
+        }
+    }
+
+    /* do the (complete) handshake after acquiring the handshake lock.
+     * If two threads call this at the same time, then we depend
+     * on the wrapper methods being idempotent. eg. if wrapAndSend()
+     * is called with no data to send then there must be no problem
+     */
+    @SuppressWarnings("fallthrough")
+    void doHandshake (HandshakeStatus hs_status) throws IOException {
+        boolean wasBlocking = false;
+        try {
+            wasBlocking = chan.isBlocking();
+            handshaking.lock();
+            chan.configureBlocking(true);
+            ByteBuffer tmp = allocate(BufType.APPLICATION);
+            while (hs_status != HandshakeStatus.FINISHED &&
+                   hs_status != HandshakeStatus.NOT_HANDSHAKING)
+            {
+                WrapperResult r = null;
+                switch (hs_status) {
+                    case NEED_TASK:
+                        Runnable task;
+                        while ((task = engine.getDelegatedTask()) != null) {
+                            /* run in current thread, because we are already
+                             * running an external Executor
+                             */
+                            task.run();
+                        }
+                        /* fall thru - call wrap again */
+                    case NEED_WRAP:
+                        tmp.clear();
+                        tmp.flip();
+                        r = wrapper.wrapAndSend(tmp, false);
+                        break;
+
+                    case NEED_UNWRAP:
+                        tmp.clear();
+                        r = wrapper.recvAndUnwrap (tmp);
+                        if (r.buf != tmp) {
+                            tmp = r.buf;
+                        }
+                        assert tmp.position() == 0;
+                        break;
+                }
+                hs_status = r.result.getHandshakeStatus();
+            }
+            Log.logSSL(getSessionInfo());
+            if (!wasBlocking) {
+                chan.configureBlocking(false);
+            }
+        } finally {
+            handshaking.unlock();
+        }
+    }
+
+    String getSessionInfo() {
+        StringBuilder sb = new StringBuilder();
+        String application = engine.getApplicationProtocol();
+        SSLSession sess = engine.getSession();
+        String cipher = sess.getCipherSuite();
+        String protocol = sess.getProtocol();
+        sb.append("Handshake complete alpn: ")
+                .append(application)
+                .append(", Cipher: ")
+                .append(cipher)
+                .append(", Protocol: ")
+                .append(protocol);
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.security.AccessControlContext;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLEngineResult.Status;
+import javax.net.ssl.SSLParameters;
+import java.net.http.SSLDelegate.BufType;
+import java.net.http.SSLDelegate.WrapperResult;
+
+/**
+ * An SSL tunnel built on a Plain (CONNECT) TCP tunnel.
+ */
+class SSLTunnelConnection extends HttpConnection {
+
+    final PlainTunnelingConnection delegate;
+    protected SSLDelegate sslDelegate;
+    private volatile boolean connected;
+
+    @Override
+    public void connect() throws IOException, InterruptedException {
+        delegate.connect();
+        this.sslDelegate = new SSLDelegate(delegate.channel(), client, null);
+        connected = true;
+    }
+
+    @Override
+    boolean connected() {
+        return connected && delegate.connected();
+    }
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync()
+            .thenAccept((Void v) -> {
+                try {
+                    // can this block?
+                    this.sslDelegate = new SSLDelegate(delegate.channel(),
+                                                       client,
+                                                       null);
+                    connected = true;
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+            });
+    }
+
+    SSLTunnelConnection(InetSocketAddress addr,
+                        HttpClientImpl client,
+                        InetSocketAddress proxy,
+                        AccessControlContext acc) {
+        super(addr, client);
+        delegate = new PlainTunnelingConnection(addr, proxy, client, acc);
+    }
+
+    @Override
+    SSLParameters sslParameters() {
+        return sslDelegate.getSSLParameters();
+    }
+
+    @Override
+    public String toString() {
+        return "SSLTunnelConnection: " + super.toString();
+    }
+
+    private static long countBytes(ByteBuffer[] buffers, int start, int number) {
+        long c = 0;
+        for (int i=0; i<number; i++) {
+            c+= buffers[start+i].remaining();
+        }
+        return c;
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return ConnectionPool.cacheKey(address, delegate.proxyAddr);
+    }
+
+    @Override
+    long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        //debugPrint("Send", buffers, start, number);
+        long l = countBytes(buffers, start, number);
+        WrapperResult r = sslDelegate.sendData(buffers, start, number);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        //debugPrint("Send", buffer);
+        long l = buffer.remaining();
+        WrapperResult r = sslDelegate.sendData(buffer);
+        if (r.result.getStatus() == Status.CLOSED) {
+            if (l > 0) {
+                throw new IOException("SSLHttpConnection closed");
+            }
+        }
+        return l;
+    }
+
+    @Override
+    void close() {
+        try {
+            //System.err.println ("Closing: " + this);
+            delegate.channel().close(); // TODO: proper close
+        } catch (IOException ex) {
+        }
+    }
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        ByteBuffer buf = sslDelegate.allocate(BufType.PACKET, length);
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.buf;
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buf) throws IOException {
+        WrapperResult r = sslDelegate.recvData(buf);
+        // TODO: check for closure
+        String s = "Receive) ";
+        //debugPrint(s, r.buf);
+        return r.result.bytesProduced();
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        return delegate.whenReceivingResponse();
+    }
+
+    @Override
+    boolean isSecure() {
+        return true;
+    }
+
+    @Override
+    boolean isProxied() {
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.function.LongConsumer;
+
+/**
+ * Http/2 Stream
+ */
+class Stream extends ExchangeImpl {
+
+    void debugPrint() {
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+            return null;
+    }
+
+    Stream(HttpClientImpl client, Http2Connection connection, Exchange e) {
+        super(e);
+    }
+
+    @Override
+    HttpResponseImpl getResponse() throws IOException {
+        return null;
+    }
+
+    @Override
+    void sendRequest() throws IOException, InterruptedException {
+    }
+
+    @Override
+    void sendHeadersOnly() throws IOException, InterruptedException {
+    }
+
+    @Override
+    void sendBody() throws IOException, InterruptedException {
+    }
+
+    @Override
+    CompletableFuture<Void> sendHeadersAsync() {
+        return null;
+    }
+
+    @Override
+    CompletableFuture<HttpResponseImpl> getResponseAsync(Void v) {
+        return null;
+    }
+
+    @Override
+    CompletableFuture<Void> sendBodyAsync() {
+        return null;
+    }
+
+    @Override
+    void cancel() {
+    }
+
+
+    @Override
+    CompletableFuture<Void> sendRequestAsync() {
+        return null;
+    }
+
+    @Override
+    <T> T responseBody(HttpResponse.BodyProcessor<T> processor) throws IOException {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/TimeoutEvent.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+/**
+ * Timeout event delivered by selector thread. Executes given handler
+ * if the timer not cancelled first.
+ *
+ * Register with HttpClientImpl.registerTimer(TimeoutEvent)
+ *
+ * Cancel with HttpClientImpl.cancelTimer(TimeoutEvent)
+ */
+abstract class TimeoutEvent {
+
+    final long timeval;
+
+    long delta; // used when on queue
+
+    TimeoutEvent(long timeval) { this.timeval = timeval; }
+
+    public abstract void handle();
+
+    /**  Returns the timevalue in milli-seconds */
+    public long timevalMillis() { return timeval; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.NetPermission;
+import java.net.URI;
+import java.net.URLPermission;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.net.ssl.SSLParameters;
+import sun.net.NetProperties;
+
+/**
+ * Miscellaneous utilities
+ */
+class Utils {
+
+    /**
+     * Allocated buffer size. Must never be higher than 16K. But can be lower
+     * if smaller allocation units preferred. HTTP/2 mandates that all
+     * implementations support frame payloads of at least 16K.
+     */
+    public static final int BUFSIZE = 16 * 1024;
+
+    /** Validates a RFC7230 token */
+    static void validateToken(String token, String errormsg) {
+        int length = token.length();
+        for (int i = 0; i < length; i++) {
+            int c = token.codePointAt(i);
+            if (c >= 0x30 && c <= 0x39 // 0 - 9
+                    || (c >= 0x61 && c <= 0x7a) // a - z
+                    || (c >= 0x41 && c <= 0x5a) // A - Z
+                    || (c >= 0x21 && c <= 0x2e && c != 0x22 && c != 0x27 && c != 0x2c)
+                    || (c >= 0x5e && c <= 0x60)
+                    || (c == 0x7c) || (c == 0x7e)) {
+            } else {
+                throw new IllegalArgumentException(errormsg);
+            }
+        }
+    }
+
+    /**
+     * Return sthe security permission required for the given details.
+     * If method is CONNECT, then uri must be of form "scheme://host:port"
+     */
+    static URLPermission getPermission(URI uri,
+                                       String method,
+                                       Map<String, List<String>> headers) {
+        StringBuilder sb = new StringBuilder();
+
+        String urlstring, actionstring;
+
+        if (method.equals("CONNECT")) {
+            urlstring = uri.toString();
+            actionstring = "CONNECT";
+        } else {
+            sb.append(uri.getScheme())
+                    .append("://")
+                    .append(uri.getHost())
+                    .append(uri.getPath());
+            urlstring = sb.toString();
+
+            sb = new StringBuilder();
+            sb.append(method);
+            if (headers != null && !headers.isEmpty()) {
+                sb.append(':');
+                Set<String> keys = headers.keySet();
+                boolean first = true;
+                for (String key : keys) {
+                    if (!first) {
+                        sb.append(',');
+                    }
+                    sb.append(key);
+                    first = false;
+                }
+            }
+            actionstring = sb.toString();
+        }
+        return new URLPermission(urlstring, actionstring);
+    }
+
+    static void checkNetPermission(String target) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null)
+            return;
+        NetPermission np = new NetPermission(target);
+        sm.checkPermission(np);
+    }
+
+    static int getIntegerNetProperty(String name, int defaultValue) {
+        return AccessController.doPrivileged((PrivilegedAction<Integer>)() ->
+            NetProperties.getInteger(name, defaultValue) );
+    }
+
+    static String getNetProperty(String name) {
+        return AccessController.doPrivileged((PrivilegedAction<String>)() ->
+            NetProperties.get(name) );
+    }
+
+    static SSLParameters copySSLParameters(SSLParameters p) {
+        SSLParameters p1 = new SSLParameters();
+        p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
+        p1.setCipherSuites(p.getCipherSuites());
+        p1.setEnableRetransmissions(p.getEnableRetransmissions());
+        p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
+        p1.setMaximumPacketSize(p.getMaximumPacketSize());
+        p1.setNeedClientAuth(p.getNeedClientAuth());
+        p1.setProtocols(p.getProtocols().clone());
+        p1.setSNIMatchers(p.getSNIMatchers());
+        p1.setServerNames(p.getServerNames());
+        p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
+        p1.setWantClientAuth(p.getWantClientAuth());
+        return p1;
+    }
+
+
+    /** Resumes reading into the given buffer. */
+    static void unflip(ByteBuffer buf) {
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+    }
+
+    /**
+     * Set limit to position, and position to mark.
+     *
+     *
+     * @param buffer
+     * @param mark
+     */
+    static void flipToMark(ByteBuffer buffer, int mark) {
+        buffer.limit(buffer.position());
+        buffer.position(mark);
+    }
+
+    /** Compact and leave ready for reading. */
+    static void compact(List<ByteBuffer> buffers) {
+        for (ByteBuffer b : buffers) {
+            b.compact();
+            b.flip();
+        }
+    }
+
+    static String stackTrace(Throwable t) {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        String s = null;
+        try {
+            PrintStream p = new PrintStream(bos, true, "US-ASCII");
+            t.printStackTrace(p);
+            s = bos.toString("US-ASCII");
+        } catch (UnsupportedEncodingException ex) {
+            // can't happen
+        }
+        return s;
+    }
+
+    /** Copies as much of src to dst as possible. */
+    static void copy (ByteBuffer src, ByteBuffer dst) {
+        int srcLen = src.remaining();
+        int dstLen = dst.remaining();
+        if (srcLen > dstLen) {
+            int diff = srcLen - dstLen;
+            int limit = src.limit();
+            src.limit(limit - diff);
+            dst.put(src);
+            src.limit(limit);
+        } else {
+            dst.put(src);
+        }
+    }
+
+    static ByteBuffer copy(ByteBuffer src) {
+        ByteBuffer dst = ByteBuffer.allocate(src.remaining());
+        dst.put(src);
+        dst.flip();
+        return dst;
+    }
+
+    static String combine(String[] s) {
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        boolean first = true;
+        for (String s1 : s) {
+            if (!first) {
+                sb.append(", ");
+                first = false;
+            }
+            sb.append(s1);
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/package-info.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <h2>High level HTTP API</h2>
+ * This provides a high-level client interface to HTTP (versions 1.1 and 2).
+ * Synchronous and asynchronous (via
+ * {@link java.util.concurrent.CompletableFuture}) modes are provided. The main
+ * classes defined are:
+ * <ul>
+ *    <li>{@link java.net.http.HttpClient}</li>
+ *    <li>{@link java.net.http.HttpRequest}</li>
+ *    <li>{@link java.net.http.HttpResponse}</li>
+ * </ul>
+ *
+ * @since 9
+ */
+package java.net.http;
--- a/jdk/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/jdk.jdi/share/native/libdt_shmem/shmemBack.c	Mon Feb 29 15:42:34 2016 +0000
@@ -338,7 +338,7 @@
     return JDWPTRANSPORT_ERROR_NONE;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
                      jint version, jdwpTransportEnv** result)
 {
--- a/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c	Mon Feb 29 15:42:34 2016 +0000
@@ -784,7 +784,7 @@
     return JDWPTRANSPORT_ERROR_NONE;
 }
 
-JNIEXPORT jint JNICALL
+jint JNICALL
 jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr,
                      jint version, jdwpTransportEnv** result)
 {
--- a/jdk/src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/src/jdk.localedata/share/classes/META-INF/services/sun.util.locale.provider.LocaleDataMetaInfo	Mon Feb 29 15:42:34 2016 +0000
@@ -1,2 +1,2 @@
 sun.util.resources.provider.NonBaseLocaleDataMetaInfo
-sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo_jdk_localedata
+sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo
--- a/jdk/test/ProblemList.txt	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/ProblemList.txt	Mon Feb 29 15:42:34 2016 +0000
@@ -200,6 +200,9 @@
 java/nio/file/WatchService/Basic.java				solaris-all
 java/nio/file/WatchService/LotsOfEvents.java			solaris-all
 
+# 8149712
+java/nio/charset/coders/BashStreams.java                        generic-all
+
 ############################################################################
 
 # jdk_rmi
--- a/jdk/test/com/sun/net/httpserver/FileServerHandler.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/com/sun/net/httpserver/FileServerHandler.java	Mon Feb 29 15:42:34 2016 +0000
@@ -23,6 +23,7 @@
 
 import java.util.*;
 import java.util.concurrent.*;
+import java.util.logging.*;
 import java.io.*;
 import java.net.*;
 import java.security.*;
@@ -36,6 +37,10 @@
  * Must be given an abs pathname to the document root.
  * Directory listings together with text + html files
  * can be served.
+ *
+ * File Server created on files sub-path
+ *
+ * Echo server created on echo sub-path
  */
 public class FileServerHandler implements HttpHandler {
 
@@ -44,14 +49,24 @@
                 System.out.println ("usage: java FileServerHandler rootDir port logfilename");
                 System.exit(1);
             }
+            Logger logger = Logger.getLogger("com.sun.net.httpserver");
+            ConsoleHandler ch = new ConsoleHandler();
+            logger.setLevel(Level.ALL);
+            ch.setLevel(Level.ALL);
+            logger.addHandler(ch);
+
             String rootDir = args[0];
             int port = Integer.parseInt (args[1]);
             String logfile = args[2];
-            HttpServer server = HttpServer.create (new InetSocketAddress (8000), 0);
+            HttpServer server = HttpServer.create (new InetSocketAddress (port), 0);
             HttpHandler h = new FileServerHandler (rootDir);
+            HttpHandler h1 = new EchoHandler ();
 
-            HttpContext c = server.createContext ("/", h);
+            HttpContext c = server.createContext ("/files", h);
             c.getFilters().add (new LogFilter (new File (logfile)));
+            HttpContext c1 = server.createContext ("/echo", h1);
+            c.getFilters().add (new LogFilter (new File (logfile)));
+            c1.getFilters().add (new LogFilter (new File (logfile)));
             server.setExecutor (Executors.newCachedThreadPool());
             server.start ();
         }
@@ -72,7 +87,8 @@
             URI uri = t.getRequestURI();
             String path = uri.getPath();
 
-            while (is.read () != -1) ;
+            int x = 0;
+            while (is.read () != -1) x++;
             is.close();
             File f = new File (docroot, path);
             if (!f.exists()) {
@@ -164,3 +180,61 @@
             t.close();
         }
     }
+
+class EchoHandler implements HttpHandler {
+
+    byte[] read(InputStream is) throws IOException {
+        byte[] buf = new byte[1024];
+        byte[] result = new byte[0];
+
+        while (true) {
+            int n = is.read(buf);
+            if (n > 0) {
+                byte[] b1 = new byte[result.length + n];
+                System.arraycopy(result, 0, b1, 0, result.length);
+                System.arraycopy(buf, 0, b1, result.length, n);
+                result = b1;
+            } else if (n == -1) {
+                return result;
+            }
+        }
+    }
+
+    public void handle (HttpExchange t)
+        throws IOException
+    {
+        InputStream is = t.getRequestBody();
+        Headers map = t.getRequestHeaders();
+        String fixedrequest = map.getFirst ("XFixed");
+
+        // return the number of bytes received (no echo)
+        String summary = map.getFirst ("XSummary");
+        if (fixedrequest != null && summary == null)  {
+            byte[] in = read(is);
+            t.sendResponseHeaders(200, in.length);
+            OutputStream os = t.getResponseBody();
+            os.write(in);
+            os.close();
+            is.close();
+        } else {
+            OutputStream os = t.getResponseBody();
+            byte[] buf = new byte[64 * 1024];
+            t.sendResponseHeaders(200, 0);
+            int n, count=0;;
+
+            while ((n = is.read(buf)) != -1) {
+                if (summary == null) {
+                    os.write(buf, 0, n);
+                }
+                count += n;
+            }
+            if (summary != null) {
+                String s = Integer.toString(count);
+                os.write(s.getBytes());
+            }
+            os.close();
+            is.close();
+        }
+    }
+}
+
--- a/jdk/test/java/lang/invoke/T8139885.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/lang/invoke/T8139885.java	Mon Feb 29 15:42:34 2016 +0000
@@ -26,6 +26,7 @@
 /* @test
  * @bug 8139885
  * @bug 8143798
+ * @bug 8150825
  * @run testng/othervm -ea -esa test.java.lang.invoke.T8139885
  */
 
@@ -315,14 +316,17 @@
                 {intid, MethodHandles.identity(double.class)},
                 {intid, MethodHandles.dropArguments(intid, 0, String.class)},
                 {intid, MethodHandles.dropArguments(intid, 0, Throwable.class, double.class)},
-                {errTarget, errCleanup}
+                {errTarget, errCleanup},
+                {TryFinally.MH_voidTarget, TryFinally.MH_voidCleanup}
         };
         String[] messages = {
                 "target and return types must match: double != int",
                 "cleanup first argument and Throwable must match: (String,int)int != class java.lang.Throwable",
                 "cleanup second argument and target return type must match: (Throwable,double,int)int != int",
                 "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " +
-                        errCleanup.type() + " != " + errTarget.type()
+                        errCleanup.type() + " != " + errTarget.type(),
+                "cleanup parameters after (Throwable,result) and target parameter list prefix must match: " +
+                        TryFinally.MH_voidCleanup.type() + " != " + TryFinally.MH_voidTarget.type()
         };
         for (int i = 0; i < cases.length; ++i) {
             boolean caught = false;
@@ -908,6 +912,10 @@
             return r + " (but " + first + " first)!";
         }
 
+        static void voidTarget() {}
+
+        static void voidCleanup(Throwable t, int a) {}
+
         static final Class<TryFinally> TRY_FINALLY = TryFinally.class;
 
         static final MethodType MT_greet = methodType(String.class, String.class);
@@ -916,6 +924,8 @@
         static final MethodType MT_printMore = methodType(void.class, Throwable.class, String.class);
         static final MethodType MT_greetMore = methodType(String.class, String.class, String.class);
         static final MethodType MT_exclaimMore = methodType(String.class, Throwable.class, String.class, String.class);
+        static final MethodType MT_voidTarget = methodType(void.class);
+        static final MethodType MT_voidCleanup = methodType(void.class, Throwable.class, int.class);
 
         static final MethodHandle MH_greet;
         static final MethodHandle MH_exclaim;
@@ -923,6 +933,8 @@
         static final MethodHandle MH_printMore;
         static final MethodHandle MH_greetMore;
         static final MethodHandle MH_exclaimMore;
+        static final MethodHandle MH_voidTarget;
+        static final MethodHandle MH_voidCleanup;
 
         static final MethodType MT_hello = methodType(String.class, String.class);
         static final MethodType MT_printHello = methodType(void.class, String.class);
@@ -936,6 +948,8 @@
                 MH_printMore = LOOKUP.findStatic(TRY_FINALLY, "printMore", MT_printMore);
                 MH_greetMore = LOOKUP.findStatic(TRY_FINALLY, "greetMore", MT_greetMore);
                 MH_exclaimMore = LOOKUP.findStatic(TRY_FINALLY, "exclaimMore", MT_exclaimMore);
+                MH_voidTarget = LOOKUP.findStatic(TRY_FINALLY, "voidTarget", MT_voidTarget);
+                MH_voidCleanup = LOOKUP.findStatic(TRY_FINALLY, "voidCleanup", MT_voidCleanup);
             } catch (Exception e) {
                 throw new ExceptionInInitializerError(e);
             }
--- a/jdk/test/java/net/SocketOption/OptionsTest.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/net/SocketOption/OptionsTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -54,6 +54,7 @@
         Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
@@ -61,6 +62,7 @@
     static Test[] serverSocketTests = new Test[] {
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
 
@@ -68,6 +70,7 @@
         Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)),
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
         Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE),
         Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
 
@@ -97,15 +100,19 @@
             Socket c = new Socket("127.0.0.1", srv.getLocalPort());
             Socket s = srv.accept();
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<socketTests.length; i++) {
                 Test test = socketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(Socket.class, c,test.option);
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("S Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(Socket.class, c,test.option);
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("S Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -115,15 +122,19 @@
         try (
             DatagramSocket c = new DatagramSocket(0);
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<dgSocketTests.length; i++) {
                 Test test = dgSocketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("DG Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(DatagramSocket.class, c,test.option);
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("DG Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -151,17 +162,21 @@
         try (
             ServerSocket c = new ServerSocket(0);
         ) {
+            Set<SocketOption<?>> options = c.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
             for (int i=0; i<serverSocketTests.length; i++) {
                 Test test = serverSocketTests[i];
-                c.setOption((SocketOption)test.option, test.testValue);
-                Object getval = c.getOption((SocketOption)test.option);
-                Object legacyget = legacyGetOption(
-                    ServerSocket.class, c, test.option
-                );
-                if (!getval.equals(legacyget)) {
-                    Formatter f = new Formatter();
-                    f.format("SS Err %d: %s/%s", i, getval, legacyget);
-                    throw new RuntimeException(f.toString());
+                if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) {
+                    c.setOption((SocketOption)test.option, test.testValue);
+                    Object getval = c.getOption((SocketOption)test.option);
+                    Object legacyget = legacyGetOption(
+                        ServerSocket.class, c, test.option
+                    );
+                    if (!getval.equals(legacyget)) {
+                        Formatter f = new Formatter();
+                        f.format("SS Err %d: %s/%s", i, getval, legacyget);
+                        throw new RuntimeException(f.toString());
+                    }
                 }
             }
         }
@@ -174,6 +189,8 @@
     {
         if (type.equals(Socket.class)) {
             Socket socket = (Socket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) {
                 return Boolean.valueOf(socket.getKeepAlive());
@@ -183,6 +200,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.SO_LINGER)) {
                 return Integer.valueOf(socket.getSoLinger());
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
@@ -194,10 +213,15 @@
             }
         } else if  (type.equals(ServerSocket.class)) {
             ServerSocket socket = (ServerSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
+
             if (option.equals(StandardSocketOptions.SO_RCVBUF)) {
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(jdk.net.Sockets.getOption(
                     socket, StandardSocketOptions.IP_TOS));
@@ -206,6 +230,8 @@
             }
         } else if  (type.equals(DatagramSocket.class)) {
             DatagramSocket socket = (DatagramSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
                 return Integer.valueOf(socket.getSendBufferSize());
@@ -213,6 +239,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(socket.getTrafficClass());
             } else {
@@ -221,6 +249,8 @@
 
         } else if  (type.equals(MulticastSocket.class)) {
             MulticastSocket socket = (MulticastSocket)s;
+            Set<SocketOption<?>> options = socket.supportedOptions();
+            boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT);
 
             if (option.equals(StandardSocketOptions.SO_SNDBUF)) {
                 return Integer.valueOf(socket.getSendBufferSize());
@@ -228,6 +258,8 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) {
+                return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT));
             } else if (option.equals(StandardSocketOptions.IP_TOS)) {
                 return Integer.valueOf(socket.getTrafficClass());
             } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/APIErrors.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm APIErrors
+ */
+//package javaapplication16;
+
+import com.sun.net.httpserver.*;
+import java.io.IOException;
+import java.net.*;
+import java.net.http.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.function.Supplier;
+
+/**
+ * Does stupid things with API, to check appropriate errors/exceptions thrown
+ */
+public class APIErrors {
+
+    static HttpServer s1 = null;
+    static ExecutorService executor = null;
+    static int port;
+    static HttpClient client;
+    static String httproot, fileuri, fileroot;
+    static List<HttpClient> clients = new LinkedList<>();
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        fileroot = System.getProperty("test.src") + "/docs";
+
+        client = HttpClient.create().build();
+
+        clients.add(HttpClient.getDefault());
+
+        try {
+            test1();
+            test2();
+            test3();
+        } finally {
+            s1.stop(0);
+            executor.shutdownNow();
+            for (HttpClient client : clients)
+                client.executorService().shutdownNow();
+        }
+    }
+
+    static void reject(Runnable r, Class<? extends Exception> extype) {
+        try {
+            r.run();
+            throw new RuntimeException("Expected: " + extype);
+        } catch (Throwable t) {
+            if (!extype.isAssignableFrom(t.getClass())) {
+                throw new RuntimeException("Wrong exception type: " + extype + " / "
+                    +t.getClass());
+            }
+        }
+    }
+
+    static void accept(Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            throw new RuntimeException("Unexpected exception: " + t);
+        }
+    }
+
+    static void checkNonNull(Supplier<?> r) {
+        if (r.get() == null)
+            throw new RuntimeException("Unexpected null return:");
+    }
+
+    static void assertTrue(Supplier<Boolean> r) {
+        if (r.get() == false)
+            throw new RuntimeException("Assertion failure:");
+    }
+
+    // HttpClient.Builder
+    static void test1() throws Exception {
+        System.out.println("Test 1");
+        HttpClient.Builder cb = HttpClient.create();
+        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000);
+        reject(() -> { cb.priority(-1);}, IllegalArgumentException.class);
+        reject(() -> { cb.priority(500);}, IllegalArgumentException.class);
+        accept(() -> { cb.priority(1);});
+        accept(() -> { cb.priority(255);});
+
+        accept(() -> {clients.add(cb.build()); clients.add(cb.build());});
+    }
+
+    static void test2() throws Exception {
+        System.out.println("Test 2");
+        HttpClient.Builder cb = HttpClient.create();
+        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000);
+        cb.proxy(ProxySelector.of(addr));
+        HttpClient c = cb.build();
+        clients.add(c);
+        checkNonNull(()-> {return c.executorService();});
+        assertTrue(()-> {return c.followRedirects() == HttpClient.Redirect.NEVER;});
+        assertTrue(()-> {return !c.authenticator().isPresent();});
+    }
+
+    static URI accessibleURI() {
+        return URI.create(fileuri);
+    }
+
+    static HttpRequest request() {
+        return HttpRequest.create(accessibleURI())
+                .GET();
+    }
+
+    static void test3() throws Exception {
+        System.out.println("Test 3");
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp = r1.response();
+                HttpResponse resp1 = r1.response();
+            } catch (IOException |InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp = r1.response();
+                HttpResponse resp1 = r1.responseAsync().get();
+            } catch (IOException |InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+        reject(()-> {
+            try {
+                HttpRequest r1 = request();
+                HttpResponse resp1 = r1.responseAsync().get();
+                HttpResponse resp = r1.response();
+            } catch (IOException |InterruptedException | ExecutionException e) {
+                throw new RuntimeException(e);
+            }
+        }, IllegalStateException.class);
+    }
+
+    static class Auth extends java.net.Authenticator {
+        int count = 0;
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            if (count++ == 0) {
+                return new PasswordAuthentication("user", "passwd".toCharArray());
+            } else {
+                return new PasswordAuthentication("user", "goober".toCharArray());
+            }
+        }
+        int count() {
+            return count;
+        }
+    }
+
+    public static void initServer() throws Exception {
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = s1.createContext("/files", h);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor (executor);
+        s1.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httproot = "http://127.0.0.1:" + port + "/files/";
+        fileuri = httproot + "foo.txt";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/BasicAuthTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm BasicAuthTest
+ * @summary Basic Authentication Test
+ */
+
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+public class BasicAuthTest {
+
+    static volatile boolean ok;
+    static final String RESPONSE = "Hello world";
+    static final String POST_BODY = "This is the POST body 123909090909090";
+
+    public static void main(String[] args) throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 10);
+        ExecutorService e = Executors.newCachedThreadPool();
+        Handler h = new Handler();
+        HttpContext serverContext = server.createContext("/test", h);
+        int port = server.getAddress().getPort();
+        System.out.println("Server port = " + port);
+
+        ClientAuth ca = new ClientAuth();
+        ServerAuth sa = new ServerAuth("foo realm");
+        serverContext.setAuthenticator(sa);
+        server.setExecutor(e);
+        server.start();
+        HttpClient client = HttpClient.create()
+                                      .authenticator(ca)
+                                      .build();
+
+        try {
+            URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/test/foo");
+            HttpRequest req = client.request(uri).GET();
+
+            HttpResponse resp = req.response();
+            ok = resp.statusCode() == 200 &&
+                    resp.body(HttpResponse.asString()).equals(RESPONSE);
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+
+            // repeat same request, should succeed but no additional authenticator calls
+
+            req = client.request(uri).GET();
+            resp = req.response();
+            ok = resp.statusCode() == 200 &&
+                    resp.body(HttpResponse.asString()).equals(RESPONSE);
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+
+            // try a POST
+
+            req = client.request(uri)
+                    .body(HttpRequest.fromString(POST_BODY))
+                    .POST();
+            resp = req.response();
+            ok = resp.statusCode() == 200;
+
+            if (!ok || ca.count != 1)
+                throw new RuntimeException("Test failed");
+        } finally {
+            client.executorService().shutdownNow();
+            server.stop(0);
+            e.shutdownNow();
+        }
+        System.out.println("OK");
+    }
+
+    static class ServerAuth extends BasicAuthenticator {
+
+        ServerAuth(String realm) {
+            super(realm);
+        }
+
+        @Override
+        public boolean checkCredentials(String username, String password) {
+            if (!"user".equals(username) || !"passwd".equals(password)) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+    static class ClientAuth extends java.net.Authenticator {
+        volatile int count = 0;
+
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            count++;
+            return new PasswordAuthentication("user", "passwd".toCharArray());
+        }
+    }
+
+   static class Handler implements HttpHandler {
+        static volatile boolean ok;
+
+        @Override
+        public void handle(HttpExchange he) throws IOException {
+            String method = he.getRequestMethod();
+            InputStream is = he.getRequestBody();
+            if (method.equalsIgnoreCase("POST")) {
+                String requestBody = new String(is.readAllBytes(), US_ASCII);
+                if (!requestBody.equals(POST_BODY)) {
+                    he.sendResponseHeaders(500, -1);
+                    ok = false;
+                } else {
+                    he.sendResponseHeaders(200, -1);
+                    ok = true;
+                }
+            } else { // GET
+                he.sendResponseHeaders(200, RESPONSE.length());
+                OutputStream os = he.getResponseBody();
+                os.write(RESPONSE.getBytes(US_ASCII));
+                os.close();
+                ok = true;
+            }
+        }
+
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/HeadersTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.http.HttpRequest;
+import java.net.URI;
+
+/**
+ * @test
+ * @bug 8087112
+ * @summary Basic test for headers
+ */
+public class HeadersTest {
+
+    static final URI TEST_URI = URI.create("http://www.foo.com/");
+
+    static void bad(String name) {
+        HttpRequest.Builder builder = HttpRequest.create(TEST_URI);
+        try {
+            builder.header(name, "foo");
+            throw new RuntimeException("Expected IAE for header:" + name);
+        } catch (IllegalArgumentException expected) { }
+    }
+
+    static void good(String name) {
+        HttpRequest.Builder builder = HttpRequest.create(TEST_URI);
+        try {
+            builder.header(name, "foo");
+        } catch (IllegalArgumentException e) {
+            throw new RuntimeException("Unexpected IAE for header:" + name);
+        }
+    }
+
+    public static void main(String[] args) {
+        bad("bad:header");
+        bad("Foo\n");
+        good("X-Foo!");
+        good("Bar~");
+        good("x");
+        bad(" ");
+        bad("Bar\r\n");
+        good("Hello#world");
+        good("Qwer#ert");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/HttpUtils.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import static java.net.http.HttpRequest.fromByteArray;
+import static java.net.http.HttpRequest.fromByteArrays;
+import static java.net.http.HttpRequest.fromFile;
+import static java.net.http.HttpRequest.fromInputStream;
+import static java.net.http.HttpRequest.fromString;
+import java.net.http.HttpResponse;
+import static java.net.http.HttpResponse.asByteArray;
+import static java.net.http.HttpResponse.asFile;
+import static java.net.http.HttpResponse.asInputStream;
+import static java.net.http.HttpResponse.asString;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+public final class HttpUtils {
+
+    static final int DEFAULT_OFFSET = 10;
+    static final int DEFAULT_LENGTH = 1000;
+    static final String midSizedFilename = "/files/notsobigfile.txt";
+    static final String smallFilename = "/files/smallfile.txt";
+    static final Path midSizedFile;
+    static final Path smallFile;
+    static final String fileroot;
+
+    public enum RequestBody {
+        STRING, FILE, BYTE_ARRAY, BYTE_ARRAY_OFFSET, INPUTSTREAM, STRING_WITH_CHARSET,
+    }
+
+    static {
+        fileroot = System.getProperty("test.src") + "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+    }
+
+    static public String getFileContent(String path) throws IOException {
+        FileInputStream fis = new FileInputStream(path);
+        byte[] buf = new byte[2 * 1024];
+        StringBuilder sb = new StringBuilder();
+        int byteRead;
+        while ((byteRead = fis.read(buf)) != -1) {
+            sb.append(new String(buf, 0, byteRead, "US-ASCII"));
+        }
+        return sb.toString();
+    }
+
+    public static HttpRequest.Builder getHttpRequestBuilder(final HttpClient client,
+                                                            final String requestType,
+                                                            final URI uri)
+        throws IOException
+    {
+        HttpRequest.Builder builder;
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        byte buf[] = fileContents.getBytes();
+        switch (requestType) {
+            case "InputStream":
+                InputStream inputStream = new FileInputStream(smallFile.toFile());
+                builder = client.request(uri)
+                                .body(fromInputStream(inputStream));
+                break;
+            case "byteArray":
+                builder = client.request(uri)
+                                .body(fromByteArray(buf));
+                break;
+            case "byteArrays":
+                Iterable iterable = Arrays.asList(buf);
+                builder = client.request(uri)
+                                .body(fromByteArrays(iterable.iterator()));
+                break;
+            case "string":
+                builder = client.request(uri)
+                                .body(fromString(fileContents));
+                break;
+            case "byteArray_offset":
+                builder = client.request(uri)
+                                .body(fromByteArray(buf,
+                                                    DEFAULT_OFFSET,
+                                                    DEFAULT_LENGTH));
+                break;
+            case "file":
+                builder = client.request(uri)
+                                .body(fromFile(smallFile));
+                break;
+            case "string_charset":
+                builder = client.request(uri)
+                                .body(fromString(new String(buf),
+                                                 Charset.defaultCharset()));
+                break;
+            default:
+                builder = null;
+                break;
+        }
+        return builder;
+    }
+
+    public static void checkResponse(final HttpResponse response,
+                                     String requestType,
+                                     final String responseType)
+        throws IOException
+    {
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        if (requestType.equals("byteArray_offset")) {
+            fileContents = fileContents.substring(DEFAULT_OFFSET,
+                                                  DEFAULT_OFFSET + DEFAULT_LENGTH);
+        }
+        byte buf[] = fileContents.getBytes();
+        String responseBody;
+        switch (responseType) {
+            case "string":
+                responseBody = response.body(asString());
+                if (!responseBody.equals(fileContents)) {
+                    throw new RuntimeException();
+                }
+                break;
+            case "byteArray":
+                byte arr[] = response.body(asByteArray());
+                if (!Arrays.equals(arr, buf)) {
+                    throw new RuntimeException();
+                }
+                break;
+            case "file":
+                response.body(asFile(Paths.get("barf.txt")));
+                Path downloaded = Paths.get("barf.txt");
+                if (Files.size(downloaded) != fileContents.length()) {
+                    throw new RuntimeException("Size mismatch");
+                }
+                break;
+            case "InputStream":
+                InputStream is = response.body(asInputStream());
+                byte arr1[] = new byte[1024];
+                int byteRead;
+                StringBuilder sb = new StringBuilder();
+                while ((byteRead = is.read(arr1)) != -1) {
+                    sb.append(new String(arr1, 0, byteRead));
+                }
+                if (!sb.toString().equals(fileContents)) {
+                    throw new RuntimeException();
+                }
+                break;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ImmutableHeaders.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm ImmutableHeaders
+ * @summary ImmutableHeaders
+ */
+
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.Headers;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.List;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+public class ImmutableHeaders {
+
+    final static String RESPONSE = "Hello world";
+
+    public static void main(String[] args) throws Exception {
+        HttpServer server = HttpServer.create(new InetSocketAddress(0), 10);
+        ExecutorService e = Executors.newCachedThreadPool();
+        Handler h = new Handler();
+        HttpContext serverContext = server.createContext("/test", h);
+        int port = server.getAddress().getPort();
+        System.out.println("Server port = " + port);
+
+        server.setExecutor(e);
+        server.start();
+        HttpClient client = HttpClient.create()
+                                      .build();
+
+        try {
+            URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/test/foo");
+            HttpRequest req = client.request(uri)
+                .headers("X-Foo", "bar")
+                .headers("X-Bar", "foo")
+                .GET();
+
+            try {
+                HttpHeaders hd = req.headers();
+                List<String> v = hd.allValues("X-Foo");
+                if (!v.get(0).equals("bar"))
+                    throw new RuntimeException("Test failed");
+                v.add("XX");
+                throw new RuntimeException("Test failed");
+            } catch (UnsupportedOperationException ex) {
+            }
+            HttpResponse resp = req.response();
+            try {
+                HttpHeaders hd = resp.headers();
+                List<String> v = hd.allValues("X-Foo-Response");
+                if (!v.get(0).equals("resp"))
+                    throw new RuntimeException("Test failed");
+                v.add("XX");
+                throw new RuntimeException("Test failed");
+            } catch (UnsupportedOperationException ex) {
+            }
+
+        } finally {
+            client.executorService().shutdownNow();
+            server.stop(0);
+            e.shutdownNow();
+        }
+        System.out.println("OK");
+    }
+
+   static class Handler implements HttpHandler {
+
+        @Override
+        public void handle(HttpExchange he) throws IOException {
+            String method = he.getRequestMethod();
+            InputStream is = he.getRequestBody();
+            Headers h = he.getResponseHeaders();
+            h.add("X-Foo-Response", "resp");
+            he.sendResponseHeaders(200, RESPONSE.length());
+            OutputStream os = he.getResponseBody();
+            os.write(RESPONSE.getBytes(US_ASCII));
+            os.close();
+        }
+
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/LightWeightHttpServer.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ */
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.net.ssl.SSLContext;
+import jdk.testlibrary.SimpleSSLContext;
+
+public class LightWeightHttpServer {
+
+    static SSLContext ctx;
+    static HttpServer httpServer;
+    static HttpsServer httpsServer;
+    static ExecutorService executor;
+    static int port;
+    static int httpsport;
+    static String httproot;
+    static String httpsroot;
+    static ProxyServer proxy;
+    static int proxyPort;
+    static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure;
+    static RedirectHandler redirectHandler, redirectHandlerSecure;
+    static DelayHandler delayHandler;
+    static final String midSizedFilename = "/files/notsobigfile.txt";
+    static final String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+
+    public static void initServer() throws IOException {
+
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+
+        String root = System.getProperty("test.src") + "/docs";
+        InetSocketAddress addr = new InetSocketAddress(0);
+        httpServer = HttpServer.create(addr, 0);
+        if (httpServer instanceof HttpsServer) {
+            throw new RuntimeException("should not be httpsserver");
+        }
+        httpsServer = HttpsServer.create(addr, 0);
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = httpServer.createContext("/files", h);
+        HttpContext c2 = httpsServer.createContext("/files", h);
+        HttpContext c3 = httpServer.createContext("/echo", new EchoHandler());
+        redirectHandler = new RedirectHandler("/redirect");
+        redirectHandlerSecure = new RedirectHandler("/redirect");
+        HttpContext c4 = httpServer.createContext("/redirect", redirectHandler);
+        HttpContext c41 = httpsServer.createContext("/redirect", redirectHandlerSecure);
+        HttpContext c5 = httpsServer.createContext("/echo", new EchoHandler());
+        HttpContext c6 = httpServer.createContext("/keepalive", new KeepAliveHandler());
+        redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
+        redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
+        HttpContext c7 = httpServer.createContext("/redirecterror", redirectErrorHandler);
+        HttpContext c71 = httpsServer.createContext("/redirecterror", redirectErrorHandlerSecure);
+        delayHandler = new DelayHandler();
+        HttpContext c8 = httpServer.createContext("/delay", delayHandler);
+        HttpContext c81 = httpsServer.createContext("/delay", delayHandler);
+
+        executor = Executors.newCachedThreadPool();
+        httpServer.setExecutor(executor);
+        httpsServer.setExecutor(executor);
+        ctx = new SimpleSSLContext().get();
+        httpsServer.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        httpServer.start();
+        httpsServer.start();
+
+        port = httpServer.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httpsport = httpsServer.getAddress().getPort();
+        System.out.println("HTTPS server port = " + httpsport);
+        httproot = "http://127.0.0.1:" + port + "/";
+        httpsroot = "https://127.0.0.1:" + httpsport + "/";
+
+        proxy = new ProxyServer(0, false);
+        proxyPort = proxy.getPort();
+        System.out.println("Proxy port = " + proxyPort);
+    }
+
+    public static void stop() throws IOException {
+        if (httpServer != null) {
+            httpServer.stop(0);
+        }
+        if (httpsServer != null) {
+            httpsServer.stop(0);
+        }
+        if (proxy != null) {
+            proxy.close();
+        }
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+    }
+
+    static class RedirectErrorHandler implements HttpHandler {
+
+        String root;
+        volatile int count = 1;
+
+        RedirectErrorHandler(String root) {
+            this.root = root;
+        }
+
+        synchronized int count() {
+            return count;
+        }
+
+        synchronized void increment() {
+            count++;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+
+            Headers map = t.getResponseHeaders();
+            String redirect = root + "/foo/" + Integer.toString(count);
+            increment();
+            map.add("Location", redirect);
+            t.sendResponseHeaders(301, -1);
+            t.close();
+        }
+    }
+
+    static class RedirectHandler implements HttpHandler {
+
+        String root;
+        volatile int count = 0;
+
+        RedirectHandler(String root) {
+            this.root = root;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+
+            Headers map = t.getResponseHeaders();
+
+            if (count++ < 1) {
+                map.add("Location", root + "/foo/" + count);
+            } else {
+                map.add("Location", SmokeTest.midSizedFilename);
+            }
+            t.sendResponseHeaders(301, -1);
+            t.close();
+        }
+
+        int count() {
+            return count;
+        }
+
+        void reset() {
+            count = 0;
+        }
+    }
+
+    static class KeepAliveHandler implements HttpHandler {
+
+        volatile int counter = 0;
+        HashSet<Integer> portSet = new HashSet<>();
+        volatile int[] ports = new int[4];
+
+        void sleep(int n) {
+            try {
+                Thread.sleep(n);
+            } catch (InterruptedException e) {
+            }
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            int remotePort = t.getRemoteAddress().getPort();
+            String result = "OK";
+
+            int n = counter++;
+            /// First test
+            if (n < 4) {
+                ports[n] = remotePort;
+            }
+            if (n == 3) {
+                // check all values in ports[] are the same
+                if (ports[0] != ports[1] || ports[2] != ports[3]
+                        || ports[0] != ports[2]) {
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                }
+            }
+            // Second test
+            if (n >= 4 && n < 8) {
+                // delay to ensure ports are different
+                sleep(500);
+                ports[n - 4] = remotePort;
+            }
+            if (n == 7) {
+                // should be all different
+                if (ports[0] == ports[1] || ports[2] == ports[3]
+                        || ports[0] == ports[2]) {
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                    System.out.printf("Ports: %d, %d, %d, %d\n",
+                                      ports[0], ports[1], ports[2], ports[3]);
+                }
+                // setup for third test
+                for (int i = 0; i < 4; i++) {
+                    portSet.add(ports[i]);
+                }
+            }
+            // Third test
+            if (n > 7) {
+                // just check that port is one of the ones in portSet
+                if (!portSet.contains(remotePort)) {
+                    System.out.println("UNEXPECTED REMOTE PORT " + remotePort);
+                    result = "Error " + Integer.toString(n);
+                    System.out.println(result);
+                }
+            }
+            byte[] buf = new byte[2048];
+
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+            t.sendResponseHeaders(200, result.length());
+            OutputStream o = t.getResponseBody();
+            o.write(result.getBytes("US-ASCII"));
+            t.close();
+        }
+    }
+
+    static class DelayHandler implements HttpHandler {
+
+        CyclicBarrier bar1 = new CyclicBarrier(2);
+        CyclicBarrier bar2 = new CyclicBarrier(2);
+        CyclicBarrier bar3 = new CyclicBarrier(2);
+
+        CyclicBarrier barrier1() {
+            return bar1;
+        }
+
+        CyclicBarrier barrier2() {
+            return bar2;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange he) throws IOException {
+            byte[] buf = Util.readAll(he.getRequestBody());
+            try {
+                bar1.await();
+                bar2.await();
+            } catch (InterruptedException | BrokenBarrierException e) {
+            }
+            he.sendResponseHeaders(200, -1); // will probably fail
+            he.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ManyRequests.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm ManyRequests
+ * @summary Send a large number of requests asynchronously
+ */
+
+//package javaapplication16;
+
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLContext;
+import jdk.testlibrary.SimpleSSLContext;
+
+public class ManyRequests {
+
+    public static void main(String[] args) throws Exception {
+        SSLContext ctx = new SimpleSSLContext().get();
+
+        InetSocketAddress addr = new InetSocketAddress(0);
+        HttpsServer server = HttpsServer.create(addr, 0);
+        server.setHttpsConfigurator(new HttpsConfigurator(ctx));
+
+        HttpClient client = HttpClient.create()
+                                      .sslContext(ctx)
+                                      .build();
+        try {
+            test(server, client);
+            System.out.println("OK");
+        } finally {
+            server.stop(0);
+            client.executorService().shutdownNow();
+        }
+    }
+
+    static final int REQUESTS = 1000;
+
+    static void test(HttpsServer server, HttpClient client) throws Exception {
+        int port = server.getAddress().getPort();
+        URI uri = new URI("https://127.0.0.1:" + port + "/foo/x");
+        server.createContext("/foo", new EchoHandler());
+        server.start();
+
+        RequestLimiter limiter = new RequestLimiter(40);
+        Random rand = new Random();
+        CompletableFuture<Void>[] results = new CompletableFuture[REQUESTS];
+        HashMap<HttpRequest,byte[]> bodies = new HashMap<>();
+
+        for (int i=0; i<REQUESTS; i++) {
+            byte[] buf = new byte[i+1];  // different size bodies
+            rand.nextBytes(buf);
+            HttpRequest r = client.request(uri)
+                                  .body(HttpRequest.fromByteArray(buf))
+                                  .POST();
+            bodies.put(r, buf);
+
+            results[i] =
+                limiter.whenOkToSend()
+                       .thenCompose((v) -> r.responseAsync())
+                       .thenCompose((resp) -> {
+                           limiter.requestComplete();
+                           if (resp.statusCode() != 200) {
+                               resp.bodyAsync(HttpResponse.ignoreBody());
+                               String s = "Expected 200, got: " + resp.statusCode();
+                               return completedWithIOException(s);
+                           }
+                           return resp.bodyAsync(HttpResponse.asByteArray())
+                                      .thenApply((b) -> new Pair<>(resp, b));
+                       })
+                      .thenAccept((pair) -> {
+                          HttpRequest request = pair.t.request();
+                          byte[] requestBody = bodies.get(request);
+                          check(Arrays.equals(requestBody, pair.u),
+                                "bodies not equal");
+
+                      });
+        }
+        // wait for them all to complete and throw exception in case of error
+        CompletableFuture.allOf(results).join();
+    }
+
+    static <T> CompletableFuture<T> completedWithIOException(String message) {
+        CompletableFuture<T> cf = new CompletableFuture<>();
+        cf.completeExceptionally(new IOException(message));
+        return cf;
+    }
+
+    static final class Pair<T,U> {
+        Pair(T t, U u) {
+            this.t = t; this.u = u;
+        }
+        T t;
+        U u;
+    }
+
+    /**
+     * A simple limiter for controlling the number of requests to be run in
+     * parallel whenOkToSend() is called which returns a CF<Void> that allows
+     * each individual request to proceed, or block temporarily (blocking occurs
+     * on the waiters list here. As each request actually completes
+     * requestComplete() is called to notify this object, and allow some
+     * requests to continue.
+     */
+    static class RequestLimiter {
+
+        static final CompletableFuture<Void> COMPLETED_FUTURE =
+                CompletableFuture.completedFuture(null);
+
+        final int maxnumber;
+        final LinkedList<CompletableFuture<Void>> waiters;
+        int number;
+        boolean blocked;
+
+        RequestLimiter(int maximum) {
+            waiters = new LinkedList<>();
+            maxnumber = maximum;
+        }
+
+        synchronized void requestComplete() {
+            number--;
+            // don't unblock until number of requests has halved.
+            if ((blocked && number <= maxnumber / 2) ||
+                        (!blocked && waiters.size() > 0)) {
+                int toRelease = Math.min(maxnumber - number, waiters.size());
+                for (int i=0; i<toRelease; i++) {
+                    CompletableFuture<Void> f = waiters.remove();
+                    number ++;
+                    f.complete(null);
+                }
+                blocked = number >= maxnumber;
+            }
+        }
+
+        synchronized CompletableFuture<Void> whenOkToSend() {
+            if (blocked || number + 1 >= maxnumber) {
+                blocked = true;
+                CompletableFuture<Void> r = new CompletableFuture<>();
+                waiters.add(r);
+                return r;
+            } else {
+                number++;
+                return COMPLETED_FUTURE;
+            }
+        }
+    }
+
+    static void check(boolean cond, Object... msg) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : msg)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/ProxyServer.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+
+/**
+ * A minimal proxy server that supports CONNECT tunneling. It does not do
+ * any header transformations. In future this could be added.
+ * Two threads are created per client connection. So, it's not
+ * intended for large numbers of parallel connections.
+ */
+public class ProxyServer extends Thread implements Closeable {
+
+    ServerSocket listener;
+    int port;
+    volatile boolean debug;
+
+    /**
+     * Create proxy on port (zero means don't care). Call getPort()
+     * to get the assigned port.
+     */
+    public ProxyServer(Integer port) throws IOException {
+        this(port, false);
+    }
+
+    public ProxyServer(Integer port, Boolean debug) throws IOException {
+        this.debug = debug;
+        listener = new ServerSocket(port);
+        this.port = listener.getLocalPort();
+        setName("ProxyListener");
+        setDaemon(true);
+        connections = new LinkedList<>();
+        start();
+    }
+
+    public ProxyServer(String s) {  }
+
+    /**
+     * Returns the port number this proxy is listening on
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Shuts down the proxy, probably aborting any connections
+     * currently open
+     */
+    public void close() throws IOException {
+        if (debug) System.out.println("Proxy: closing");
+            done = true;
+        listener.close();
+        for (Connection c : connections) {
+            if (c.running()) {
+                c.close();
+            }
+        }
+    }
+
+    List<Connection> connections;
+
+    volatile boolean done;
+
+    public void run() {
+        if (System.getSecurityManager() == null) {
+            execute();
+        } else {
+            // so calling domain does not need to have socket permission
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    execute();
+                    return null;
+                }
+            });
+        }
+    }
+
+    public void execute() {
+        try {
+            while(!done) {
+                Socket s = listener.accept();
+                if (debug)
+                    System.out.println("Client: " + s);
+                Connection c = new Connection(s);
+                connections.add(c);
+            }
+        } catch(Throwable e) {
+            if (debug && !done) {
+                System.out.println("Fatal error: Listener: " + e);
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Transparently forward everything, once we know what the destination is
+     */
+    class Connection {
+
+        Socket clientSocket, serverSocket;
+        Thread out, in;
+        volatile InputStream clientIn, serverIn;
+        volatile OutputStream clientOut, serverOut;
+
+        boolean forwarding = false;
+
+        final static int CR = 13;
+        final static int LF = 10;
+
+        Connection(Socket s) throws IOException {
+            this.clientSocket= s;
+            this.clientIn = new BufferedInputStream(s.getInputStream());
+            this.clientOut = s.getOutputStream();
+            init();
+        }
+
+        byte[] readHeaders(InputStream is) throws IOException {
+            byte[] outbuffer = new byte[8000];
+            int crlfcount = 0;
+            int bytecount = 0;
+            int c;
+            while ((c=is.read()) != -1 && bytecount < outbuffer.length) {
+                outbuffer[bytecount++] = (byte)c;
+                if (debug) System.out.write(c);
+                // were looking for CRLFCRLF sequence
+                if (c == CR || c == LF) {
+                    switch(crlfcount) {
+                        case 0:
+                            if (c == CR) crlfcount ++;
+                            break;
+                        case 1:
+                            if (c == LF) crlfcount ++;
+                            break;
+                        case 2:
+                            if (c == CR) crlfcount ++;
+                            break;
+                        case 3:
+                            if (c == LF) crlfcount ++;
+                            break;
+                    }
+                } else {
+                    crlfcount = 0;
+                }
+                if (crlfcount == 4) {
+                    break;
+                }
+            }
+            byte[] ret = new byte[bytecount];
+            System.arraycopy(outbuffer, 0, ret, 0, bytecount);
+            return ret;
+        }
+
+        boolean running() {
+            return out.isAlive() || in.isAlive();
+        }
+
+        public void close() throws IOException {
+            if (debug) System.out.println("Closing connection (proxy)");
+            if (serverSocket != null) serverSocket.close();
+            if (clientSocket != null) clientSocket.close();
+        }
+
+        int findCRLF(byte[] b) {
+            for (int i=0; i<b.length-1; i++) {
+                if (b[i] == CR && b[i+1] == LF) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        public void init() {
+            try {
+                byte[] buf = readHeaders(clientIn);
+                int p = findCRLF(buf);
+                if (p == -1) {
+                    close();
+                    return;
+                }
+                String cmd = new String(buf, 0, p, "US-ASCII");
+                String[] params = cmd.split(" ");
+                if (params[0].equals("CONNECT")) {
+                    doTunnel(params[1]);
+                } else {
+                    doProxy(params[1], buf, p, cmd);
+                }
+            } catch (IOException e) {
+                if (debug) {
+                    System.out.println (e);
+                }
+                try {close(); } catch (IOException e1) {}
+            }
+        }
+
+        void doProxy(String dest, byte[] buf, int p, String cmdLine)
+            throws IOException
+        {
+            try {
+                URI uri = new URI(dest);
+                if (!uri.isAbsolute()) {
+                    throw new IOException("request URI not absolute");
+                }
+                dest = uri.getAuthority();
+                // now extract the path from the URI and recreate the cmd line
+                int sp = cmdLine.indexOf(' ');
+                String method = cmdLine.substring(0, sp);
+                cmdLine = method + " " + uri.getPath() + " HTTP/1.1";
+                int x = cmdLine.length() - 1;
+                int i = p;
+                while (x >=0) {
+                    buf[i--] = (byte)cmdLine.charAt(x--);
+                }
+                i++;
+
+                commonInit(dest, 80);
+                serverOut.write(buf, i, buf.length-i);
+                proxyCommon();
+
+            } catch (URISyntaxException e) {
+                throw new IOException(e);
+            }
+        }
+
+        void commonInit(String dest, int defaultPort) throws IOException {
+            int port;
+            String[] hostport = dest.split(":");
+            if (hostport.length == 1) {
+                port = defaultPort;
+            } else {
+                port = Integer.parseInt(hostport[1]);
+            }
+            if (debug) System.out.printf("Server: (%s/%d)\n", hostport[0], port);
+            serverSocket = new Socket(hostport[0], port);
+            serverOut = serverSocket.getOutputStream();
+
+            serverIn = new BufferedInputStream(serverSocket.getInputStream());
+        }
+
+        void proxyCommon() throws IOException {
+            out = new Thread(() -> {
+                try {
+                    byte[] bb = new byte[8000];
+                    int n;
+                    while ((n = clientIn.read(bb)) != -1) {
+                        serverOut.write(bb, 0, n);
+                    }
+                    serverSocket.close();
+                    clientSocket.close();
+                } catch (IOException e) {
+                    if (debug) {
+                        System.out.println (e);
+                    }
+                }
+            });
+            in = new Thread(() -> {
+                try {
+                    byte[] bb = new byte[8000];
+                    int n;
+                    while ((n = serverIn.read(bb)) != -1) {
+                        clientOut.write(bb, 0, n);
+                    }
+                    serverSocket.close();
+                    clientSocket.close();
+                } catch (IOException e) {
+                    if (debug) {
+                        System.out.println(e);
+                        e.printStackTrace();
+                    }
+                }
+            });
+            out.setName("Proxy-outbound");
+            out.setDaemon(true);
+            in.setDaemon(true);
+            in.setName("Proxy-inbound");
+            out.start();
+            in.start();
+        }
+
+        void doTunnel(String dest) throws IOException {
+            commonInit(dest, 443);
+            clientOut.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
+            proxyCommon();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        int port = Integer.parseInt(args[0]);
+        boolean debug = args.length > 1 && args[1].equals("-debug");
+        System.out.println("Debugging : " + debug);
+        ProxyServer ps = new ProxyServer(port, debug);
+        System.out.println("Proxy server listening on port " + ps.getPort());
+        while (true) {
+            Thread.sleep(5000);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/QuickResponses.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @test
+ * @bug 8087112
+ * @build Server
+ * @run main/othervm -Djava.net.HttpClient.log=all QuickResponses
+ */
+
+/**
+ * Tests the buffering of data on connections across multiple
+ * responses
+ */
+public class QuickResponses {
+
+    static Server server;
+
+    static String response(String body) {
+        return "HTTP/1.1 200 OK\r\nContent-length: " + Integer.toString(body.length())
+                + "\r\n\r\n" + body;
+    }
+
+    static final String responses[] = {
+        "Lorem ipsum",
+        "dolor sit amet",
+        "consectetur adipiscing elit, sed do eiusmod tempor",
+        "quis nostrud exercitation ullamco",
+        "laboris nisi",
+        "ut",
+        "aliquip ex ea commodo consequat." +
+        "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
+        "cillum dolore eu fugiat nulla pariatur.",
+        "Excepteur sint occaecat cupidatat non proident."
+    };
+
+    static String entireResponse() {
+        String s = "";
+        for (String r : responses) {
+            s += response(r);
+        }
+        return s;
+    }
+
+    public static void main(String[] args) throws Exception {
+        server = new Server(0);
+        URI uri = new URI(server.getURL());
+
+        HttpRequest request = HttpRequest.create(uri)
+                .GET();
+
+        CompletableFuture<HttpResponse> cf1 = request.responseAsync();
+        Server.Connection s1 = server.activity();
+        s1.send(entireResponse());
+
+
+        HttpResponse r = cf1.join();
+        if (r.statusCode()!= 200 || !r.body(HttpResponse.asString()).equals(responses[0]))
+            throw new RuntimeException("Failed on first response");
+
+        //now get the same identical response, synchronously to ensure same connection
+        int remaining = responses.length - 1;
+
+        for (int i=0; i<remaining; i++) {
+            r = HttpRequest.create(uri)
+                    .GET()
+                    .response();
+            if (r.statusCode()!= 200)
+                throw new RuntimeException("Failed");
+
+            String body = r.body(HttpResponse.asString());
+            if (!body.equals(responses[i+1]))
+                throw new RuntimeException("Failed");
+        }
+        HttpClient.getDefault().executorService().shutdownNow();
+        System.out.println("OK");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/RequestBodyTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm RequestBodyTest
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.Executors;
+import javax.net.ssl.SSLContext;
+
+public class RequestBodyTest {
+
+    final static String STRING = "string";
+    final static String BYTE_ARRAY = "byteArray";
+    final static String BYTE_ARRAYS = "byteArrays";
+    final static String BYTE_ARRAY_OFFSET = "byteArray_offset";
+    final static String FILE = "file";
+    final static String STRING_CHARSET = "string_charset";
+    final static String INPUTSTREAM = "InputStream";
+
+    final static String midSizedFilename = "/files/notsobigfile.txt";
+    final static String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+    static HttpClient client;
+    static SSLContext ctx;
+    static String httproot;
+    static String httpsroot;
+
+    public static void main(String args[]) throws Exception {
+        fileroot = System.getProperty("test.src") + "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+        //start the server
+        LightWeightHttpServer.initServer();
+
+        httproot = LightWeightHttpServer.httproot;
+        httpsroot = LightWeightHttpServer.httpsroot;
+        ctx = LightWeightHttpServer.ctx;
+        client = HttpClient.create().sslContext(ctx)
+                .followRedirects(HttpClient.Redirect.ALWAYS)
+                .executorService(Executors.newCachedThreadPool())
+                .build();
+
+        String TARGET = httproot + "echo/foo";
+        boolean isSync = false;
+        requestBodyTypes(TARGET, STRING, STRING, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, STRING, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, STRING, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAY, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAYS, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, FILE, isSync);
+
+        requestBodyTypes(TARGET, INPUTSTREAM, STRING, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, FILE, isSync);
+
+        requestBodyTypes(TARGET, FILE, STRING, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, FILE, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, FILE, FILE, isSync);
+
+        isSync = true;
+        requestBodyTypes(TARGET, STRING, STRING, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, STRING, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, STRING, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, STRING, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAY, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAY, FILE, isSync);
+
+        requestBodyTypes(TARGET, BYTE_ARRAYS, STRING, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, BYTE_ARRAYS, FILE, isSync);
+
+        requestBodyTypes(TARGET, INPUTSTREAM, STRING, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, INPUTSTREAM, FILE, isSync);
+
+        requestBodyTypes(TARGET, FILE, STRING, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAY, isSync);
+        requestBodyTypes(TARGET, FILE, BYTE_ARRAYS, isSync);
+        requestBodyTypes(TARGET, FILE, INPUTSTREAM, isSync);
+        requestBodyTypes(TARGET, FILE, FILE, isSync);
+
+    }
+
+    static void requestBodyTypes(final String target,
+                                 final String requestType,
+                                 final String responseType,
+                                 final boolean isAsync)
+        throws Exception
+    {
+        System.out.println("Running test_request_body_type " + requestType +
+                " and response type " + responseType + " and sync=" + isAsync);
+        URI uri = new URI(target);
+        byte buf[];
+        String filename = smallFile.toFile().getAbsolutePath();
+        String fileContents = HttpUtils.getFileContent(filename);
+        buf = fileContents.getBytes();
+        HttpRequest.Builder builder = HttpUtils.getHttpRequestBuilder(client,
+                                                                      requestType,
+                                                                      uri);
+        HttpResponse response;
+        if (!isAsync) {
+            response = builder.GET().response();
+        } else {
+            response = builder.GET().responseAsync().join();
+        }
+        HttpUtils.checkResponse(response, requestType, responseType);
+        System.out.println("OK");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/Server.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//package javaapplication16;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A cut-down Http/1 Server for testing various error situations
+ *
+ * use interrupt() to halt
+ */
+public class Server extends Thread {
+
+    ServerSocket ss;
+    List<Connection> sockets;
+    AtomicInteger counter = new AtomicInteger(0);
+
+    // waits up to 20 seconds for something to happen
+    // dont use this unless certain activity coming.
+    public Connection activity() {
+        for (int i = 0; i < 80 * 100; i++) {
+            for (Connection c : sockets) {
+                if (c.poll()) {
+                    return c;
+                }
+            }
+            try {
+                Thread.sleep(250);
+            } catch (InterruptedException e) {
+            }
+        }
+        return null;
+    }
+
+    // clears all current connections on Server.
+    public void reset() {
+        for (Connection c : sockets) {
+            c.close();
+        }
+    }
+
+    /**
+     * Reads data into an ArrayBlockingQueue<String> where each String
+     * is a line of input, that was terminated by CRLF (not included)
+     */
+    class Connection extends Thread {
+        Connection(Socket s) throws IOException {
+            this.socket = s;
+            id = counter.incrementAndGet();
+            is = s.getInputStream();
+            os = s.getOutputStream();
+            incoming = new ArrayBlockingQueue<>(100);
+            setName("Server-Connection");
+            setDaemon(true);
+            start();
+        }
+        final Socket socket;
+        final int id;
+        final InputStream is;
+        final OutputStream os;
+        final ArrayBlockingQueue<String> incoming;
+
+        final static String CRLF = "\r\n";
+
+        // sentinel indicating connection closed
+        final static String CLOSED = "C.L.O.S.E.D";
+        volatile boolean closed = false;
+
+        @Override
+        public void run() {
+            byte[] buf = new byte[256];
+            String s = "";
+            try {
+                while (true) {
+                    int n = is.read(buf);
+                    if (n == -1) {
+                        cleanup();
+                        return;
+                    }
+                    String s0 = new String(buf, 0, n, StandardCharsets.ISO_8859_1);
+                    s = s + s0;
+                    int i;
+                    while ((i=s.indexOf(CRLF)) != -1) {
+                        String s1 = s.substring(0, i+2);
+                        incoming.put(s1);
+                        if (i+2 == s.length()) {
+                            s = "";
+                            break;
+                        }
+                        s = s.substring(i+2);
+                    }
+                }
+            } catch (IOException |InterruptedException e1) {
+                cleanup();
+            } catch (Throwable t) {
+                System.out.println("X: " + t);
+                cleanup();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Server.Connection: " + socket.toString();
+        }
+
+        public void sendHttpResponse(int code, String body, String... headers)
+            throws IOException
+        {
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            for (int i=0; i<headers.length; i+=2) {
+                r1 += headers[i] + ": " + headers[i+1] + CRLF;
+            }
+            int clen = body == null ? 0 : body.length();
+            r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
+            r1 += CRLF;
+            if (body != null) {
+                r1 += body;
+            }
+            send(r1);
+        }
+
+        // content-length is 10 bytes too many
+        public void sendIncompleteHttpResponseBody(int code) throws IOException {
+            String body = "Hello World Helloworld Goodbye World";
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            int clen = body.length() + 10;
+            r1 += "Content-Length: " + Integer.toString(clen) + CRLF;
+            r1 += CRLF;
+            if (body != null) {
+                r1 += body;
+            }
+            send(r1);
+        }
+
+        public void sendIncompleteHttpResponseHeaders(int code)
+            throws IOException
+        {
+            String r1 = "HTTP/1.1 " + Integer.toString(code) + " status" + CRLF;
+            send(r1);
+        }
+
+        public void send(String r) throws IOException {
+            os.write(r.getBytes(StandardCharsets.ISO_8859_1));
+        }
+
+        public synchronized void close() {
+            cleanup();
+            closed = true;
+            incoming.clear();
+        }
+
+        public String nextInput(long timeout, TimeUnit unit) {
+            String result = "";
+            while (poll()) {
+                try {
+                    String s = incoming.poll(timeout, unit);
+                    if (s == null && closed) {
+                        return CLOSED;
+                    } else {
+                        result += s;
+                    }
+                } catch (InterruptedException e) {
+                    return null;
+                }
+            }
+            return result;
+        }
+
+        public String nextInput() {
+            return nextInput(0, TimeUnit.SECONDS);
+        }
+
+        public boolean poll() {
+            return incoming.peek() != null;
+        }
+
+        private void cleanup() {
+            try {
+                socket.close();
+            } catch (IOException e) {}
+            sockets.remove(this);
+        }
+    }
+
+    Server(int port) throws IOException {
+        ss = new ServerSocket(port);
+        sockets = Collections.synchronizedList(new LinkedList<>());
+        setName("Test-Server");
+        setDaemon(true);
+        start();
+    }
+
+    Server() throws IOException {
+        this(0);
+    }
+
+    int port() {
+        return ss.getLocalPort();
+    }
+
+    public String getURL() {
+        return "http://127.0.0.1:" + port() + "/foo/";
+    }
+
+    public void close() {
+        try {
+            ss.close();
+        } catch (IOException e) {
+        }
+        for (Connection c : sockets) {
+            c.close();
+        }
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                Socket s = ss.accept();
+                Connection c = new Connection(s);
+                sockets.add(c);
+            } catch (IOException e) {
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/SmokeTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @compile ../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @run main/othervm SmokeTest
+ */
+
+//package javaapplication16;
+
+import com.sun.net.httpserver.*;
+import java.net.*;
+import java.net.http.*;
+import java.io.*;
+import java.util.concurrent.*;
+import javax.net.ssl.*;
+import java.nio.file.*;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import jdk.testlibrary.SimpleSSLContext;
+import static java.net.http.HttpRequest.*;
+import static java.net.http.HttpResponse.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * * Basic smoke test for Http/1.1 client
+ * - basic request response
+ * - request body POST
+ * - response body GET
+ * - redirect
+ * - chunked request/response
+ * - SSL
+ * - proxies
+ * - 100 continue
+ * - check keep alive appears to be working
+ * - cancel of long request
+ *
+ * Uses a FileServerHandler serving a couple of known files
+ * in docs directory.
+ */
+public class SmokeTest {
+    static SSLContext ctx;
+    static HttpServer s1 ;
+    static HttpsServer s2;
+    static ExecutorService executor;
+    static int port;
+    static int httpsport;
+    static String httproot;
+    static String httpsroot;
+    static HttpClient client;
+    static ProxyServer proxy;
+    static int proxyPort;
+    static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure;
+    static RedirectHandler redirectHandler, redirectHandlerSecure;
+    static DelayHandler delayHandler;
+    final static String midSizedFilename = "/files/notsobigfile.txt";
+    final static String smallFilename = "/files/smallfile.txt";
+    static Path midSizedFile;
+    static Path smallFile;
+    static String fileroot;
+
+    static String getFileContent(String path) throws IOException {
+        FileInputStream fis = new FileInputStream(path);
+        byte[] buf = new byte[2000];
+        StringBuilder sb = new StringBuilder();
+        int n;
+        while ((n=fis.read(buf)) != -1) {
+            sb.append(new String(buf, 0, n, "US-ASCII"));
+        }
+        return sb.toString();
+    }
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        fileroot = System.getProperty ("test.src", ".")+ "/docs";
+        midSizedFile = Paths.get(fileroot + midSizedFilename);
+        smallFile = Paths.get(fileroot + smallFilename);
+
+        client = HttpClient.create()
+                           .sslContext(ctx)
+                           .followRedirects(HttpClient.Redirect.ALWAYS)
+                           .executorService(Executors.newCachedThreadPool())
+                           .build();
+
+        try {
+            test1(httproot + "files/foo.txt", true);
+
+            test1(httproot + "files/foo.txt", false);
+            test1(httpsroot + "files/foo.txt", true);
+            test1(httpsroot + "files/foo.txt", false);
+            test2(httproot + "echo/foo", "This is a short test");
+            test2(httpsroot + "echo/foo", "This is a short test");
+
+            test3(httproot + "redirect/foo.txt");
+            test3(httpsroot + "redirect/foo.txt");
+            test4(httproot + "files/foo.txt");
+            test4(httpsroot + "files/foo.txt");
+            test5(httproot + "echo/foo", true);
+            test5(httpsroot + "echo/foo", true);
+            test5(httproot + "echo/foo", false);
+            test5(httpsroot + "echo/foo", false);
+
+            test6(httproot + "echo/foo", true);
+            test6(httpsroot + "echo/foo", true);
+            test6(httproot + "echo/foo", false);
+            test6(httpsroot + "echo/foo", false);
+
+            test7(httproot + "keepalive/foo");
+
+            test8(httproot + "files/foo.txt", true);
+            test8(httproot + "files/foo.txt", false);
+            test8(httpsroot + "files/foo.txt", true);
+            test8(httpsroot + "files/foo.txt", false);
+            // disabled test9();
+
+            test10(httproot + "redirecterror/foo.txt");
+
+            test10(httpsroot + "redirecterror/foo.txt");
+
+            test11(httproot + "echo/foo");
+            test11(httpsroot + "echo/foo");
+            //test12(httproot + "delay/foo", delayHandler);
+
+        } finally {
+            s1.stop(0);
+            s2.stop(0);
+            proxy.close();
+            executor.shutdownNow();
+            client.executorService().shutdownNow();
+        }
+    }
+
+    static class Auth extends java.net.Authenticator {
+        volatile int count = 0;
+        @Override
+        protected PasswordAuthentication getPasswordAuthentication() {
+            if (count++ == 0) {
+                return new PasswordAuthentication("user", "passwd".toCharArray());
+            } else {
+                return new PasswordAuthentication("user", "goober".toCharArray());
+            }
+        }
+        int count() {
+            return count;
+        }
+    }
+
+    // Basic test
+    static void test1(String target, boolean fixedLen) throws Exception {
+        System.out.print("test1: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                             .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        String body = response.body(asString());
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException();
+        }
+
+        // repeat async
+        response = builder.GET().responseAsync().join();
+
+        body = response.body(asString());
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException();
+        }
+        System.out.println(" OK");
+    }
+
+    // POST use echo to check reply
+    static void test2(String s, String body) throws Exception {
+        System.out.print("test2: " + s);
+        URI uri = new URI(s);
+
+        HttpResponse response = client.request(uri)
+                                       .body(fromString(body))
+                                       .POST()
+                                       .response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                "Expected 200, got [ " + response.statusCode() + " ]");
+        }
+        String reply = response.body(asString());
+        if (!reply.equals(body)) {
+            throw new RuntimeException(
+                "Body mismatch: expected [" + body + "], got [" + reply + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    // Redirect
+    static void test3(String s) throws Exception {
+        System.out.print("test3: " + s);
+        URI uri = new URI(s);
+        RedirectHandler handler = uri.getScheme().equals("https")
+                ? redirectHandlerSecure : redirectHandler;
+
+        HttpResponse response = client.request(uri)
+                                      .body(noBody())
+                                      .GET()
+                                      .response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                "Expected 200, got [ " + response.statusCode() + " ]");
+        } else {
+            response.body(HttpResponse.asFile(Paths.get("redir1.txt")));
+        }
+
+        Path downloaded = Paths.get("redir1.txt");
+        if (Files.size(downloaded) != Files.size(midSizedFile)) {
+            throw new RuntimeException("Size mismatch");
+        }
+
+        System.out.printf(" (count: %d) ", handler.count());
+        // repeat with async api
+
+        handler.reset();
+
+        response = client.request(uri)
+                         .body(noBody())
+                         .GET()
+                         .responseAsync()
+                         .join();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                    "Expected 200, got [ " + response.statusCode() + " ]");
+        } else {
+            response.body(HttpResponse.asFile(Paths.get("redir2.txt")));
+        }
+
+        downloaded = Paths.get("redir2.txt");
+        if (Files.size(downloaded) != Files.size(midSizedFile)) {
+            throw new RuntimeException("Size mismatch 2");
+        }
+        System.out.printf(" (count: %d) ", handler.count());
+        System.out.println(" OK");
+    }
+
+    // Proxies
+    static void test4(String s) throws Exception {
+        System.out.print("test4: " + s);
+        URI uri = new URI(s);
+        InetSocketAddress proxyAddr = new InetSocketAddress("127.0.0.1", proxyPort);
+        String filename = fileroot + uri.getPath();
+
+        HttpClient cl = HttpClient.create()
+                                  .proxy(ProxySelector.of(proxyAddr))
+                                  .sslContext(ctx)
+                                  .build();
+
+        CompletableFuture<String> fut = cl.request(uri)
+                                          .body(noBody())
+                                          .GET()
+                                          .responseAsync()
+                                          .thenCompose((HttpResponse response) ->
+                                                          response.bodyAsync(asString())
+                                          );
+
+        String body = fut.get(5, TimeUnit.HOURS);
+
+        String fc = getFileContent(filename);
+
+        if (!body.equals(fc)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + body + "], got [" + fc + "]");
+        }
+        cl.executorService().shutdownNow();
+        System.out.println(" OK");
+    }
+
+    // 100 Continue: use echo target
+    static void test5(String target, boolean fixedLen) throws Exception {
+        System.out.print("test5: " + target);
+        URI uri = new URI(target);
+        String requestBody = generateString(12 * 1024 + 13);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .expectContinue(true)
+                                            .body(fromString(requestBody));
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        String body = response.body(asString());
+
+        if (!body.equals(requestBody)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + body + "], got [" + body + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    // use echo
+    static void test6(String target, boolean fixedLen) throws Exception {
+        System.out.print("test6: " + target);
+        URI uri = new URI(target);
+        String requestBody = generateString(12 * 1024 + 3);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException(
+                    "Expected 200, got [ " + response.statusCode() + " ]");
+        }
+
+        String responseBody = response.body(asString());
+
+        if (responseBody.equals(requestBody)) {
+            throw new RuntimeException(
+                    "Body mismatch: expected [" + requestBody + "], got [" + responseBody + "]");
+        }
+        System.out.println(" OK");
+    }
+
+    @SuppressWarnings("rawtypes")
+    static void test7(String target) throws Exception {
+        System.out.print("test7: " + target);
+
+        // First test
+        URI uri = new URI(target);
+        for (int i=0; i<4; i++) {
+            HttpResponse r = client.request(uri)
+                                   .body(noBody())
+                                   .GET()
+                                   .response();
+            String body = r.body(asString());
+            if (!body.equals("OK")) {
+                throw new RuntimeException("Expected OK, got: " + body);
+            }
+        }
+
+        // Second test: 4 x parallel
+        List<CompletableFuture<HttpResponse>> futures = new LinkedList<>();
+        for (int i=0; i<4; i++) {
+            futures.add(client.request(uri)
+                              .body(noBody())
+                              .GET()
+                              .responseAsync());
+        }
+        // all sent?
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                         .join();
+
+        List<CompletableFuture<String>> futureBodies = new LinkedList<>();
+        for (int i=0; i<4; i++) {
+            futureBodies.add(futures.get(i)
+                                    .join()
+                                    .bodyAsync(asString()));
+        }
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
+                         .join();
+
+        for (CompletableFuture<String> future : futureBodies) {
+            String body = future.get();
+            if (!body.equals("OK")) {
+                throw new RuntimeException("Expected OK, got: " + body);
+            }
+        }
+
+        // Third test: Multiple of 4 parallel requests
+        BlockingQueue<String> q = new LinkedBlockingQueue<>();
+        for (int i=0; i<4; i++) {
+            client.request(uri)
+                  .body(noBody())
+                  .GET()
+                  .responseAsync()
+                  .thenApply((HttpResponse resp) -> {
+                      String body = resp.body(asString());
+                      putQ(q, body);
+                      return body;
+                  });
+        }
+        // we've sent four requests. Now, just send another request
+        // as each response is received. The idea is to ensure that
+        // only four sockets ever get used.
+
+        for (int i=0; i<100; i++) {
+            // block until response received
+            String body = takeQ(q);
+            if (!body.equals("OK")) {
+                throw new RuntimeException(body);
+            }
+            client.request(uri)
+                  .body(noBody())
+                  .GET()
+                  .responseAsync()
+                  .thenApply((HttpResponse resp) -> {
+                      String body1 = resp.body(asString());
+                      putQ(q, body1);
+                      return body1;
+                  });
+        }
+        // should be four left
+        for (int i=0; i<4; i++) {
+            takeQ(q);
+        }
+        System.out.println(" OK");
+    }
+
+    static String takeQ(BlockingQueue<String> q) {
+        String r = null;
+        try {
+            r = q.take();
+        } catch (InterruptedException e) {}
+
+        return r;
+    }
+
+    static void putQ(BlockingQueue<String> q, String o) {
+        try {
+            q.put(o);
+        } catch (InterruptedException e) {
+            // can't happen
+        }
+    }
+
+    static void test8(String target, boolean fixedLen) throws Exception {
+        System.out.print("test8: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(noBody());
+
+        if (fixedLen) {
+            builder.header("XFixed", "yes");
+        }
+
+        HttpResponse response = builder.GET().response();
+
+        StringBuilder sb = new StringBuilder();
+
+        InputStream is = response.body(asInputStream());
+        int c;
+        byte[] buf = new byte[2048];
+        while ((c = is.read(buf)) != -1) {
+            for (int i=0; i<c; i++)
+                sb.append((char)buf[i]);
+        }
+        is.close();
+        String body = sb.toString();
+
+        if (!body.equals("This is foo.txt\r\n")) {
+            throw new RuntimeException("Expected \"This is foo.txt\", got: " + body);
+        }
+        System.out.println(" OK");
+    }
+
+    // Chunked output stream
+    static void test11(String target) throws Exception {
+        System.out.print("test11: " + target);
+        URI uri = new URI(target);
+
+        FileInputStream file = new FileInputStream(smallFile.toFile());
+
+        HttpRequest.Builder builder = client.request(uri)
+                                            .body(HttpRequest.fromInputStream(file));
+        HttpResponse response = builder.POST().response();
+
+        if (response.statusCode() != 200) {
+            throw new RuntimeException("Wrong response code");
+        }
+
+        Path download = Paths.get("test11.txt");
+        download.toFile().delete();
+        response.body(HttpResponse.asFile(download));
+
+        if (Files.size(download) != Files.size(smallFile)) {
+            System.out.println("Original size: " + Files.size(smallFile));
+            System.out.println("Downloaded size: " + Files.size(download));
+            throw new RuntimeException("Size mismatch");
+        }
+        System.out.println(" OK");
+    }
+
+    // cancel
+    /*
+    static void test12(String target, DelayHandler h) throws Exception {
+        System.out.print("test12: " + target);
+        URI uri = new URI(target);
+
+        HttpRequest.Builder builder = client
+            .request(uri)
+            .body(HttpRequest.fromString("Hello world"));
+
+        HttpRequest request = builder
+                .GET();
+        request.sendAsync();
+        h.barrier1().await();
+        // request has been processed
+        CompletableFuture<HttpResponse> cf = request.responseAsync();
+        request.cancel();
+        h.barrier2().await();
+        try {
+            HttpResponse r = cf.get();
+            throw new RuntimeException("failed 2");
+        } catch (Exception e) {
+        }
+        System.out.println(" OK");
+    }
+*/
+    static void delay(int seconds) {
+        try {
+            Thread.sleep(seconds * 1000);
+        } catch (InterruptedException e) {
+        }
+    }
+/*
+    // test won't work until sending fully decoupled from receiving in impl
+    static void test9() throws Exception {
+        System.out.print("test9: ");
+        UploadServer up = new UploadServer(1000 * 1000);
+        int size = up.size();
+        String u = "http://127.0.0.1:" + up.port() + "/";
+        URI uri = new URI(u);
+
+        HttpRequest request = client
+            .request(uri)
+            .body(new HttpRequestBodyProcessor() {
+                @Override
+                public ByteBuffer onRequestBodyChunk(ByteBuffer b) throws IOException {
+                    // slow things down
+                    delay(1);
+                    b.position(b.limit()); // fill it
+                    return b;
+                }
+                @Override
+                public long onRequestStart(HttpRequest req) throws IOException {
+                    return size;
+                }
+             })
+            .PUT();
+
+        CompletableFuture<HttpRequest> cf1 = request.sendAsync();
+        CompletableFuture<HttpResponse> cf = request.responseAsync();
+
+        HttpResponse resp = cf.get(1, TimeUnit.MINUTES);
+        if (resp.statusCode() != 201) {
+            throw new RuntimeException("failed: wrong response code");
+        }
+        delay(2); // allow some data to be sent
+        request.cancel();
+        delay(1);
+        if (up.failed()) {
+            throw new RuntimeException("failed to cancel request");
+        }
+        System.out.println(" OK");
+    }
+  */
+    // Redirect loop: return an error after a certain number of redirects
+    static void test10(String s) throws Exception {
+        System.out.print("test10: " + s);
+        URI uri = new URI(s);
+        RedirectErrorHandler handler = uri.getScheme().equals("https")
+                ? redirectErrorHandlerSecure : redirectErrorHandler;
+
+        CompletableFuture<HttpResponse> cf = client.request(uri)
+                                                   .body(noBody())
+                                                   .GET()
+                                                   .responseAsync();
+
+        try {
+            HttpResponse response = cf.join();
+            throw new RuntimeException("Exepected Completion Exception");
+        } catch (CompletionException e) {
+            //System.out.println(e);
+        }
+
+        System.out.printf(" (Calls %d) ", handler.count());
+        System.out.println(" OK");
+    }
+
+    static final int NUM = 50;
+
+    static Random random = new Random();
+    static final String alphabet = "ABCDEFGHIJKLMNOPQRST";
+
+    static char randomChar() {
+        return alphabet.charAt(random.nextInt(alphabet.length()));
+    }
+
+    static String generateString(int length) {
+        StringBuilder sb = new StringBuilder(length);
+        for (int i=0; i<length; i++) {
+            sb.append(randomChar());
+        }
+        return sb.toString();
+    }
+
+    static void initServer() throws Exception {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        s2 = HttpsServer.create (addr, 0);
+        HttpHandler h = new FileServerHandler(root);
+
+        HttpContext c1 = s1.createContext("/files", h);
+        HttpContext c2 = s2.createContext("/files", h);
+        HttpContext c3 = s1.createContext("/echo", new EchoHandler());
+        redirectHandler = new RedirectHandler("/redirect");
+        redirectHandlerSecure = new RedirectHandler("/redirect");
+        HttpContext c4 = s1.createContext("/redirect", redirectHandler);
+        HttpContext c41 = s2.createContext("/redirect", redirectHandlerSecure);
+        HttpContext c5 = s2.createContext("/echo", new EchoHandler());
+        HttpContext c6 = s1.createContext("/keepalive", new KeepAliveHandler());
+        redirectErrorHandler = new RedirectErrorHandler("/redirecterror");
+        redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror");
+        HttpContext c7 = s1.createContext("/redirecterror", redirectErrorHandler);
+        HttpContext c71 = s2.createContext("/redirecterror", redirectErrorHandlerSecure);
+        delayHandler = new DelayHandler();
+        HttpContext c8 = s1.createContext("/delay", delayHandler);
+        HttpContext c81 = s2.createContext("/delay", delayHandler);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor(executor);
+        s2.setExecutor(executor);
+        ctx = new SimpleSSLContext().get();
+        s2.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        s1.start();
+        s2.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httpsport = s2.getAddress().getPort();
+        System.out.println("HTTPS server port = " + httpsport);
+        httproot = "http://127.0.0.1:" + port + "/";
+        httpsroot = "https://127.0.0.1:" + httpsport + "/";
+
+        proxy = new ProxyServer(0, false);
+        proxyPort = proxy.getPort();
+        System.out.println("Proxy port = " + proxyPort);
+    }
+}
+
+class UploadServer extends Thread {
+    int statusCode;
+    ServerSocket ss;
+    int port;
+    int size;
+    Object lock;
+    boolean failed = false;
+
+    UploadServer(int size) throws IOException {
+        this.statusCode = statusCode;
+        this.size = size;
+        ss = new ServerSocket(0);
+        port = ss.getLocalPort();
+        lock = new Object();
+    }
+
+    int port() {
+          return port;
+    }
+
+    int size() {
+          return size;
+    }
+
+    // wait a sec before calling this
+    boolean failed() {
+        synchronized(lock) {
+            return failed;
+        }
+    }
+
+    @Override
+    public void run () {
+        int nbytes = 0;
+        Socket s = null;
+
+        synchronized(lock) {
+            try {
+                s = ss.accept();
+
+                InputStream is = s.getInputStream();
+                OutputStream os = s.getOutputStream();
+                os.write("HTTP/1.1 201 OK\r\nContent-length: 0\r\n\r\n".getBytes());
+                int n;
+                byte[] buf = new byte[8000];
+                while ((n=is.read(buf)) != -1) {
+                    nbytes += n;
+                }
+            } catch (IOException e) {
+                System.out.println ("read " + nbytes);
+                System.out.println ("size " + size);
+                failed = nbytes >= size;
+            } finally {
+                try {
+                    ss.close();
+                    if (s != null)
+                        s.close();
+                } catch (IOException e) {}
+            }
+        }
+    }
+}
+
+class RedirectHandler implements HttpHandler {
+    String root;
+    volatile int count = 0;
+
+    RedirectHandler(String root) {
+        this.root = root;
+    }
+
+    @Override
+    public synchronized void handle(HttpExchange t)
+        throws IOException
+    {
+        byte[] buf = new byte[2048];
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+
+        Headers responseHeaders = t.getResponseHeaders();
+
+        if (count++ < 1) {
+            responseHeaders.add("Location", root + "/foo/" + count);
+        } else {
+            responseHeaders.add("Location", SmokeTest.midSizedFilename);
+        }
+        t.sendResponseHeaders(301, -1);
+        t.close();
+    }
+
+    int count() {
+        return count;
+    }
+
+    void reset() {
+        count = 0;
+    }
+}
+
+class RedirectErrorHandler implements HttpHandler {
+    String root;
+    volatile int count = 1;
+
+    RedirectErrorHandler(String root) {
+        this.root = root;
+    }
+
+    synchronized int count() {
+        return count;
+    }
+
+    synchronized void increment() {
+        count++;
+    }
+
+    @Override
+    public synchronized void handle (HttpExchange t)
+        throws IOException
+    {
+        byte[] buf = new byte[2048];
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+
+        Headers map = t.getResponseHeaders();
+        String redirect = root + "/foo/" + Integer.toString(count);
+        increment();
+        map.add("Location", redirect);
+        t.sendResponseHeaders(301, -1);
+        t.close();
+    }
+}
+
+class Util {
+    static byte[] readAll(InputStream is) throws IOException {
+        byte[] buf = new byte[1024];
+        byte[] result = new byte[0];
+
+        while (true) {
+            int n = is.read(buf);
+            if (n > 0) {
+                byte[] b1 = new byte[result.length + n];
+                System.arraycopy(result, 0, b1, 0, result.length);
+                System.arraycopy(buf, 0, b1, result.length, n);
+                result = b1;
+            } else if (n == -1) {
+                return result;
+            }
+        }
+    }
+}
+
+class DelayHandler implements HttpHandler {
+
+    CyclicBarrier bar1 = new CyclicBarrier(2);
+    CyclicBarrier bar2 = new CyclicBarrier(2);
+    CyclicBarrier bar3 = new CyclicBarrier(2);
+
+    CyclicBarrier barrier1() {
+        return bar1;
+    }
+
+    CyclicBarrier barrier2() {
+        return bar2;
+    }
+
+    @Override
+    public synchronized void handle(HttpExchange he) throws IOException {
+        byte[] buf = Util.readAll(he.getRequestBody());
+        try {
+            bar1.await();
+            bar2.await();
+        } catch (Exception e) {}
+        he.sendResponseHeaders(200, -1); // will probably fail
+        he.close();
+    }
+
+}
+
+// check for simple hardcoded sequence and use remote address
+// to check.
+// First 4 requests executed in sequence (should use same connection/address)
+// Next 4 requests parallel (should use different addresses)
+// Then send 4 requests in parallel x 100 times (same four addresses used all time)
+
+class KeepAliveHandler implements HttpHandler {
+    volatile int counter = 0;
+
+    HashSet<Integer> portSet = new HashSet<>();
+
+    volatile int[] ports = new int[4];
+
+    void sleep(int n) {
+        try {
+            Thread.sleep(n);
+        } catch (InterruptedException e) {}
+    }
+
+    @Override
+    public synchronized void handle (HttpExchange t)
+        throws IOException
+    {
+        int remotePort = t.getRemoteAddress().getPort();
+        String result = "OK";
+
+        int n = counter++;
+        /// First test
+        if (n < 4) {
+            ports[n] = remotePort;
+        }
+        if (n == 3) {
+            // check all values in ports[] are the same
+            if (ports[0] != ports[1] || ports[2] != ports[3]
+                    || ports[0] != ports[2]) {
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+            }
+        }
+        // Second test
+        if (n >=4 && n < 8) {
+            // delay to ensure ports are different
+            sleep(500);
+            ports[n-4] = remotePort;
+        }
+        if (n == 7) {
+            // should be all different
+            if (ports[0] == ports[1] || ports[2] == ports[3]
+                    || ports[0] == ports[2]) {
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+                System.out.printf("Ports: %d, %d, %d, %d\n", ports[0], ports[1], ports[2], ports[3]);
+            }
+            // setup for third test
+            for (int i=0; i<4; i++) {
+                portSet.add(ports[i]);
+            }
+        }
+        // Third test
+        if (n > 7) {
+            // just check that port is one of the ones in portSet
+            if (!portSet.contains(remotePort)) {
+                System.out.println ("UNEXPECTED REMOTE PORT " + remotePort);
+                result = "Error " + Integer.toString(n);
+                System.out.println(result);
+            }
+        }
+        byte[] buf = new byte[2048];
+
+        try (InputStream is = t.getRequestBody()) {
+            while (is.read(buf) != -1) ;
+        }
+        t.sendResponseHeaders(200, result.length());
+        OutputStream o = t.getResponseBody();
+        o.write(result.getBytes("US-ASCII"));
+        t.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/SplitResponse.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//package javaapplication16;
+
+import java.io.IOException;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * @test
+ * @bug 8087112
+ * @build Server
+ * @run main/othervm -Djava.net.HttpClient.log=all SplitResponse
+ */
+
+/**
+ * Similar test to QuickResponses except that each byte of the response
+ * is sent in a separate packet, which tests the stability of the implementation
+ * for receiving unusual packet sizes.
+ */
+public class SplitResponse {
+
+    static Server server;
+
+    static String response(String body) {
+        return "HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-length: "
+                + Integer.toString(body.length())
+                + "\r\n\r\n" + body;
+    }
+
+    static final String responses[] = {
+        "Lorem ipsum",
+        "dolor sit amet",
+        "consectetur adipiscing elit, sed do eiusmod tempor",
+        "quis nostrud exercitation ullamco",
+        "laboris nisi",
+        "ut",
+        "aliquip ex ea commodo consequat." +
+        "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
+        "cillum dolore eu fugiat nulla pariatur.",
+        "Excepteur sint occaecat cupidatat non proident."
+    };
+
+    public static void main(String[] args) throws Exception {
+        server = new Server(0);
+        URI uri = new URI(server.getURL());
+
+        HttpRequest request;
+        HttpResponse r;
+        CompletableFuture<HttpResponse> cf1;
+
+        for (int i=0; i<responses.length; i++) {
+            cf1 = HttpRequest.create(uri)
+                    .GET()
+                    .responseAsync();
+            String body = responses[i];
+
+            Server.Connection c = server.activity();
+            sendSplitResponse(response(body), c);
+            r = cf1.get();
+            if (r.statusCode()!= 200)
+                throw new RuntimeException("Failed");
+
+            String rxbody = r.body(HttpResponse.asString());
+            System.out.println("received " + rxbody);
+            if (!rxbody.equals(body))
+                throw new RuntimeException("Failed");
+            c.close();
+        }
+        HttpClient.getDefault().executorService().shutdownNow();
+        System.out.println("OK");
+    }
+
+    // send the response one byte at a time with a small delay between bytes
+    // to ensure that each byte is read in a separate read
+    static void sendSplitResponse(String s, Server.Connection conn) {
+        System.out.println("Sending: ");
+        Thread t = new Thread(() -> {
+            try {
+                int len = s.length();
+                for (int i = 0; i < len; i++) {
+                    String onechar = s.substring(i, i + 1);
+                    conn.send(onechar);
+                    Thread.sleep(30);
+                }
+                System.out.println("sent");
+            } catch (IOException | InterruptedException e) {
+            }
+        });
+        t.setDaemon(true);
+        t.start();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/TimeoutTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpTimeoutException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @test
+ * @bug 8087112
+ * @run main/othervm TimeoutTest
+ */
+
+public class TimeoutTest {
+
+    static int[] timeouts = {6, 4, 8, 6, 6, 4};
+    static HttpRequest[] rqs = new HttpRequest[timeouts.length];
+    static LinkedBlockingQueue<HttpRequest> queue = new LinkedBlockingQueue<>();
+    static volatile boolean error = false;
+    static ExecutorService executor = Executors.newCachedThreadPool();
+
+    public static void main(String[] args) throws Exception {
+        try {
+            dotest();
+        } finally {
+            HttpClient.getDefault().executorService().shutdownNow();
+            executor.shutdownNow();
+        }
+    }
+    public static void dotest() throws Exception {
+        System.out.println("Test takes over 40 seconds");
+        ServerSocket ss = new ServerSocket(0, 20);
+        int port = ss.getLocalPort();
+
+        URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/foo");
+        int i = 0;
+        for (int timeout : timeouts) {
+            HttpRequest request;
+            (request = rqs[i] = HttpRequest.create(uri)
+                .timeout(TimeUnit.SECONDS, timeout)
+                .GET())
+                .responseAsync()
+                .whenComplete((HttpResponse r, Throwable t) -> {
+                    if (!(t.getCause() instanceof HttpTimeoutException)) {
+                        System.out.println("Wrong exception type:" + t.toString());
+                        error = true;
+                    }
+                    if (t != null) {
+                        queue.add(request);
+                    }
+                })
+                .thenAccept((HttpResponse r) -> {
+                    r.bodyAsync(HttpResponse.ignoreBody());
+                });
+            i++;
+        }
+
+        System.out.println("SUBMITTED");
+
+        checkReturnOrder();
+
+        if (error)
+            throw new RuntimeException("Failed");
+
+        // Repeat blocking in separate threads. Use queue to wait.
+        System.out.println("DOING BLOCKING");
+
+        i = 0;
+        for (int timeout : timeouts) {
+            HttpRequest req = HttpRequest.create(uri)
+                .timeout(TimeUnit.SECONDS, timeout)
+                .GET();
+            rqs[i] = req;
+            executor.execute(() -> {
+                try {
+                    req.response().body(HttpResponse.ignoreBody());
+                } catch (HttpTimeoutException e) {
+                    queue.offer(req);
+                } catch (IOException | InterruptedException ee) {
+                    error = true;
+                }
+            });
+            i++;
+        }
+
+        checkReturnOrder();
+
+        if (error)
+            throw new RuntimeException("Failed");
+    }
+
+    static void checkReturnOrder() throws InterruptedException {
+        // wait for exceptions and check order
+        for (int j = 0; j < timeouts.length; j++) {
+            HttpRequest req = queue.take();
+            switch (j) {
+                case 0:
+                case 1:
+                    if (req != rqs[1] && req != rqs[5]) {
+                        System.out.printf("Expected 1 or 5. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+                    break;
+                case 2:
+                case 3:
+                case 4:
+                    if (req != rqs[0] && req != rqs[3] && req != rqs[4]) {
+                        System.out.printf("Expected r1, r4 or r5. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+                    break;
+                case 5:
+                    if (req != rqs[2]) {
+                        System.out.printf("Expected r3. Got %s\n", getRequest(req));
+                        throw new RuntimeException("Error");
+                    }
+            }
+        }
+        System.out.println("Return order ok");
+    }
+
+    static String getRequest(HttpRequest req) {
+        for (int i=0; i<rqs.length; i++) {
+            if (req == rqs[i]) {
+                return "[" + Integer.toString(i) + "]";
+            }
+        }
+        return "unknown";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/foo.txt	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,1 @@
+This is foo.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/notsobigfile.txt	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
+This is a not so big file at all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/docs/files/smallfile.txt	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,1792 @@
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
+This is a small file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/0.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy: 0
+
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/1.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 1
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/10.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,22 @@
+// Policy 10
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/11.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/12.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/15.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,27 @@
+// Policy 11
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+    permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
+
+    // Test checks for this explicitly
+    permission java.net.RuntimePermission "foobar"; 
+};
+
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/2.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 2
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/*", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/3.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 3
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/foo.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/4.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,25 @@
+// Policy 4
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/foo.txt", "GET";
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/bar.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/5.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 5
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/redirect/bar.txt", "GET";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/6.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 6
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "POST";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/7.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 7
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:X-Bar";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/8.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 8
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:X-Foo1,X-Foo,X-Bar";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/9.policy	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,24 @@
+// Policy 9
+grant {
+    // permissions common to all tests
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "test.classes", "read";
+    permission java.io.FilePermission "${test.classes}${/}-", "read,write,delete";
+    permission java.net.NetPermission "getDefaultHttpClient";
+    permission java.lang.RuntimePermission "modifyThread";
+    permission java.util.logging.LoggingPermission "control", "";
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen";
+    permission java.io.FilePermission "${test.src}${/}docs${/}-", "read";
+    permission java.lang.RuntimePermission "createClassLoader";
+
+
+    // permissions specific to this test
+    permission java.net.URLPermission "http://127.0.0.1:*/files/foo.txt", "GET:*";
+};
+
+// For proxy only. Not being tested
+grant codebase "file:${test.classes}/proxydir/-" {
+    permission java.net.SocketPermission "localhost:1024-", "accept,listen,connect";
+    permission java.net.SocketPermission "127.0.0.1:1024-", "connect,resolve";
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/security/Security.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+/**
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @compile ../../../../com/sun/net/httpserver/LogFilter.java
+ * @compile ../../../../com/sun/net/httpserver/FileServerHandler.java
+ * @compile ../ProxyServer.java
+ *
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=0.policy Security 0
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=1.policy Security 1
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=2.policy Security 2
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=3.policy Security 3
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=4.policy Security 4
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=5.policy Security 5
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=6.policy Security 6
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=7.policy Security 7
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=8.policy Security 8
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=9.policy Security 9
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=10.policy Security 10
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=11.policy Security 11
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=12.policy Security 12
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=0.policy Security 13
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=1.policy Security 14
+ * @run main/othervm/secure=java.lang.SecurityManager/policy=15.policy Security 15
+ */
+
+import com.sun.net.httpserver.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.net.*;
+import java.net.http.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.function.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Security checks test
+ */
+public class Security {
+
+    static HttpServer s1 = null;
+    static ExecutorService executor=null;
+    static int port;
+    static HttpClient client;
+    static String httproot, fileuri, fileroot, redirectroot;
+    static List<HttpClient> clients = new LinkedList<>();
+    static URI uri;
+
+    interface Test {
+        public void execute() throws IOException, InterruptedException;
+    }
+
+    static class TestAndResult {
+        Test test;
+        boolean result;
+
+        TestAndResult (Test t, boolean result) {
+            this.test = t;
+            this.result = result;
+        }
+    }
+
+    static TestAndResult test(boolean result, Test t) {
+        return new TestAndResult(t, result);
+    }
+
+    static TestAndResult[] tests;
+    static String testclasses;
+    static File subdir;
+
+    /**
+     * The ProxyServer class is compiled by jtreg, but we want to
+     * move it so it is not on the application claspath. We want to
+     * load it through a separate classloader so that it has a separate
+     * protection domain and security permissions.
+     *
+     * Its permissions are in the second grant block in each policy file
+     */
+    static void setupProxy() throws IOException, ClassNotFoundException, NoSuchMethodException {
+        testclasses = System.getProperty("test.classes");
+        subdir = new File (testclasses, "proxydir");
+        subdir.mkdir();
+
+        movefile("ProxyServer.class");
+        movefile("ProxyServer$Connection.class");
+        movefile("ProxyServer$1.class");
+
+        URL url = subdir.toURL();
+        System.out.println("URL for class loader = " + url);
+        URLClassLoader urlc = new URLClassLoader(new URL[] {url});
+        proxyClass = Class.forName("ProxyServer", true, urlc);
+        proxyConstructor = proxyClass.getConstructor(Integer.class, Boolean.class);
+    }
+
+    static void movefile(String f) throws IOException {
+        Path src = Paths.get(testclasses, f);
+        Path dest = subdir.toPath().resolve(f);
+        if (!dest.toFile().exists()) {
+            System.out.printf("moving %s to %s\n", src.toString(), dest.toString());
+            Files.move(src, dest,  StandardCopyOption.REPLACE_EXISTING);
+        } else {
+            System.out.printf("NOT moving %s to %s\n", src.toString(), dest.toString());
+        }
+    }
+
+    static Object getProxy(int port, boolean b) throws Exception {
+        return proxyConstructor.newInstance(port, b);
+    }
+
+    static Class<?> proxyClass;
+    static Constructor<?> proxyConstructor;
+
+    static void setupTests() {
+        tests = new TestAndResult[]{
+            // (0) policy does not have permission for file. Should fail
+            test(false, () -> { // Policy 0
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (1) policy has permission for file URL
+            test(true, () -> { //Policy 1
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (2) policy has permission for all file URLs under /files
+            test(true, () -> { // Policy 2
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (3) policy has permission for first URL but not redirected URL
+            test(false, () -> { // Policy 3
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (4) policy has permission for both first URL and redirected URL
+            test(true, () -> { // Policy 4
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (5) policy has permission for redirected but not first URL
+            test(false, () -> { // Policy 5
+                URI u = URI.create("http://127.0.0.1:" + port + "/redirect/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (6) policy has permission for file URL, but not method
+            test(false, () -> { //Policy 6
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (7) policy has permission for file URL, method, but not header
+            test(false, () -> { //Policy 7
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .header("X-Foo", "bar")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (8) policy has permission for file URL, method and header
+            test(true, () -> { //Policy 8
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .header("X-Foo", "bar")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (9) policy has permission for file URL, method and header
+            test(true, () -> { //Policy 9
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .headers("X-Foo", "bar", "X-Bar", "foo")
+                        .GET();
+                HttpResponse response = request.response();
+            }),
+            // (10) policy has permission for destination URL but not for proxy
+            test(false, () -> { //Policy 10
+                directProxyTest(27208, true);
+            }),
+            // (11) policy has permission for both destination URL and proxy
+            test(true, () -> { //Policy 11
+                directProxyTest(27301, true);
+            }),
+            // (12) policy has permission for both destination URL and proxy
+            test(false, () -> { //Policy 11
+                directProxyTest(28301, false);
+            }),
+            // (13) async version of test 0
+            test(false, () -> { // Policy 0
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                try {
+                    HttpResponse response = request.responseAsync().get();
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }),
+            // (14) async version of test 1
+            test(true, () -> { //Policy 1
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                try {
+                    HttpResponse response = request.responseAsync().get();
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }),
+            // (15) check that user provided unprivileged code running on a worker
+            //      thread does not gain ungranted privileges.
+            test(false, () -> { //Policy 12
+                URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+                HttpRequest request = client.request(u)
+                        .GET();
+                HttpResponse response = request.response();
+                HttpResponse.BodyProcessor<String> stproc = HttpResponse.asString();
+
+                CompletableFuture<String> cf;
+                cf = response.bodyAsync(new HttpResponse.BodyProcessor<String>() {
+                        public void onResponseBodyChunk(ByteBuffer b) throws IOException {
+                            // do some mischief here
+                            SecurityManager sm = System.getSecurityManager();
+                            System.setSecurityManager(null);
+                            System.setSecurityManager(sm);
+                            // problem if we get this far
+                            stproc.onResponseBodyChunk(b);
+                        }
+                        public String onResponseBodyStart(long contentLength,
+                                        HttpHeaders responseHeaders,
+                                        LongConsumer fc) throws IOException {
+
+                            SecurityManager sm = System.getSecurityManager();
+                            // should succeed.
+                            sm.checkPermission(new RuntimePermission("foobar"));
+                            return stproc.onResponseBodyStart(contentLength,responseHeaders, fc);
+                        }
+                        public String onResponseComplete() throws IOException {
+                            return stproc.onResponseComplete();
+                        }
+                        public void onResponseError(Throwable t) {
+                            stproc.onResponseError(t);
+                        }
+                    }
+                );
+                try {
+                    System.out.println("Body = " + cf.get());// should not reach here
+                } catch (ExecutionException e) {
+                    if (e.getCause() instanceof SecurityException) {
+                        throw (SecurityException)e.getCause();
+                    } else {
+                        throw new RuntimeException(e);
+                    }
+                }
+            })
+        };
+    }
+
+    private static void directProxyTest(int proxyPort, boolean samePort) throws IOException, InterruptedException {
+        Object proxy = null;
+        try {
+            proxy = getProxy(proxyPort, true);
+        } catch (IOException e) {
+            System.out.println("Cannot bind. Not running test");
+            throw new SecurityException("test not run");
+        } catch (Exception ee) {
+            throw new RuntimeException(ee);
+        }
+        System.out.println("Proxy port = " + proxyPort);
+        if (!samePort)
+            proxyPort++;
+
+        HttpClient cl = HttpClient.create()
+                .proxy(ProxySelector.of(
+                                new InetSocketAddress("127.0.0.1", proxyPort)))
+                .build();
+        clients.add(cl);
+
+        URI u = URI.create("http://127.0.0.1:" + port + "/files/foo.txt");
+        HttpRequest request = cl.request(u)
+                .headers("X-Foo", "bar", "X-Bar", "foo")
+                .GET();
+        HttpResponse response = request.response();
+    }
+
+    static void runtest(Test r, String policy, boolean succeeds) {
+        System.out.println("Using policy file: " + policy);
+        try {
+            r.execute();
+            if (!succeeds) {
+                System.out.println("FAILED: expected security exception");
+                throw new RuntimeException("Failed");
+            }
+            System.out.println (policy + " succeeded as expected");
+        } catch (SecurityException e) {
+            if (succeeds) {
+                System.out.println("FAILED");
+                throw new RuntimeException(e);
+            }
+            System.out.println (policy + " threw exception as expected");
+        } catch (IOException | InterruptedException ee) {
+            throw new RuntimeException(ee);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        initServer();
+        setupProxy();
+        fileroot = System.getProperty ("test.src")+ "/docs";
+        int testnum = Integer.parseInt(args[0]);
+        String policy = args[0];
+
+        client = HttpClient
+            .create()
+            .followRedirects(HttpClient.Redirect.ALWAYS)
+            .build();
+
+        clients.add(HttpClient.getDefault());
+        clients.add(client);
+
+        try {
+            setupTests();
+            TestAndResult tr = tests[testnum];
+            runtest(tr.test, policy, tr.result);
+        } finally {
+            s1.stop(0);
+            //executor.shutdownNow();
+            for (HttpClient client : clients)
+                client.executorService().shutdownNow();
+        }
+    }
+
+    // create Http Server on port range below. So, we can
+    HttpServer createServer() {
+        HttpServer server;
+        for (int i=25800; i<26800; i++) {
+            InetSocketAddress a = new InetSocketAddress(i);
+            try {
+                server = HttpServer.create(a, 0);
+                return server;
+            } catch (IOException e) {}
+        }
+        return null;
+    }
+
+    public static void initServer() throws Exception {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        ConsoleHandler ch = new ConsoleHandler();
+        logger.setLevel(Level.ALL);
+        ch.setLevel(Level.ALL);
+        logger.addHandler(ch);
+        String root = System.getProperty ("test.src")+ "/docs";
+        InetSocketAddress addr = new InetSocketAddress (0);
+        s1 = HttpServer.create (addr, 0);
+        if (s1 instanceof HttpsServer) {
+            throw new RuntimeException ("should not be httpsserver");
+        }
+        HttpHandler h = new FileServerHandler (root);
+        HttpContext c = s1.createContext ("/files", h);
+
+        HttpHandler h1 = new RedirectHandler ("/redirect");
+        HttpContext c1 = s1.createContext ("/redirect", h1);
+
+        executor = Executors.newCachedThreadPool();
+        s1.setExecutor (executor);
+        s1.start();
+
+        port = s1.getAddress().getPort();
+        System.out.println("HTTP server port = " + port);
+        httproot = "http://127.0.0.1:" + port + "/files/";
+        redirectroot = "http://127.0.0.1:" + port + "/redirect/";
+        uri = new URI(httproot);
+        fileuri = httproot + "foo.txt";
+    }
+
+    static class RedirectHandler implements HttpHandler {
+
+        String root;
+        int count = 0;
+
+        RedirectHandler(String root) {
+            this.root = root;
+        }
+
+        synchronized int count() {
+            return count;
+        }
+
+        synchronized void increment() {
+            count++;
+        }
+
+        @Override
+        public synchronized void handle(HttpExchange t)
+                throws IOException {
+            byte[] buf = new byte[2048];
+            System.out.println("Server: " + t.getRequestURI());
+            try (InputStream is = t.getRequestBody()) {
+                while (is.read(buf) != -1) ;
+            }
+            increment();
+            if (count() == 1) {
+                Headers map = t.getResponseHeaders();
+                String redirect = "/redirect/bar.txt";
+                map.add("Location", redirect);
+                t.sendResponseHeaders(301, -1);
+                t.close();
+            } else {
+                String response = "Hello world";
+                t.sendResponseHeaders(200, response.length());
+                OutputStream os = t.getResponseBody();
+                os.write(response.getBytes(StandardCharsets.ISO_8859_1));
+                t.close();
+            }
+        }
+    }
+}
--- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -141,8 +141,11 @@
         try {
             // check supported options
             Set<SocketOption<?>> options = ch.supportedOptions();
+            boolean reuseport = options.contains(SO_REUSEPORT);
             if (!options.contains(SO_REUSEADDR))
                 throw new RuntimeException("SO_REUSEADDR should be supported");
+            if (!options.contains(SO_REUSEPORT) && reuseport)
+                throw new RuntimeException("SO_REUSEPORT should be supported");
             if (!options.contains(SO_RCVBUF))
                 throw new RuntimeException("SO_RCVBUF should be supported");
 
@@ -156,6 +159,13 @@
             checkOption(ch, SO_REUSEADDR, true);
             ch.setOption(SO_REUSEADDR, false);
             checkOption(ch, SO_REUSEADDR, false);
+
+            if (reuseport) {
+                ch.setOption(SO_REUSEPORT, true);
+                checkOption(ch, SO_REUSEPORT, true);
+                ch.setOption(SO_REUSEPORT, false);
+                checkOption(ch, SO_REUSEPORT, false);
+            }
         } finally {
             ch.close();
         }
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
 import java.util.concurrent.atomic.*;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.Set;
 
 public class Basic {
     static final Random rand = new Random();
@@ -165,6 +166,15 @@
             // read others (can't check as actual value is implementation dependent)
             ch.getOption(SO_RCVBUF);
             ch.getOption(SO_SNDBUF);
+
+            Set<SocketOption<?>> options = ch.supportedOptions();
+            boolean reuseport = options.contains(SO_REUSEPORT);
+            if (reuseport) {
+                if (ch.getOption(SO_REUSEPORT))
+                    throw new RuntimeException("Default of SO_REUSEPORT should be 'false'");
+                if (!ch.setOption(SO_REUSEPORT, true).getOption(SO_REUSEPORT))
+                    throw new RuntimeException("SO_REUSEPORT did not change");
+            }
         }
     }
 
--- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,9 +50,17 @@
 
         // check supported options
         Set<SocketOption<?>> options = dc.supportedOptions();
-        List<? extends SocketOption<?>> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
-            SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
-            IP_MULTICAST_LOOP);
+        boolean reuseport = options.contains(SO_REUSEPORT);
+        List<? extends SocketOption<?>> expected;
+        if (reuseport) {
+           expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+                      SO_REUSEADDR, SO_REUSEPORT, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF,
+                      IP_MULTICAST_TTL, IP_MULTICAST_LOOP);
+        } else {
+           expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
+                      SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
+                      IP_MULTICAST_LOOP);
+        }
         for (SocketOption opt: expected) {
             if (!options.contains(opt))
                 throw new RuntimeException(opt.name() + " should be supported");
@@ -83,7 +91,12 @@
         checkOption(dc, SO_REUSEADDR, true);
         dc.setOption(SO_REUSEADDR, false);
         checkOption(dc, SO_REUSEADDR, false);
-
+        if (reuseport) {
+            dc.setOption(SO_REUSEPORT, true);
+            checkOption(dc, SO_REUSEPORT, true);
+            dc.setOption(SO_REUSEPORT, false);
+            checkOption(dc, SO_REUSEPORT, false);
+        }
         // bind socket
         dc.bind(new InetSocketAddress(0));
 
--- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,8 +49,11 @@
 
         // check supported options
         Set<SocketOption<?>> options = ssc.supportedOptions();
+        boolean reuseport = options.contains(SO_REUSEPORT);
         if (!options.contains(SO_REUSEADDR))
             throw new RuntimeException("SO_REUSEADDR should be supported");
+        if (!options.contains(SO_REUSEPORT) && reuseport)
+            throw new RuntimeException("SO_REUSEPORT should be supported");
         if (!options.contains(SO_RCVBUF))
             throw new RuntimeException("SO_RCVBUF should be supported");
 
@@ -64,6 +67,12 @@
         checkOption(ssc, SO_REUSEADDR, true);
         ssc.setOption(SO_REUSEADDR, false);
         checkOption(ssc, SO_REUSEADDR, false);
+        if (reuseport) {
+            ssc.setOption(SO_REUSEPORT, true);
+            checkOption(ssc, SO_REUSEPORT, true);
+            ssc.setOption(SO_REUSEPORT, false);
+            checkOption(ssc, SO_REUSEPORT, false);
+        }
 
         // NullPointerException
         try {
--- a/jdk/test/java/nio/charset/coders/BashStreams.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/charset/coders/BashStreams.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /* @test
  * @summary Stochastic test of charset-based streams
- * @key randomness
+ * @key randomness intermittent
  */
 
 import java.io.*;
--- a/jdk/test/java/nio/file/Files/probeContentType/Basic.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/nio/file/Files/probeContentType/Basic.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,8 +29,9 @@
  * @run main/othervm Basic
  */
 
+import java.io.*;
 import java.nio.file.*;
-import java.io.*;
+import java.util.stream.Stream;
 
 /**
  * Uses Files.probeContentType to probe html file, custom file type, and minimal
@@ -38,6 +39,9 @@
  */
 public class Basic {
 
+    private static final boolean IS_UNIX =
+        ! System.getProperty("os.name").startsWith("Windows");
+
     static Path createHtmlFile() throws IOException {
         Path file = Files.createTempFile("foo", ".html");
         try (OutputStream out = Files.newOutputStream(file)) {
@@ -51,10 +55,61 @@
         return Files.createTempFile("red", ".grape");
     }
 
-    static void checkContentTypes(String[] extensions, String[] expectedTypes)
+    private static int checkContentTypes(String expected, String actual) {
+        assert expected != null;
+        assert actual != null;
+
+        if (!expected.equals(actual)) {
+            if (IS_UNIX) {
+                Path userMimeTypes =
+                    Paths.get(System.getProperty("user.home"), ".mime.types");
+                if (!Files.exists(userMimeTypes)) {
+                    System.out.println(userMimeTypes + " does not exist");
+                } else if (!Files.isReadable(userMimeTypes)) {
+                    System.out.println(userMimeTypes + " is not readable");
+                } else {
+                    System.out.println(userMimeTypes + " contents:");
+                    try (Stream<String> lines = Files.lines(userMimeTypes)) {
+                        lines.forEach(System.out::println);
+                        System.out.println("");
+                    } catch (IOException ioe) {
+                        System.err.println("Problem reading "
+                                           + userMimeTypes);
+                    }
+                }
+
+                Path etcMimeTypes = Paths.get("/etc/mime.types");
+                if (!Files.exists(etcMimeTypes)) {
+                    System.out.println(etcMimeTypes + " does not exist");
+                } else if (!Files.isReadable(etcMimeTypes)) {
+                    System.out.println(etcMimeTypes + " is not readable");
+                } else {
+                    System.out.println(etcMimeTypes + " contents:");
+                    try (Stream<String> lines = Files.lines(etcMimeTypes)) {
+                        lines.forEach(System.out::println);
+                        System.out.println("");
+                    } catch (IOException ioe) {
+                        System.err.println("Problem reading "
+                                           + etcMimeTypes);
+                    }
+                }
+            }
+
+            System.err.println("Expected \"" + expected
+                               + "\" but obtained \""
+                               + actual + "\"");
+
+            return 1;
+        }
+
+        return 0;
+    }
+
+    static int checkOSXContentTypes(String[] extensions, String[] expectedTypes)
         throws IOException {
         if (extensions.length != expectedTypes.length) {
-            throw new IllegalArgumentException("Parameter array lengths differ");
+            throw new IllegalArgumentException
+                ("Parameter array lengths differ");
         }
 
         int failures = 0;
@@ -79,12 +134,11 @@
             }
         }
 
-        if (failures > 0) {
-            throw new RuntimeException("Test failed!");
-        }
+        return failures;
     }
 
     public static void main(String[] args) throws IOException {
+        int failures = 0;
 
         // exercise default file type detector
         Path file = createHtmlFile();
@@ -93,8 +147,7 @@
             if (type == null) {
                 System.err.println("Content type cannot be determined - test skipped");
             } else {
-                if (!type.equals("text/html"))
-                    throw new RuntimeException("Unexpected type: " + type);
+                failures += checkContentTypes("text/html", type);
             }
         } finally {
             Files.delete(file);
@@ -106,8 +159,7 @@
             String type = Files.probeContentType(file);
             if (type == null)
                 throw new RuntimeException("Custom file type detector not installed?");
-            if (!type.equals("grape/unknown"))
-                throw new RuntimeException("Unexpected type: " + type);
+            failures += checkContentTypes("grape/unknown", type);
         } finally {
             Files.delete(file);
         }
@@ -122,7 +174,11 @@
                 "image/jpeg", "audio/mpeg", "video/mp4", "application/pdf",
                 "image/png"
             };
-            checkContentTypes(extensions, expectedTypes);
+            failures += checkOSXContentTypes(extensions, expectedTypes);
+        }
+
+        if (failures > 0) {
+            throw new RuntimeException("Test failed!");
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarAPI.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the extended API and the aliasing additions in JarFile that
+ *          support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarAPI
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static java.util.jar.JarFile.Release;
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+public class MultiReleaseJarAPI {
+    String userdir = System.getProperty("user.dir",".");
+    File unversioned = new File(userdir, "unversioned.jar");
+    File multirelease = new File(userdir, "multi-release.jar");
+    File signedmultirelease = new File(userdir, "signed-multi-release.jar");
+    Release[] values = JarFile.Release.values();
+
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildUnversionedJar();
+        creator.buildMultiReleaseJar();
+        creator.buildSignedMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(unversioned.toPath());
+        Files.delete(multirelease.toPath());
+        Files.delete(signedmultirelease.toPath());
+    }
+
+    @Test
+    public void isMultiReleaseJar() throws Exception {
+        try (JarFile jf = new JarFile(unversioned)) {
+            Assert.assertFalse(jf.isMultiRelease());
+        }
+
+        try (JarFile jf = new JarFile(multirelease)) {
+            Assert.assertTrue(jf.isMultiRelease());
+        }
+    }
+
+    @Test
+    public void testVersioning() throws Exception {
+        // multi-release jar
+        JarFile jar = new JarFile(multirelease);
+        Assert.assertEquals(Release.BASE, jar.getVersion());
+        jar.close();
+
+        for (Release value : values) {
+            System.err.println("test versioning for Release " + value);
+            try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, value)) {
+                Assert.assertEquals(value, jf.getVersion());
+            }
+        }
+
+        // regular, unversioned, jar
+        for (Release value : values) {
+            try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, value)) {
+                Assert.assertEquals(Release.BASE, jf.getVersion());
+            }
+        }
+
+        // assure that we have a Release object corresponding to the actual runtime version
+        String version = "VERSION_" + jdkMajorVersion();
+        boolean runtimeVersionExists = false;
+        for (Release value : values) {
+            if (version.equals(value.name())) runtimeVersionExists = true;
+        }
+        Assert.assertTrue(runtimeVersionExists);
+    }
+
+    @Test
+    public void testAliasing() throws Exception {
+        for (Release value : values) {
+            System.err.println("test aliasing for Release " + value);
+            String name = value.name();
+            String prefix;
+            if (name.equals("BASE")) {
+                prefix = "";
+            } else if (name.equals("RUNTIME")) {
+                prefix = "META-INF/versions/" + jdkMajorVersion() + "/";
+            } else {
+                prefix = "META-INF/versions/" + name.substring(8) + "/";
+            }
+            // test both multi-release jars
+            readAndCompare(multirelease, value, "README", prefix + "README");
+            readAndCompare(multirelease, value, "version/Version.class", prefix + "version/Version.class");
+            // and signed multi-release jars
+            readAndCompare(signedmultirelease, value, "README", prefix + "README");
+            readAndCompare(signedmultirelease, value, "version/Version.class", prefix + "version/Version.class");
+        }
+    }
+
+    private void readAndCompare(File jar, Release version, String name, String realName) throws Exception {
+        byte[] baseBytes;
+        byte[] versionedBytes;
+        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, Release.BASE)) {
+            ZipEntry ze = jf.getEntry(realName);
+            try (InputStream is = jf.getInputStream(ze)) {
+                baseBytes = is.readAllBytes();
+            }
+        }
+        assert baseBytes.length > 0;
+
+        try (JarFile jf = new JarFile(jar, true, ZipFile.OPEN_READ, version)) {
+            ZipEntry ze = jf.getEntry(name);
+            try (InputStream is = jf.getInputStream(ze)) {
+                versionedBytes = is.readAllBytes();
+            }
+        }
+        assert versionedBytes.length > 0;
+
+        Assert.assertTrue(Arrays.equals(baseBytes, versionedBytes));
+    }
+
+    @Test
+    public void testNames() throws Exception {
+        String rname = "version/Version.class";
+        String vname = "META-INF/versions/9/version/Version.class";
+        ZipEntry ze1;
+        ZipEntry ze2;
+        try (JarFile jf = new JarFile(multirelease)) {
+            ze1 = jf.getEntry(vname);
+        }
+        Assert.assertEquals(ze1.getName(), vname);
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            ze2 = jf.getEntry(rname);
+        }
+        Assert.assertEquals(ze2.getName(), rname);
+        Assert.assertNotEquals(ze1.getName(), ze2.getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarHttpProperties.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the System properties for JarFile that support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=0 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=100 MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarHttpProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarHttpProperties
+ */
+
+import com.sun.net.httpserver.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarHttpProperties extends MultiReleaseJarProperties {
+    private SimpleHttpServer server;
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        server = new SimpleHttpServer();
+        server.start();
+        super.initialize();
+    }
+
+    @Override
+    protected void initializeClassLoader() throws Exception {
+        URL[] urls = new URL[]{
+                new URL("http://localhost:" + server.getPort() + "/multi-release-jar")
+        };
+        cldr = new URLClassLoader(urls);
+        // load any class, Main is convenient and in the root entries
+        rootClass = cldr.loadClass("version.Main");
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        // Windows requires server to stop before file is deleted
+        if (server != null)
+            server.stop();
+        super.close();
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force is a no-op for URLClassLoader
+     */
+
+    @Test
+    public void testURLClassLoader() throws Throwable {
+        Class<?> vcls = cldr.loadClass("version.Version");
+        invokeMethod(vcls, rtVersion);
+    }
+
+    @Test
+    public void testGetResourceAsStream() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResourceAsStream(rootClass, resource);
+    }
+
+    @Test
+    public void testGetResource() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResource(rootClass, resource);
+    }
+}
+
+/**
+ * Extremely simple server that only performs one task.  The server listens for
+ * requests on the ephemeral port.  If it sees a request that begins with
+ * "/multi-release-jar", it consumes the request and returns a stream of bytes
+ * representing the jar file multi-release.jar found in "userdir".
+ */
+class SimpleHttpServer {
+    private static final String userdir = System.getProperty("user.dir", ".");
+    private static final Path multirelease = Paths.get(userdir, "multi-release.jar");
+
+    private final HttpServer server;
+
+    public SimpleHttpServer() throws IOException {
+        server = HttpServer.create();
+    }
+
+    public void start() throws IOException {
+        server.bind(new InetSocketAddress(0), 0);
+        server.createContext("/multi-release-jar", t -> {
+            try (InputStream is = t.getRequestBody()) {
+                is.readAllBytes();  // probably not necessary to consume request
+                byte[] bytes = Files.readAllBytes(multirelease);
+                t.sendResponseHeaders(200, bytes.length);
+                try (OutputStream os = t.getResponseBody()) {
+                    os.write(bytes);
+                }
+            }
+        });
+        server.setExecutor(null); // creates a default executor
+        server.start();
+    }
+
+    public void stop() {
+        server.stop(0);
+    }
+
+    int getPort() {
+        return server.getAddress().getPort();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarIterators.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the extended API and the aliasing additions in JarFile that
+ *          support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarIterators
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.zip.ZipFile;
+
+import static java.util.jar.JarFile.Release;
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+public class MultiReleaseJarIterators {
+    String userdir = System.getProperty("user.dir", ".");
+    File unversioned = new File(userdir, "unversioned.jar");
+    File multirelease = new File(userdir, "multi-release.jar");
+    Map<String,JarEntry> uvEntries = new HashMap<>();
+    Map<String,JarEntry> mrEntries = new HashMap<>();
+    Map<String,JarEntry> baseEntries = new HashMap<>();
+    Map<String,JarEntry> v9Entries = new HashMap<>();
+    Map<String, JarEntry> v10Entries = new HashMap<>();
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildUnversionedJar();
+        creator.buildMultiReleaseJar();
+
+        try (JarFile jf = new JarFile(multirelease)) {
+            for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements(); ) {
+                JarEntry je = e.nextElement();
+                String name = je.getName();
+                mrEntries.put(name, je);
+                if (name.startsWith("META-INF/versions/")) {
+                    if (name.startsWith("META-INF/versions/9/")) {
+                        v9Entries.put(name.substring(20), je);
+                    } else if (name.startsWith("META-INF/versions/10/")) {
+                        v10Entries.put(name.substring(21), je);
+                    }
+                } else {
+                    baseEntries.put(name, je);
+                }
+            }
+        }
+        Assert.assertEquals(mrEntries.size(), 14);
+        Assert.assertEquals(baseEntries.size(), 6);
+        Assert.assertEquals(v9Entries.size(), 5);
+        Assert.assertEquals(v10Entries.size(), 3);
+
+        try (JarFile jf = new JarFile(unversioned)) {
+            jf.entries().asIterator().forEachRemaining(je -> uvEntries.put(je.getName(), je));
+        }
+        Assert.assertEquals(uvEntries.size(), 6);
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(unversioned.toPath());
+        Files.delete(multirelease.toPath());
+    }
+
+    @Test
+    public void testMultiReleaseJar() throws IOException {
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ)) {
+            testEnumeration(jf, mrEntries);
+            testStream(jf, mrEntries);
+        }
+
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.BASE)) {
+            testEnumeration(jf, baseEntries);
+            testStream(jf, baseEntries);
+        }
+
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            testEnumeration(jf, v9Entries);
+            testStream(jf, v9Entries);
+        }
+
+        try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+            Map<String,JarEntry> expectedEntries;
+            switch (jdkMajorVersion()) {
+                case 9:
+                    expectedEntries = v9Entries;
+                    break;
+                case 10:  // won't get here until JDK 10
+                    expectedEntries = v10Entries;
+                    break;
+                default:
+                    expectedEntries = baseEntries;
+                    break;
+            }
+
+            testEnumeration(jf, expectedEntries);
+            testStream(jf, expectedEntries);
+        }
+    }
+
+    @Test
+    public void testUnversionedJar() throws IOException {
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.BASE)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.VERSION_9)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+
+        try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
+            testEnumeration(jf, uvEntries);
+            testStream(jf, uvEntries);
+        }
+    }
+
+    private void testEnumeration(JarFile jf, Map<String,JarEntry> expectedEntries) {
+        Map<String, JarEntry> actualEntries = new HashMap<>();
+        for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements(); ) {
+            JarEntry je = e.nextElement();
+            actualEntries.put(je.getName(), je);
+        }
+
+        testEntries(jf, actualEntries, expectedEntries);
+    }
+
+
+    private void testStream(JarFile jf, Map<String,JarEntry> expectedEntries) {
+        Map<String,JarEntry> actualEntries = jf.stream().collect(Collectors.toMap(je -> je.getName(), je -> je));
+
+        testEntries(jf, actualEntries, expectedEntries);
+    }
+
+    private void testEntries(JarFile jf, Map<String,JarEntry> actualEntries, Map<String,JarEntry> expectedEntries) {
+        /* For multi-release jar files constructed with a Release object,
+         * actualEntries contain versionedEntries that are considered part of the
+         * public API.  They have a 1-1 correspondence with baseEntries,
+         * so entries that are not part of the public API won't be present,
+         * i.e. those entries with a name that starts with version/PackagePrivate
+         * in this particular jar file (multi-release.jar)
+         */
+
+        Map<String,JarEntry> entries;
+        if (expectedEntries == mrEntries) {
+            Assert.assertEquals(actualEntries.size(), mrEntries.size());
+            entries = mrEntries;
+        } else if (expectedEntries == uvEntries) {
+            Assert.assertEquals(actualEntries.size(), uvEntries.size());
+            entries = uvEntries;
+        } else {
+            Assert.assertEquals(actualEntries.size(), baseEntries.size());  // this is correct
+            entries = baseEntries;
+        }
+
+        entries.keySet().forEach(name -> {
+            JarEntry ee = expectedEntries.get(name);
+            if (ee == null) ee = entries.get(name);
+            JarEntry ae = actualEntries.get(name);
+            try {
+                compare(jf, ae, ee);
+            } catch (IOException x) {
+                throw new RuntimeException(x);
+            }
+        });
+    }
+
+    private void compare(JarFile jf, JarEntry actual, JarEntry expected) throws IOException {
+        byte[] abytes;
+        byte[] ebytes;
+
+        try (InputStream is = jf.getInputStream(actual)) {
+            abytes = is.readAllBytes();
+        }
+
+        try (InputStream is = jf.getInputStream(expected)) {
+            ebytes = is.readAllBytes();
+        }
+
+        Assert.assertEquals(abytes, ebytes);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarProperties.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test the System properties for JarFile that support multi-release jar files
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=0 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=100 MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=8 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=9 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.version=10 -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=false MultiReleaseJarProperties
+ * @run testng/othervm -Djdk.util.jar.enableMultiRelease=force MultiReleaseJarProperties
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import static sun.misc.Version.jdkMajorVersion;  // fixme JEP 223 Version
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarProperties {
+    final static int ROOTVERSION = 8; // magic number from knowledge of internals
+    final static String userdir = System.getProperty("user.dir", ".");
+    final static File multirelease = new File(userdir, "multi-release.jar");
+    protected int rtVersion;
+    boolean force;
+    protected ClassLoader cldr;
+    protected Class<?> rootClass;
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+
+        rtVersion = Integer.getInteger("jdk.util.jar.version", jdkMajorVersion());
+        String mrprop = System.getProperty("jdk.util.jar.enableMultiRelease", "");
+        if (mrprop.equals("false")) {
+            rtVersion = ROOTVERSION;
+        } else if (rtVersion < ROOTVERSION) {
+            rtVersion = ROOTVERSION;
+        } else if (rtVersion > jdkMajorVersion()) {
+            rtVersion = jdkMajorVersion();
+        }
+        force = mrprop.equals("force");
+
+        initializeClassLoader();
+    }
+
+    protected void initializeClassLoader() throws Exception {
+        URL[] urls = new URL[]{multirelease.toURI().toURL()};
+        cldr = new URLClassLoader(urls);
+        // load any class, Main is convenient and in the root entries
+        rootClass = cldr.loadClass("version.Main");
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        ((URLClassLoader)cldr).close();
+        Files.delete(multirelease.toPath());
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force is a no-op for URLClassLoader
+     */
+    @Test
+    public void testURLClassLoader() throws Throwable {
+        Class<?> vcls = cldr.loadClass("version.Version");
+        invokeMethod(vcls, rtVersion);
+    }
+
+    protected void invokeMethod(Class<?> vcls, int expected) throws Throwable {
+        MethodType mt = MethodType.methodType(int.class);
+        MethodHandle mh = MethodHandles.lookup().findVirtual(vcls, "getVersion", mt);
+        Assert.assertEquals(expected, (int) mh.invoke(vcls.newInstance()));
+    }
+
+    /*
+     * jdk.util.jar.enableMultiRelease=force should affect a custom class loader
+     */
+    @Test
+    public void testClassLoader() throws Throwable {
+        try (JarFile jf = new JarFile(multirelease)) {  // do not set runtime versioning
+            ClassLoader cldr = new CustomClassLoader(jf);
+            Class<?> vcls = cldr.loadClass("version.Version");
+            if (rtVersion == 9) {
+                try {
+                    cldr.loadClass("version.PackagePrivate");
+                } catch (ClassNotFoundException x) {
+                    if (force) throw x;
+                }
+            }
+            invokeMethod(vcls, force ? rtVersion : ROOTVERSION);
+        }
+    }
+
+    private static class CustomClassLoader extends ClassLoader {
+        private final JarFile jf;
+
+        CustomClassLoader(JarFile jf) throws Exception {
+            super(null);
+            this.jf = jf;
+        }
+
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            try {
+                byte[] b;
+                String entryName = name.replace(".", "/") + ".class";
+                JarEntry je = jf.getJarEntry(entryName);
+                if (je != null) {
+                    try (InputStream is = jf.getInputStream(je)) {
+                        b = new byte[(int) je.getSize()];
+                        is.read(b);
+                    }
+                    return defineClass(name, b, 0, b.length);
+                }
+                throw new ClassNotFoundException(name);
+            } catch (IOException x) {
+                throw new ClassNotFoundException(x.getMessage());
+            }
+        }
+    }
+
+    @Test
+    public void testGetResourceAsStream() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use fileRootClass as a base for getting resources
+        getResourceAsStream(rootClass, resource);
+    }
+
+    protected void getResourceAsStream(Class<?> rootClass, String resource) throws Exception {
+        try (InputStream is = rootClass.getResourceAsStream(resource)) {
+            byte[] bytes = is.readAllBytes();
+            resource = new String(bytes);
+        }
+        String match = "return " + rtVersion + ";";
+        Assert.assertTrue(resource.contains(match));
+    }
+
+    @Test
+    public void testGetResource() throws Exception {
+        String resource = rtVersion == 9 ? "/version/PackagePrivate.java" : "/version/Version.java";
+        // use rootClass as a base for getting resources
+        getResource(rootClass, resource);
+    }
+
+    protected void getResource(Class<?> rootClass, String resource) throws Exception {
+        URL url = rootClass.getResource(resource);
+        try (InputStream is = url.openStream()) {
+            byte[] bytes = is.readAllBytes();
+            resource = new String(bytes);
+        }
+        String match = "return " + rtVersion + ";";
+        Assert.assertTrue(resource.contains(match));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/jar/JarFile/MultiReleaseJarSecurity.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test potential security related issues
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarSecurity
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.zip.ZipFile;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarSecurity {
+    String userdir = System.getProperty("user.dir",".");
+    File multirelease = new File(userdir, "multi-release.jar");
+    File signedmultirelease = new File(userdir, "signed-multi-release.jar");
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator =  new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+        creator.buildSignedMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(multirelease.toPath());
+        Files.delete(signedmultirelease.toPath());
+    }
+
+    @Test
+    public void testCertsAndSigners() throws IOException {
+        try (JarFile jf = new JarFile(signedmultirelease, true, ZipFile.OPEN_READ, JarFile.Release.RUNTIME)) {
+            int version = sun.misc.Version.jdkMajorVersion();  // fixme JEP 223 Version
+            CertsAndSigners vcas = new CertsAndSigners(jf, jf.getJarEntry("version/Version.class"));
+            CertsAndSigners rcas = new CertsAndSigners(jf, jf.getJarEntry("META-INF/versions/" + version + "/version/Version.class"));
+            Assert.assertTrue(Arrays.equals(rcas.getCertificates(), vcas.getCertificates()));
+            Assert.assertTrue(Arrays.equals(rcas.getCodeSigners(), vcas.getCodeSigners()));
+        }
+    }
+
+    private static class CertsAndSigners {
+        final private JarFile jf;
+        final private JarEntry je;
+        private boolean readComplete;
+
+        CertsAndSigners(JarFile jf, JarEntry je) {
+            this.jf = jf;
+            this.je = je;
+        }
+
+        Certificate[] getCertificates() throws IOException {
+            readEntry();
+            return je.getCertificates();
+        }
+
+        CodeSigner[] getCodeSigners() throws IOException {
+            readEntry();
+            return je.getCodeSigners();
+        }
+
+        private void readEntry() throws IOException {
+            if (!readComplete) {
+                try (InputStream is = jf.getInputStream(je)) {
+                    is.readAllBytes();
+                }
+                readComplete = true;
+            }
+        }
+    }
+}
--- a/jdk/test/java/util/logging/LogManagerAppContextDeadlock.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/java/util/logging/LogManagerAppContextDeadlock.java	Mon Feb 29 15:42:34 2016 +0000
@@ -141,6 +141,7 @@
         t1.setDaemon(true);
         t1.start();
         Thread t2 = new Thread() {
+            public Object logger;
             public void run() {
                 sem3.release();
                 try {
@@ -151,7 +152,10 @@
                     Thread.interrupted();
                 }
                 System.out.println("Logger.getLogger(name).info(name)");
-                Logger.getLogger(test.name());//.info(name);
+                // stick the logger in an instance variable to prevent it
+                // from being garbage collected before the main thread
+                // calls LogManager.getLogger() below.
+                logger = Logger.getLogger(test.name());//.info(name);
                 System.out.println("Done: Logger.getLogger(name).info(name)");
             }
         };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/JceSecurity/FinalRestricted.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8149417
+ * @summary Use final restricted flag
+ */
+
+import java.security.*;
+import java.lang.reflect.*;
+
+public class FinalRestricted {
+
+    public static void main(String[] args) throws Exception {
+
+        int modifiers = Class.forName("javax.crypto.JceSecurity")
+                    .getDeclaredField("isRestricted").getModifiers();
+        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers) &&
+                Modifier.isPrivate(modifiers))) {
+            throw new Exception("JceSecurity.isRestricted is not " +
+                                "a private static final field!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/Stapling/StapleEnableProps.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,721 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8145854
+ * @summary SSLContextImpl.statusResponseManager should be generated if required
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm StapleEnableProps
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.math.BigInteger;
+import java.security.*;
+import java.nio.*;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+public class StapleEnableProps {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    // These two ByteBuffer references will be used to hang onto ClientHello
+    // messages with and without the status_request[_v2] extensions.  These
+    // will be used in the server-side stapling tests.
+    private static ByteBuffer cHelloStaple;
+    private static ByteBuffer cHelloNoStaple;
+
+    // The following items are used to set up the keystores.
+    private static final String passwd = "passphrase";
+    private static final String ROOT_ALIAS = "root";
+    private static final String INT_ALIAS = "intermediate";
+    private static final String SSL_ALIAS = "ssl";
+
+    // PKI components we will need for this test
+    private static KeyManagerFactory kmf;
+    private static TrustManagerFactory tmf;
+    private static KeyStore rootKeystore;       // Root CA Keystore
+    private static KeyStore intKeystore;        // Intermediate CA Keystore
+    private static KeyStore serverKeystore;     // SSL Server Keystore
+    private static KeyStore trustStore;         // SSL Client trust store
+    private static SimpleOCSPServer rootOcsp;   // Root CA OCSP Responder
+    private static int rootOcspPort;            // Port for root OCSP
+    private static SimpleOCSPServer intOcsp;    // Intermediate CA OCSP server
+    private static int intOcspPort;             // Port for intermediate OCSP
+
+    // A few helpful TLS definitions to make it easier
+    private static final int HELLO_EXT_STATUS_REQ = 5;
+    private static final int HELLO_EXT_STATUS_REQ_V2 = 17;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl");
+        }
+
+        // Create the PKI we will use for the test and start the OCSP servers
+        createPKI();
+
+        // Set up the KeyManagerFactory and TrustManagerFactory
+        kmf = KeyManagerFactory.getInstance("PKIX");
+        kmf.init(serverKeystore, passwd.toCharArray());
+        tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(trustStore);
+
+        // Run the client and server property tests
+        testClientProp();
+        testServerProp();
+
+    }
+
+    private static void testClientProp() throws Exception {
+        SSLEngineResult clientResult;
+
+        // Test with the client-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Client Test 1: " +
+                "jdk.tls.client.enableStatusRequestExtension = true");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(null, tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        SSLSession session = engine.getSession();
+        ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());
+        ByteBuffer cTOs =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, true, true);
+        cHelloStaple = cTOs;
+
+        // Test with the property set to false
+        System.out.println("=========================================");
+        System.out.println("Client Test 2: " +
+                "jdk.tls.client.enableStatusRequestExtension = false");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, false, false);
+        cHelloNoStaple = cTOs;
+    }
+
+    private static void testServerProp() throws Exception {
+        SSLEngineResult serverResult;
+        HandshakeStatus hsStat;
+
+        // Test with the server-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Server Test 1: " +
+                "jdk.tls.server.enableStatusRequestExtension = true");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        SSLSession session = engine.getSession();
+        ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());
+        ByteBuffer serverIn =
+                ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        ByteBuffer sTOc =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHelloStaple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, true);
+
+        // Flip the client hello so we can reuse it in the next test.
+        cHelloStaple.flip();
+
+        // Test with the server-side enable property set to false
+        System.out.println("=========================================");
+        System.out.println("Server Test 2: " +
+                "jdk.tls.server.enableStatusRequestExtension = false");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        session = engine.getSession();
+        serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHelloStaple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, false);
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+
+    /**
+     * Dump a ByteBuffer as a hexdump to stdout.  The dumping routine will
+     * start at the current position of the buffer and run to its limit.
+     * After completing the dump, the position will be returned to its
+     * starting point.
+     *
+     * @param data the ByteBuffer to dump to stdout.
+     *
+     * @return the hexdump of the byte array.
+     */
+    private static String dumpHexBytes(ByteBuffer data) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            int i = 0;
+            data.mark();
+            while (data.hasRemaining()) {
+                if (i % 16 == 0 && i != 0) {
+                    sb.append("\n");
+                }
+                sb.append(String.format("%02X ", data.get()));
+                i++;
+            }
+            data.reset();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tests the ClientHello for the presence (or not) of the status_request
+     * and status_request_v2 hello extensions.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ClientHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param data the ByteBuffer containing the ClientHello bytes
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkClientHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 1) {
+            throw new SSLException("Not a ClientHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and client random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID (if there is one)
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Jump past the cipher suites
+        int csLen = Short.toUnsignedInt(data.getShort());
+        if (csLen != 0) {
+            data.position(data.position() + csLen);
+        }
+
+        // ...and the compression
+        int compLen = Byte.toUnsignedInt(data.get());
+        if (compLen != 0) {
+            data.position(data.position() + compLen);
+        }
+
+        // Now for the fun part.  Go through the extensions and look
+        // for the two status request exts.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.hasRemaining()) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // We should be at the end of the ClientHello
+        data.reset();
+    }
+
+    /**
+     * Tests the ServerHello for the presence (or not) of the status_request
+     * or status_request_v2 hello extension.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ServerHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkServerHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        int startPos = data.position();
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 2) {
+            throw new SSLException("Not a ServerHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and server random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Skip the cipher suite and compression method
+        data.position(data.position() + 3);
+
+        // Go through the extensions and look for the request extension
+        // expected by the caller.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.position() < recLen + startPos + 5) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // Reset the position to the initial spot at the start of this method.
+        data.reset();
+    }
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(logging);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+        Thread.sleep(1000);         // Give the server a second to start up
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(logging);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+        Thread.sleep(1000);
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,711 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.internal.misc.Unsafe;
+import java.lang.reflect.Field;
+
+/*
+ * @test
+ * @summary Test Unsafe.copySwapMemory
+ * @modules java.base/jdk.internal.misc
+ */
+public class CopySwap {
+    private static final boolean DEBUG = Boolean.getBoolean("CopySwap.DEBUG");
+
+    public static final long KB = 1024;
+    public static final long MB = KB * 1024;
+    public static final long GB = MB * 1024;
+
+    private static final Unsafe UNSAFE;
+    private static final int SMALL_COPY_SIZE = 32;
+    private static final int BASE_ALIGNMENT = 16;
+
+    static {
+        try {
+            Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
+            f.setAccessible(true);
+            UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to get Unsafe instance.", e);
+        }
+    }
+
+    private static long alignDown(long value, long alignment) {
+        return value & ~(alignment - 1);
+    }
+
+    private static long alignUp(long value, long alignment) {
+        return (value + alignment - 1) & ~(alignment - 1);
+    }
+
+    private static boolean isAligned(long value, long alignment) {
+        return value == alignDown(value, alignment);
+    }
+
+    private CopySwap() {
+    }
+
+    /**
+     * Generate verification data for a given offset
+     *
+     * The verification data is used to verify that the correct bytes
+     * have indeed been copied and byte swapped.
+     *
+     * The data is generated based on the offset (in bytes) into the
+     * source buffer. For a native buffer the offset is relative to
+     * the base pointer. For a heap array it is relative to the
+     * address of the first array element.
+     *
+     * This method will return the result of doing an elementSize byte
+     * read starting at offset (in bytes).
+     *
+     * @param offset offset into buffer
+     * @param elemSize size (in bytes) of the element
+     *
+     * @return the verification data, only the least significant
+     * elemSize*8 bits are set, zero extended
+     */
+    private long getVerificationDataForOffset(long offset, long elemSize) {
+        byte[] bytes = new byte[(int)elemSize];
+
+        for (long i = 0; i < elemSize; i++) {
+            bytes[(int)i] = (byte)(offset + i);
+        }
+
+        long o = UNSAFE.arrayBaseOffset(byte[].class);
+
+        switch ((int)elemSize) {
+        case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o));
+        case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o));
+        case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o));
+        case 8: return UNSAFE.getLongUnaligned(bytes, o);
+        default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Verify byte swapped data
+     *
+     * @param ptr the data to verify
+     * @param srcOffset the srcOffset (in bytes) from which the copy started,
+     *        used as key to regenerate the verification data
+     * @param dstOffset the offset (in bytes) in the array at which to start
+     *        the verification, relative to the first element in the array
+     * @param size size (in bytes) of data to to verify
+     * @param elemSize size (in bytes) of the individual array elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) {
+        for (long offset = 0; offset < size; offset += elemSize) {
+            long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize);
+            long expected = byteSwap(expectedUnswapped, elemSize);
+
+            long actual = getArrayElem(ptr, dstOffset + offset, elemSize);
+
+            if (expected != actual) {
+                throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) +
+                                           " dstOffset: 0x" + Long.toHexString(dstOffset) +
+                                           " size: 0x" + Long.toHexString(size) +
+                                           " offset: 0x" + Long.toHexString(offset) +
+                                           " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) +
+                                           " expected: 0x" + Long.toHexString(expected) +
+                                           " != actual: 0x" + Long.toHexString(actual));
+            }
+        }
+    }
+
+    /**
+     * Initialize an array with verification friendly data
+     *
+     * @param ptr pointer to the data to initialize
+     * @param size size (in bytes) of the data
+     * @param elemSize size (in bytes) of the individual elements
+     */
+    private void initVerificationData(GenericPointer ptr, long size, long elemSize) {
+        for (long offset = 0; offset < size; offset++) {
+            byte data = (byte)getVerificationDataForOffset(offset, 1);
+
+            if (ptr.isOnHeap()) {
+                UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data);
+            } else {
+                UNSAFE.putByte(ptr.getOffset() + offset, data);
+            }
+        }
+    }
+
+    /**
+     * Allocate a primitive array
+     *
+     * @param size size (in bytes) of all the array elements (elemSize * length)
+     * @param elemSize the size of the array elements
+     *
+     * @return a newly allocated primitive array
+     */
+    Object allocArray(long size, long elemSize) {
+        int length = (int)(size / elemSize);
+
+        switch ((int)elemSize) {
+        case 2: return new short[length];
+        case 4: return new int[length];
+        case 8: return new long[length];
+        default:
+            throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Get the value of a primitive array entry
+     *
+     * @param ptr pointer to the data
+     * @param offset offset (in bytes) of the array element, relative to the first element in the array
+     *
+     * @return the array element, as an unsigned long
+     */
+    private long getArrayElem(GenericPointer ptr, long offset, long elemSize) {
+        if (ptr.isOnHeap()) {
+            Object o = ptr.getObject();
+            int index = (int)(offset / elemSize);
+
+            if (o instanceof short[]) {
+                short[] arr = (short[])o;
+                return Short.toUnsignedLong(arr[index]);
+            } else if (o instanceof int[]) {
+                int[] arr = (int[])o;
+                return Integer.toUnsignedLong(arr[index]);
+            } else if (o instanceof long[]) {
+                long[] arr = (long[])o;
+                return arr[index];
+            } else {
+                throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+            }
+        } else {
+            long addr = ptr.getOffset() + offset;
+
+            switch ((int)elemSize) {
+            case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr));
+            case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr));
+            case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr));
+            case 8: return UNSAFE.getLongUnaligned(null, addr);
+            default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+            }
+        }
+    }
+
+    private void putValue(long addr, long elemSize, long value) {
+        switch ((int)elemSize) {
+        case 1: UNSAFE.putByte(addr, (byte)value); break;
+        case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break;
+        case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break;
+        case 8: UNSAFE.putLongUnaligned(null, addr, value); break;
+        default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+        }
+    }
+
+    /**
+     * Get the size of the elements for an array
+     *
+     * @param o a primitive heap array
+     *
+     * @return the size (in bytes) of the individual array elements
+     */
+    private long getArrayElemSize(Object o) {
+        if (o instanceof short[]) {
+            return 2;
+        } else if (o instanceof int[]) {
+            return 4;
+        } else if (o instanceof long[]) {
+            return 8;
+        } else {
+            throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+        }
+    }
+
+    /**
+     * Byte swap a value
+     *
+     * @param value the value to swap, only the bytes*8 least significant bits are used
+     * @param size size (in bytes) of the value
+     *
+     * @return the byte swapped value in the bytes*8 least significant bits
+     */
+    private long byteSwap(long value, long size) {
+        switch ((int)size) {
+        case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value));
+        case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value));
+        case 8: return Long.reverseBytes(value);
+        default: throw new IllegalArgumentException("Invalid element size: " + size);
+        }
+    }
+
+    /**
+     * Verify data in a heap array which has *not* been byte swapped
+     *
+     * @param ptr the data to verify
+     * @param startOffset the offset (in bytes) at which to start the verification
+     * @param size size (in bytes) of the data to verify
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void verifyUnswappedData(GenericPointer ptr, long startOffset, long size) {
+        for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) {
+            byte expected = (byte)getVerificationDataForOffset(elemOffset, 1);
+
+            byte actual;
+            if (ptr.isOnHeap()) {
+                actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset);
+            } else {
+                actual = UNSAFE.getByte(ptr.getOffset() + elemOffset);
+            }
+
+            if (expected != actual) {
+                throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) +
+                                           " size: 0x" + Long.toHexString(size) +
+                                           " elemOffset: 0x" + Long.toHexString(elemOffset) +
+                                           " expected: 0x" + Long.toHexString(expected) +
+                                           " != actual: 0x" + Long.toHexString(actual));
+            }
+        }
+    }
+
+
+    /**
+     * Copy and byte swap data from the source to the destination
+     *
+     * This method will pre-populate the whole source and destination
+     * buffers with verification friendly data. It will then use
+     * copySwapMemory to fill part of the destination buffer with
+     * swapped data from the source. Some space (padding) will be
+     * left before and after the data in the destination buffer, which
+     * should not be touched/overwritten by the copy call.
+     *
+     * Note: Both source and destination buffers will be overwritten!
+     *
+     * @param src source buffer to copy from
+     * @param srcOffset the offset (in bytes) in the source buffer, relative to
+     *        the first array element, at which to start reading data
+     * @param dst destination buffer to copy to
+     * @param dstOffset the offset (in bytes) in the destination
+     *        buffer, relative to the first array element, at which to
+     *        start writing data
+     * @param bufSize the size (in bytes) of the src and dst arrays
+     * @param copyBytes the size (in bytes) of the copy to perform,
+     *        must be a multiple of elemSize
+     * @param elemSize the size (in bytes) of the elements to byte swap
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testCopySwap(GenericPointer src, long srcOffset,
+                              GenericPointer dst, long dstOffset,
+                              long bufSize, long copyBytes, long elemSize) {
+        if (!isAligned(copyBytes, elemSize)) {
+            throw new IllegalArgumentException(
+                "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) {
+            throw new IllegalArgumentException(
+                "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) {
+            throw new IllegalArgumentException(
+                "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")");
+        }
+        if (srcOffset + copyBytes > bufSize) {
+            throw new IllegalArgumentException(
+                "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+        }
+        if (dstOffset + copyBytes > bufSize) {
+            throw new IllegalArgumentException(
+                "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+        }
+
+        // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes)
+        initVerificationData(src, bufSize, elemSize);
+        if (!src.equals(dst)) {
+            initVerificationData(dst, bufSize, elemSize);
+        }
+
+        if (DEBUG) {
+            System.out.println("===before===");
+            for (int offset = 0; offset < bufSize; offset += elemSize) {
+                long srcValue = getArrayElem(src, offset, elemSize);
+                long dstValue = getArrayElem(dst, offset, elemSize);
+
+                System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+                                 " src=0x" + Long.toHexString(srcValue) +
+                                 " dst=0x" + Long.toHexString(dstValue));
+            }
+        }
+
+        // Copy & swap data into the middle of the destination buffer
+        UNSAFE.copySwapMemory(src.getObject(),
+                              src.getOffset() + srcOffset,
+                              dst.getObject(),
+                              dst.getOffset() + dstOffset,
+                              copyBytes,
+                              elemSize);
+
+        if (DEBUG) {
+            System.out.println("===after===");
+            for (int offset = 0; offset < bufSize; offset += elemSize) {
+                long srcValue = getArrayElem(src, offset, elemSize);
+                long dstValue = getArrayElem(dst, offset, elemSize);
+
+                System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+                                 " src=0x" + Long.toHexString(srcValue) +
+                                 " dst=0x" + Long.toHexString(dstValue));
+            }
+        }
+
+        // Verify the the front padding is unchanged
+        verifyUnswappedData(dst, 0, dstOffset);
+
+        // Verify swapped data
+        verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize);
+
+        // Verify that the back back padding is unchanged
+        long frontAndDataBytes = dstOffset + copyBytes;
+        long trailingBytes = bufSize - frontAndDataBytes;
+        verifyUnswappedData(dst, frontAndDataBytes, trailingBytes);
+    }
+
+    /**
+     * Test various configurations copy-swapping from one buffer to the other
+     *
+     * @param src the source buffer to copy from
+     * @param dst the destination buffer to copy to
+     * @param size size (in bytes) of the buffers
+     * @param elemSize size (in bytes) of the individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) {
+        // offset in source from which to start reading data
+        for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) {
+
+            // offset in destination at which to start writing data
+            for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) {
+
+                // number of bytes to copy
+                long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset);
+                for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) {
+                    try {
+                        testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize);
+                    } catch (RuntimeException e) {
+                        // Wrap the exception in another exception to catch the relevant configuration data
+                        throw new RuntimeException("testBufferPair: " +
+                                                   "src=" + src +
+                                                   " dst=" + dst +
+                                                   " elemSize=0x" + Long.toHexString(elemSize) +
+                                                   " copyBytes=0x" + Long.toHexString(copyBytes) +
+                                                   " srcOffset=0x" + Long.toHexString(srcOffset) +
+                                                   " dstOffset=0x" + Long.toHexString(dstOffset),
+                                                   e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Test copying between various permutations of buffers
+     *
+     * @param buffers buffers to permute (src x dst)
+     * @param size size (in bytes) of buffers
+     * @param elemSize size (in bytes) of individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) {
+        for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) {
+            for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) {
+                testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize);
+            }
+        }
+    }
+
+    /**
+     * Test copying of a specific element size
+     *
+     * @param size size (in bytes) of buffers to allocate
+     * @param elemSize size (in bytes) of individual elements
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testElemSize(long size, long elemSize) {
+        long buf1Raw = 0;
+        long buf2Raw = 0;
+
+        try {
+            buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT);
+
+            buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT);
+
+            GenericPointer[] buffers = {
+                new GenericPointer(buf1),
+                new GenericPointer(buf2),
+                new GenericPointer(allocArray(size, elemSize)),
+                new GenericPointer(allocArray(size, elemSize))
+            };
+
+            testPermuteBuffers(buffers, size, elemSize);
+        } finally {
+            if (buf1Raw != 0) {
+                UNSAFE.freeMemory(buf1Raw);
+            }
+            if (buf2Raw != 0) {
+                UNSAFE.freeMemory(buf2Raw);
+            }
+        }
+    }
+
+    /**
+     * Verify that small copy swaps work
+     */
+    private void testSmallCopy() {
+        int smallBufSize = SMALL_COPY_SIZE;
+
+        // Test various element types and heap/native combinations
+        for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) {
+            testElemSize(smallBufSize, elemSize);
+        }
+    }
+
+
+    /**
+     * Verify that large copy swaps work
+     */
+    private void testLargeCopy() {
+        long size = 2 * GB + 8;
+        long bufRaw = 0;
+
+        // Check that a large native copy succeeds
+        try {
+            try {
+                bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+            } catch (OutOfMemoryError e) {
+                // Accept failure, skip test
+                return;
+            }
+
+            long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+
+            UNSAFE.copySwapMemory(null, buf, null, buf, size, 8);
+        } catch (Exception e) {
+            throw new RuntimeException("copySwapMemory of large buffer failed");
+        } finally {
+            if (bufRaw != 0) {
+                UNSAFE.freeMemory(bufRaw);
+            }
+        }
+    }
+
+    /**
+     * Run positive tests
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testPositive() {
+        testSmallCopy();
+        testLargeCopy();
+    }
+
+    /**
+     * Run negative tests, testing corner cases and the various exceptions
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void testNegative() {
+        long bufRaw = 0;
+
+        try {
+            bufRaw = UNSAFE.allocateMemory(1024);
+            long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+            short[] arr = new short[16];
+
+            // Check various illegal element sizes
+            for (int elemSize = 2; elemSize <= 8; elemSize <<= 1) {
+                long[] illegalSizes = { -1, 1, elemSize - 1, elemSize + 1, elemSize * 2 - 1 };
+                for (long size : illegalSizes) {
+                    try {
+                        // Check that illegal elemSize throws an IAE
+                        UNSAFE.copySwapMemory(null, buf, null, buf, size, elemSize);
+                        throw new RuntimeException("copySwapMemory failed to throw IAE for size=" + size + " elemSize=" + elemSize);
+                    } catch (IllegalArgumentException e) {
+                        // good
+                    }
+                }
+            }
+
+            try {
+                // Check that negative srcOffset throws an IAE
+                UNSAFE.copySwapMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset=-1");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            try {
+                // Check that negative dstOffset throws an IAE
+                UNSAFE.copySwapMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset=-1");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            long illegalElemSizes[] = { 0, 1, 3, 5, 6, 7, 9, 10, -1 };
+            for (long elemSize : illegalElemSizes) {
+                try {
+                    // Check that elemSize 1 throws an IAE
+                    UNSAFE.copySwapMemory(null, buf, null, buf, 16, elemSize);
+                    throw new RuntimeException("copySwapMemory failed to throw NPE");
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+            }
+
+            try {
+                // Check that a NULL source throws NPE
+                UNSAFE.copySwapMemory(null, 0, null, buf, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (NullPointerException e) {
+                // good
+            }
+
+            try {
+                // Check that a NULL destination throws NPE
+                UNSAFE.copySwapMemory(null, buf, null, 0, 16, 2);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (NullPointerException e) {
+                // good
+            }
+
+            try {
+                // Check that a reference array destination throws IAE
+                UNSAFE.copySwapMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16, 8);
+                throw new RuntimeException("copySwapMemory failed to throw NPE");
+            } catch (IllegalArgumentException e) {
+                // good
+            }
+
+            // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms)
+            if (UNSAFE.addressSize() == 4) {
+                long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits
+
+                try {
+                    // Check that an invalid (not 32-bit clean) source pointer throws IAE
+                    UNSAFE.copySwapMemory(null, invalidPtr, null, buf, 16, 2);
+                    throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset 0x" +
+                                               Long.toHexString(invalidPtr));
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+
+                try {
+                    // Check that an invalid (not 32-bit clean) source pointer throws IAE
+                    UNSAFE.copySwapMemory(null, buf, null, invalidPtr, 16, 2);
+                    throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset 0x" +
+                                               Long.toHexString(invalidPtr));
+                } catch (IllegalArgumentException e) {
+                    // good
+                }
+            }
+        } finally {
+            if (bufRaw != 0) {
+                UNSAFE.freeMemory(bufRaw);
+            }
+        }
+    }
+
+    /**
+     * Run all tests
+     *
+     * @throws RuntimeException if an error is found
+     */
+    private void test() {
+        testPositive();
+        testNegative();
+    }
+
+    public static void main(String[] args) {
+        CopySwap cs = new CopySwap();
+        cs.test();
+    }
+
+    /**
+     * Helper class to represent a "pointer" - either a heap array or
+     * a pointer to a native buffer.
+     *
+     * In the case of a native pointer, the Object is null and the offset is
+     * the absolute address of the native buffer.
+     *
+     * In the case of a heap object, the Object is a primitive array, and
+     * the offset will be set to the base offset to the first element, meaning
+     * the object and the offset together form a double-register pointer.
+     */
+    static class GenericPointer {
+        private final Object o;
+        private final long offset;
+
+        private GenericPointer(Object o, long offset) {
+            this.o = o;
+            this.offset = offset;
+        }
+
+        public String toString() {
+            return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")";
+        }
+
+        public boolean equals(Object other) {
+            if (!(other instanceof GenericPointer)) {
+                return false;
+            }
+
+            GenericPointer otherp = (GenericPointer)other;
+
+            return o == otherp.o && offset == otherp.offset;
+        }
+
+        GenericPointer(Object o) {
+            this(o, UNSAFE.arrayBaseOffset(o.getClass()));
+        }
+
+        GenericPointer(long offset) {
+            this(null, offset);
+        }
+
+        public boolean isOnHeap() {
+            return o != null;
+        }
+
+        public Object getObject() {
+            return o;
+        }
+
+        public long getOffset() {
+            return offset;
+        }
+    }
+}
--- a/jdk/test/sun/misc/SunMiscSignalTest.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/sun/misc/SunMiscSignalTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -180,6 +180,12 @@
         return newArray;
     }
 
+    // Return true if the signal is one of the shutdown signals known to the VM
+    private static boolean isShutdownSignal(Signal signal) {
+        String name = signal.getName();
+        return name.equals("INT") || name.equals("HUP") || name.equals("TERM");
+    }
+
     /**
      * Quick verification of supported signals using sun.misc.Signal.
      *
@@ -201,14 +207,24 @@
             Assert.assertEquals(signal.toString(), "SIG" + name, "toString() mismatch, ");
 
             try {
-                SignalHandler old = Signal.handle(signal, h);
+                orig = Signal.handle(signal, h);
+                printf("oldHandler: %s%n", orig);
                 Assert.assertEquals(CanRegister.YES, register, "Unexpected handle succeeded " + name);
                 try {
                     Signal.raise(signal);
                     Assert.assertEquals(CanRaise.YES, raise, "Unexpected raise success for " + name);
                     Invoked inv = h.semaphore().tryAcquire(Utils.adjustTimeout(100L),
                             TimeUnit.MILLISECONDS) ? Invoked.YES : Invoked.NO;
-                    Assert.assertEquals(inv, invoked, "handler not invoked;");
+                    if (!isShutdownSignal(signal)) {
+                        // Normal case
+                        Assert.assertEquals(inv, invoked, "handler not invoked;");
+                    } else {
+                        if (orig == SignalHandler.SIG_IGN) {
+                            Assert.assertEquals(inv, Invoked.NO, "handler should not be invoked");
+                        } else {
+                            Assert.assertEquals(inv, invoked, "handler not invoked;");
+                        }
+                    }
                 } catch (IllegalArgumentException uoe3) {
                     Assert.assertNotEquals(CanRaise.YES, raise, "raise failed for " + name +
                             ": " + uoe3.getMessage());
@@ -270,14 +286,22 @@
     }
 
     // Test expected exception when raising a signal when no handler defined
-    @Test(expectedExceptions = IllegalArgumentException.class)
+    @Test
     static void testRaiseNoConsumer() {
         Signal signal = new Signal("INT");
         SignalHandler orig = null;
         try {
-            Signal.handle(signal, SignalHandler.SIG_DFL);
+            orig = Signal.handle(signal, SignalHandler.SIG_DFL);
+            printf("oldHandler: %s%n", orig);
+            if (orig == SignalHandler.SIG_IGN) {
+                // SIG_IGN for TERM means it cannot be handled
+                return;
+            }
             Signal.raise(signal);
-        }  finally {
+            Assert.fail("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            printf("IAE message: %s%n", iae.getMessage());
+        } finally {
             // Restore original signal handler
             if (orig != null && signal != null) {
                 Signal.handle(signal, orig);
@@ -296,7 +320,13 @@
         }
         Handler handler = new Handler();
         Signal signal = new Signal("INT");
-        Signal.handle(signal, handler);
+        SignalHandler orig = Signal.handle(signal, handler);
+        printf("oldHandler: %s%n", orig);
+        if (orig == SignalHandler.SIG_IGN) {
+            // SIG_IGN for INT means it cannot be handled
+            return;
+        }
+
         Signal.raise(signal);
         boolean handled = handler.semaphore()
                 .tryAcquire(Utils.adjustTimeout(100L), TimeUnit.MILLISECONDS);
@@ -332,6 +362,10 @@
         Handler h1 = new Handler();
         Handler h2 = new Handler();
         SignalHandler orig = Signal.handle(signal, h1);
+        if (orig == SignalHandler.SIG_IGN) {
+            // SIG_IGN for TERM means it cannot be handled
+            return;
+        }
 
         try {
             SignalHandler prev = Signal.handle(signal, h2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/net/www/protocol/jar/MultiReleaseJarURLConnection.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8132734
+ * @summary Test that URL connections to multi-release jars can be runtime versioned
+ * @library /lib/testlibrary/java/util/jar
+ * @build Compiler JarBuilder CreateMultiReleaseTestJars
+ * @run testng MultiReleaseJarURLConnection
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.jar.JarFile;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class MultiReleaseJarURLConnection {
+    String userdir = System.getProperty("user.dir",".");
+    String urlFile = "jar:file:" + userdir + "/multi-release.jar!/";
+    String urlEntry = urlFile + "version/Version.java";
+
+    @BeforeClass
+    public void initialize() throws Exception {
+        CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
+        creator.compileEntries();
+        creator.buildMultiReleaseJar();
+    }
+
+    @AfterClass
+    public void close() throws IOException {
+        Files.delete(Paths.get(userdir, "multi-release.jar"));
+    }
+
+    @Test
+    public void testRuntimeVersioning() throws Exception {
+        Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8"));
+        // #runtime is "magic"
+        Assert.assertTrue(readAndCompare(new URL(urlEntry + "#runtime"), "return 9"));
+        // #fragment or any other fragment is not magic
+        Assert.assertTrue(readAndCompare(new URL(urlEntry + "#fragment"), "return 8"));
+        // cached entities not affected
+        Assert.assertTrue(readAndCompare(new URL(urlEntry), "return 8"));
+    }
+
+    @Test
+    public void testCachedJars() throws Exception {
+        URL rootUrl = new URL(urlFile);
+        JarURLConnection juc = (JarURLConnection)rootUrl.openConnection();
+        JarFile rootJar = juc.getJarFile();
+        JarFile.Release root = rootJar.getVersion();
+
+        URL runtimeUrl = new URL(urlFile + "#runtime");
+        juc = (JarURLConnection)runtimeUrl.openConnection();
+        JarFile runtimeJar = juc.getJarFile();
+        JarFile.Release runtime = runtimeJar.getVersion();
+        Assert.assertNotEquals(root, runtime);
+
+        juc = (JarURLConnection)rootUrl.openConnection();
+        JarFile jar = juc.getJarFile();
+        Assert.assertEquals(jar.getVersion(), root);
+        Assert.assertEquals(jar, rootJar);
+
+        juc = (JarURLConnection)runtimeUrl.openConnection();
+        jar = juc.getJarFile();
+        Assert.assertEquals(jar.getVersion(), runtime);
+        Assert.assertEquals(jar, runtimeJar);
+
+        rootJar.close();
+        runtimeJar.close();
+        jar.close(); // probably not needed
+    }
+
+    private boolean readAndCompare(URL url, String match) throws Exception {
+        boolean result;
+        // necessary to do it this way, instead of openStream(), so we can
+        // close underlying JarFile, otherwise windows can't delete the file
+        URLConnection conn = url.openConnection();
+        try (InputStream is = conn.getInputStream()) {
+            byte[] bytes = is.readAllBytes();
+            result = (new String(bytes)).contains(match);
+        }
+        if (conn instanceof JarURLConnection) {
+            ((JarURLConnection)conn).getJarFile().close();
+        }
+        return result;
+    }
+}
--- a/jdk/test/tools/pack200/Pack200Test.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/tools/pack200/Pack200Test.java	Mon Feb 29 15:42:34 2016 +0000
@@ -81,7 +81,9 @@
                 System.out.println("Packing [" + in.toString() + "]");
                 // Call the packer
                 Utils.pack(jarFile, packFile);
+                System.out.println("Done Packing [" + in.toString() + "]");
                 jarFile.close();
+                System.out.println("Start leak check");
                 leakCheck();
 
                 System.out.println("  Unpacking using java unpacker");
--- a/jdk/test/tools/pack200/Utils.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/jdk/test/tools/pack200/Utils.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -324,6 +324,9 @@
     private static void findFiles0(File startDir, List<File> list,
                                     FileFilter filter) throws IOException {
         File[] foundFiles = startDir.listFiles(filter);
+        if (foundFiles == null) {
+            return;
+        }
         list.addAll(Arrays.asList(foundFiles));
         File[] dirs = startDir.listFiles(DIR_FILTER);
         for (File dir : dirs) {
--- a/langtools/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -349,3 +349,4 @@
 3f60a4808377a276f6398ff19e61c1b9086f4d97 jdk-9+104
 81bd82222f8a1f2b291a44a49e063973caa4e73b jdk-9+105
 dd05d3761a341143ef4a6b1a245e0960cc125b76 jdk-9+106
+7a0c343551497bd0e38ad69a77cc57d9f396615a jdk-9+107
--- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,12 +28,7 @@
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
-import java.util.Locale;
 import java.util.Map;
-import java.util.logging.Logger;
-import java.util.logging.Level;
-
-import static java.util.logging.Level.*;
 
 /**
  * Provides methods for locating tool providers, for example,
@@ -45,47 +40,6 @@
  */
 public class ToolProvider {
 
-    private static final String propertyName = "sun.tools.ToolProvider";
-    private static final String loggerName   = "javax.tools";
-
-    /*
-     * Define the system property "sun.tools.ToolProvider" to enable
-     * debugging:
-     *
-     *     java ... -Dsun.tools.ToolProvider ...
-     */
-    static <T> T trace(Level level, Object reason) {
-        // NOTE: do not make this method private as it affects stack traces
-        try {
-            if (System.getProperty(propertyName) != null) {
-                StackTraceElement[] st = Thread.currentThread().getStackTrace();
-                String method = "???";
-                String cls = ToolProvider.class.getName();
-                if (st.length > 2) {
-                    StackTraceElement frame = st[2];
-                    method = String.format((Locale)null, "%s(%s:%s)",
-                                           frame.getMethodName(),
-                                           frame.getFileName(),
-                                           frame.getLineNumber());
-                    cls = frame.getClassName();
-                }
-                Logger logger = Logger.getLogger(loggerName);
-                if (reason instanceof Throwable) {
-                    logger.logp(level, cls, method,
-                                reason.getClass().getName(), (Throwable)reason);
-                } else {
-                    logger.logp(level, cls, method, String.valueOf(reason));
-                }
-            }
-        } catch (SecurityException ex) {
-            System.err.format((Locale)null, "%s: %s; %s%n",
-                              ToolProvider.class.getName(),
-                              reason,
-                              ex.getLocalizedMessage());
-        }
-        return null;
-    }
-
     private static final String systemJavaCompilerName
         = "com.sun.tools.javac.api.JavacTool";
 
@@ -153,7 +107,7 @@
         try {
             return c.asSubclass(clazz).newInstance();
         } catch (InstantiationException | IllegalAccessException | RuntimeException | Error e) {
-            return trace(WARNING, e);
+            throw new Error(e);
         }
     }
 
@@ -164,7 +118,7 @@
             try {
                 c = Class.forName(name, false, ClassLoader.getSystemClassLoader());
             } catch (ClassNotFoundException | RuntimeException | Error e) {
-                return trace(WARNING, e);
+                throw new Error(e);
             }
             toolClasses.put(name, new WeakReference<>(c));
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -155,8 +155,6 @@
         allowDefaultMethods = source.allowDefaultMethods();
         allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
         sourceName = source.name;
-        relax = (options.isSet("-retrofit") ||
-                options.isSet("-relax"));
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
 
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
@@ -168,10 +166,6 @@
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
     }
 
-    /** Switch: relax some constraints for retrofit mode.
-     */
-    boolean relax;
-
     /** Switch: support target-typing inference
      */
     boolean allowPoly;
@@ -1025,8 +1019,7 @@
                         log.error(tree.pos(),
                                   "default.allowed.in.intf.annotation.member");
                 }
-                if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0 &&
-                    !relax)
+                if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0)
                     log.error(tree.pos(), "missing.meth.body.or.decl.abstract");
             } else if ((tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) {
                 if ((owner.flags() & INTERFACE) != 0) {
@@ -4384,8 +4377,7 @@
         // If this is a non-abstract class, check that it has no abstract
         // methods or unimplemented methods of an implemented interface.
         if ((c.flags() & (ABSTRACT | INTERFACE)) == 0) {
-            if (!relax)
-                chk.checkAllDefined(tree.pos(), c);
+            chk.checkAllDefined(tree.pos(), c);
         }
 
         if ((c.flags() & ANNOTATION) != 0) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Feb 29 15:42:34 2016 +0000
@@ -81,8 +81,6 @@
     private final Types types;
     private final TypeAnnotations typeAnnotations;
     private final JCDiagnostic.Factory diags;
-    private boolean warnOnSyntheticConflicts;
-    private boolean suppressAbortOnBadClassFile;
     private final JavaFileManager fileManager;
     private final Source source;
     private final Profile profile;
@@ -130,8 +128,6 @@
         allowStrictMethodClashCheck = source.allowStrictMethodClashCheck();
         allowPrivateSafeVarargs = source.allowPrivateSafeVarargs();
         allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
-        warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
-        suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
         warnOnAccessToSensitiveMembers = options.isSet("warnOnAccessToSensitiveMembers");
 
         Target target = Target.instance(context);
@@ -269,8 +265,7 @@
      */
     public Type completionError(DiagnosticPosition pos, CompletionFailure ex) {
         log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, pos, "cant.access", ex.sym, ex.getDetailValue());
-        if (ex instanceof ClassFinder.BadClassFile
-                && !suppressAbortOnBadClassFile) throw new Abort();
+        if (ex instanceof ClassFinder.BadClassFile) throw new Abort();
         else return syms.errType;
     }
 
@@ -2632,12 +2627,7 @@
      */
     private void syntheticError(DiagnosticPosition pos, Symbol sym) {
         if (!sym.type.isErroneous()) {
-            if (warnOnSyntheticConflicts) {
-                log.warning(pos, "synthetic.name.conflict", sym, sym.location());
-            }
-            else {
-                log.error(pos, "synthetic.name.conflict", sym, sym.location());
-            }
+            log.error(pos, "synthetic.name.conflict", sym, sym.location());
         }
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,9 +44,11 @@
 import com.sun.tools.javac.comp.Resolve.InapplicableMethodException;
 import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode;
 
-import java.io.File;
-import java.io.FileWriter;
 import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -353,9 +355,9 @@
                         rsContext.attrMode(),
                         rsContext.step,
                         round);
-                File dotFile = new File(dependenciesFolder, filename);
-                try (FileWriter fw = new FileWriter(dotFile)) {
-                    fw.append(graph);
+                Path dotFile = Paths.get(dependenciesFolder, filename);
+                try (Writer w = Files.newBufferedWriter(dotFile)) {
+                    w.append(graph);
                 }
                 round++;
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java	Mon Feb 29 15:42:34 2016 +0000
@@ -267,7 +267,14 @@
      * @return true if successful, and false otherwise
      */
     public boolean handleOption(Option option, String value) {
-        return locations.handleOption(option, value);
+        switch (option) {
+            case ENCODING:
+                encodingName = value;
+                return true;
+
+            default:
+                return locations.handleOption(option, value);
+        }
     }
 
     /**
@@ -285,6 +292,7 @@
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="Encoding">
+    private String encodingName;
     private String defaultEncodingName;
     private String getDefaultEncodingName() {
         if (defaultEncodingName == null) {
@@ -295,11 +303,7 @@
     }
 
     public String getEncodingName() {
-        String encName = options.get(Option.ENCODING);
-        if (encName == null)
-            return getDefaultEncodingName();
-        else
-            return encName;
+        return (encodingName != null) ? encodingName : getDefaultEncodingName();
     }
 
     @SuppressWarnings("cast")
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Mon Feb 29 15:42:34 2016 +0000
@@ -425,7 +425,7 @@
         if (container.endsWith("bootmodules.jimage")) {
             System.err.println("Warning: reference to bootmodules.jimage replaced by jrt:");
             container = Locations.JRT_MARKER_FILE;
-        } else if (container.getFileName().toString().endsWith(".jimage")) {
+        } else if (container.getNameCount() > 0 && container.getFileName().toString().endsWith(".jimage")) {
             System.err.println("Warning: reference to " + container + " ignored");
             return;
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -72,18 +72,6 @@
      */
     private boolean verbose;
 
-    /** Switch: scramble private field names.
-     */
-    private boolean scramble;
-
-    /** Switch: scramble all field names.
-     */
-    private boolean scrambleAll;
-
-    /** Switch: retrofit mode.
-     */
-    private boolean retrofit;
-
     /** Switch: emit source file attribute.
      */
     private boolean emitSourceFile;
@@ -184,9 +172,6 @@
         signatureGen = new CWSignatureGenerator(types);
 
         verbose        = options.isSet(VERBOSE);
-        scramble       = options.isSet("-scramble");
-        scrambleAll    = options.isSet("-scrambleAll");
-        retrofit       = options.isSet("-retrofit");
         genCrt         = options.isSet(XJCOV);
         debugstackmap  = options.isSet("debugstackmap");
 
@@ -491,26 +476,11 @@
         putChar(poolbuf, poolCountIdx, pool.pp);
     }
 
-    /** Given a field, return its name.
-     */
-    Name fieldName(Symbol sym) {
-        if (scramble && (sym.flags() & PRIVATE) != 0 ||
-            scrambleAll && (sym.flags() & (PROTECTED | PUBLIC)) == 0)
-            return names.fromString("_$" + sym.name.getIndex());
-        else
-            return sym.name;
-    }
-
     /** Given a symbol, return its name-and-type.
      */
     NameAndType nameType(Symbol sym) {
-        return new NameAndType(fieldName(sym),
-                               retrofit
-                               ? sym.erasure(types)
-                               : sym.externalType(types), types);
-        // if we retrofit, then the NameAndType has been read in as is
-        // and no change is necessary. If we compile normally, the
-        // NameAndType is generated from a symbol reference, and the
+        return new NameAndType(sym.name, sym.externalType(types), types);
+        // the NameAndType is generated from a symbol reference, and the
         // adjustment of adding an additional this$n parameter needs to be made.
     }
 
@@ -1055,10 +1025,10 @@
         databuf.appendChar(flags);
         if (dumpFieldModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
-            pw.println("FIELD  " + fieldName(v));
+            pw.println("FIELD  " + v.name);
             pw.println("---" + flagNames(v.flags()));
         }
-        databuf.appendChar(pool.put(fieldName(v)));
+        databuf.appendChar(pool.put(v.name));
         databuf.appendChar(pool.put(typeSig(v.erasure(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
@@ -1079,10 +1049,10 @@
         databuf.appendChar(flags);
         if (dumpMethodModifiers) {
             PrintWriter pw = log.getWriter(Log.WriterKind.ERROR);
-            pw.println("METHOD  " + fieldName(m));
+            pw.println("METHOD  " + m.name);
             pw.println("---" + flagNames(m.flags()));
         }
-        databuf.appendChar(pool.put(fieldName(m)));
+        databuf.appendChar(pool.put(m.name));
         databuf.appendChar(pool.put(typeSig(m.externalType(types))));
         int acountIdx = beginAttrs();
         int acount = 0;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -120,25 +120,11 @@
             : options.isSet(G_CUSTOM, "vars");
         genCrt = options.isSet(XJCOV);
         debugCode = options.isSet("debugcode");
-        allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
         allowBetterNullChecks = target.hasObjects();
         pool = new Pool(types);
 
         // ignore cldc because we cannot have both stackmap formats
         this.stackMap = StackMapFormat.JSR202;
-
-        // by default, avoid jsr's for simple finalizers
-        int setjsrlimit = 50;
-        String jsrlimitString = options.get("jsrlimit");
-        if (jsrlimitString != null) {
-            try {
-                setjsrlimit = Integer.parseInt(jsrlimitString);
-            } catch (NumberFormatException ex) {
-                // ignore ill-formed numbers for jsrlimit
-            }
-        }
-        this.jsrlimit = setjsrlimit;
-        this.useJsrLocally = false; // reset in visitTry
         annotate = Annotate.instance(context);
     }
 
@@ -148,19 +134,8 @@
     private final boolean varDebugInfo;
     private final boolean genCrt;
     private final boolean debugCode;
-    private final boolean allowInvokedynamic;
     private final boolean allowBetterNullChecks;
 
-    /** Default limit of (approximate) size of finalizer to inline.
-     *  Zero means always use jsr.  100 or greater means never use
-     *  jsr.
-     */
-    private final int jsrlimit;
-
-    /** True if jsr is used.
-     */
-    private boolean useJsrLocally;
-
     /** Code buffer, set by genMethod.
      */
     private Code code;
@@ -1339,31 +1314,11 @@
         // in a new environment which calls the finally block if there is one.
         final Env<GenContext> tryEnv = env.dup(tree, new GenContext());
         final Env<GenContext> oldEnv = env;
-        if (!useJsrLocally) {
-            useJsrLocally =
-                (stackMap == StackMapFormat.NONE) &&
-                (jsrlimit <= 0 ||
-                jsrlimit < 100 &&
-                estimateCodeComplexity(tree.finalizer)>jsrlimit);
-        }
         tryEnv.info.finalize = new GenFinalizer() {
             void gen() {
-                if (useJsrLocally) {
-                    if (tree.finalizer != null) {
-                        Code.State jsrState = code.state.dup();
-                        jsrState.push(Code.jsrReturnValue);
-                        tryEnv.info.cont =
-                            new Chain(code.emitJump(jsr),
-                                      tryEnv.info.cont,
-                                      jsrState);
-                    }
-                    Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curCP());
-                } else {
-                    Assert.check(tryEnv.info.gaps.length() % 2 == 0);
-                    tryEnv.info.gaps.append(code.curCP());
-                    genLast();
-                }
+                Assert.check(tryEnv.info.gaps.length() % 2 == 0);
+                tryEnv.info.gaps.append(code.curCP());
+                genLast();
             }
             void genLast() {
                 if (tree.finalizer != null)
@@ -1568,93 +1523,6 @@
             }
         }
 
-    /** Very roughly estimate the number of instructions needed for
-     *  the given tree.
-     */
-    int estimateCodeComplexity(JCTree tree) {
-        if (tree == null) return 0;
-        class ComplexityScanner extends TreeScanner {
-            int complexity = 0;
-            public void scan(JCTree tree) {
-                if (complexity > jsrlimit) return;
-                super.scan(tree);
-            }
-            public void visitClassDef(JCClassDecl tree) {}
-            public void visitDoLoop(JCDoWhileLoop tree)
-                { super.visitDoLoop(tree); complexity++; }
-            public void visitWhileLoop(JCWhileLoop tree)
-                { super.visitWhileLoop(tree); complexity++; }
-            public void visitForLoop(JCForLoop tree)
-                { super.visitForLoop(tree); complexity++; }
-            public void visitSwitch(JCSwitch tree)
-                { super.visitSwitch(tree); complexity+=5; }
-            public void visitCase(JCCase tree)
-                { super.visitCase(tree); complexity++; }
-            public void visitSynchronized(JCSynchronized tree)
-                { super.visitSynchronized(tree); complexity+=6; }
-            public void visitTry(JCTry tree)
-                { super.visitTry(tree);
-                  if (tree.finalizer != null) complexity+=6; }
-            public void visitCatch(JCCatch tree)
-                { super.visitCatch(tree); complexity+=2; }
-            public void visitConditional(JCConditional tree)
-                { super.visitConditional(tree); complexity+=2; }
-            public void visitIf(JCIf tree)
-                { super.visitIf(tree); complexity+=2; }
-            // note: for break, continue, and return we don't take unwind() into account.
-            public void visitBreak(JCBreak tree)
-                { super.visitBreak(tree); complexity+=1; }
-            public void visitContinue(JCContinue tree)
-                { super.visitContinue(tree); complexity+=1; }
-            public void visitReturn(JCReturn tree)
-                { super.visitReturn(tree); complexity+=1; }
-            public void visitThrow(JCThrow tree)
-                { super.visitThrow(tree); complexity+=1; }
-            public void visitAssert(JCAssert tree)
-                { super.visitAssert(tree); complexity+=5; }
-            public void visitApply(JCMethodInvocation tree)
-                { super.visitApply(tree); complexity+=2; }
-            public void visitNewClass(JCNewClass tree)
-                { scan(tree.encl); scan(tree.args); complexity+=2; }
-            public void visitNewArray(JCNewArray tree)
-                { super.visitNewArray(tree); complexity+=5; }
-            public void visitAssign(JCAssign tree)
-                { super.visitAssign(tree); complexity+=1; }
-            public void visitAssignop(JCAssignOp tree)
-                { super.visitAssignop(tree); complexity+=2; }
-            public void visitUnary(JCUnary tree)
-                { complexity+=1;
-                  if (tree.type.constValue() == null) super.visitUnary(tree); }
-            public void visitBinary(JCBinary tree)
-                { complexity+=1;
-                  if (tree.type.constValue() == null) super.visitBinary(tree); }
-            public void visitTypeTest(JCInstanceOf tree)
-                { super.visitTypeTest(tree); complexity+=1; }
-            public void visitIndexed(JCArrayAccess tree)
-                { super.visitIndexed(tree); complexity+=1; }
-            public void visitSelect(JCFieldAccess tree)
-                { super.visitSelect(tree);
-                  if (tree.sym.kind == VAR) complexity+=1; }
-            public void visitIdent(JCIdent tree) {
-                if (tree.sym.kind == VAR) {
-                    complexity+=1;
-                    if (tree.type.constValue() == null &&
-                        tree.sym.owner.kind == TYP)
-                        complexity+=1;
-                }
-            }
-            public void visitLiteral(JCLiteral tree)
-                { complexity+=1; }
-            public void visitTree(JCTree tree) {}
-            public void visitWildcard(JCWildcard tree) {
-                throw new AssertionError(this.getClass().getName());
-            }
-        }
-        ComplexityScanner scanner = new ComplexityScanner();
-        tree.accept(scanner);
-        return scanner.complexity;
-    }
-
     public void visitIf(JCIf tree) {
         int limit = code.nextreg;
         Chain thenExit = null;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,10 @@
 
 package com.sun.tools.javac.main;
 
-import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
@@ -73,7 +74,7 @@
 
     private String ownName;
     private Set<String> classNames;
-    private Set<File> files;
+    private Set<Path> files;
     private Map<Option, String> deferredFileManagerOptions;
     private Set<JavaFileObject> fileObjects;
     private final Options options;
@@ -153,8 +154,8 @@
         }
 
         @Override
-        public void addFile(File f) {
-            files.add(f);
+        public void addFile(Path p) {
+            files.add(p);
         }
 
         @Override
@@ -252,7 +253,7 @@
             } else {
                 fileObjects = new LinkedHashSet<>();
                 JavacFileManager jfm = (JavacFileManager) getFileManager();
-                for (JavaFileObject fo: jfm.getJavaFileObjectsFromFiles(files))
+                for (JavaFileObject fo: jfm.getJavaFileObjectsFromPaths(files))
                     fileObjects.add(fo);
             }
         }
@@ -583,8 +584,8 @@
         if (value == null) {
             return true;
         }
-        File file = new File(value);
-        if (file.exists() && !file.isDirectory()) {
+        Path file = Paths.get(value);
+        if (Files.exists(file) && !Files.isDirectory(file)) {
             error("err.file.not.directory", value);
             return false;
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/CommandLine.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,9 +27,10 @@
 
 import java.io.IOException;
 import java.io.Reader;
-import java.io.FileReader;
-import java.io.BufferedReader;
 import java.io.StreamTokenizer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
 import com.sun.tools.javac.util.ListBuffer;
 
 /**
@@ -73,7 +74,7 @@
     private static void loadCmdFile(String name, ListBuffer<String> args)
         throws IOException
     {
-        try (Reader r = new BufferedReader(new FileReader(name))) {
+        try (Reader r = Files.newBufferedReader(Paths.get(name))) {
             StreamTokenizer st = new StreamTokenizer(r);
             st.resetSyntax();
             st.wordChars(' ', 255);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Mon Feb 29 15:42:34 2016 +0000
@@ -389,10 +389,6 @@
 
         verbose       = options.isSet(VERBOSE);
         sourceOutput  = options.isSet(PRINTSOURCE); // used to be -s
-        stubOutput    = options.isSet("-stubs");
-        relax         = options.isSet("-relax");
-        printFlat     = options.isSet("-printflat");
-        encoding      = options.get(ENCODING);
         lineDebugInfo = options.isUnset(G_CUSTOM) ||
                         options.isSet(G_CUSTOM, "lines");
         genEndPos     = options.isSet(XJCOV) ||
@@ -447,21 +443,6 @@
      */
     public boolean sourceOutput;
 
-    /** Emit stub source files rather than class files.
-     */
-    public boolean stubOutput;
-
-    /** Switch: relax some constraints for producing the jsr14 prototype.
-     */
-    boolean relax;
-
-    /** Debug switch: Emit Java sources after inner class flattening.
-     */
-    public boolean printFlat;
-
-    /** The encoding to be used for source input.
-     */
-    public String encoding;
 
     /** Generate code with the LineNumberTable attribute for debugging
      */
@@ -611,7 +592,7 @@
     // where
         public boolean keepComments = false;
         protected boolean keepComments() {
-            return keepComments || sourceOutput || stubOutput;
+            return keepComments || sourceOutput;
         }
 
 
@@ -676,30 +657,6 @@
         }
     }
 
-    /** Emit plain Java source for a class.
-     *  @param env    The attribution environment of the outermost class
-     *                containing this class.
-     *  @param cdef   The class definition to be printed.
-     */
-    JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
-        JavaFileObject outFile
-            = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
-                                               cdef.sym.flatname.toString(),
-                                               JavaFileObject.Kind.SOURCE,
-                                               null);
-        if (inputFiles.contains(outFile)) {
-            log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
-            return null;
-        } else {
-            try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
-                new Pretty(out, true).printUnit(env.toplevel, cdef);
-                if (verbose)
-                    log.printVerbose("wrote.file", outFile);
-            }
-            return outFile;
-        }
-    }
-
     /** Generate code and emit a class file for a given class
      *  @param env    The attribution environment of the outermost class
      *                containing this class.
@@ -720,6 +677,30 @@
         return null;
     }
 
+    /** Emit plain Java source for a class.
+     *  @param env    The attribution environment of the outermost class
+     *                containing this class.
+     *  @param cdef   The class definition to be printed.
+     */
+    JavaFileObject printSource(Env<AttrContext> env, JCClassDecl cdef) throws IOException {
+        JavaFileObject outFile
+           = fileManager.getJavaFileForOutput(CLASS_OUTPUT,
+                                               cdef.sym.flatname.toString(),
+                                               JavaFileObject.Kind.SOURCE,
+                                               null);
+        if (inputFiles.contains(outFile)) {
+            log.error(cdef.pos(), "source.cant.overwrite.input.file", outFile);
+            return null;
+        } else {
+            try (BufferedWriter out = new BufferedWriter(outFile.openWriter())) {
+                new Pretty(out, true).printUnit(env.toplevel, cdef);
+                if (verbose)
+                    log.printVerbose("wrote.file", outFile);
+            }
+            return outFile;
+        }
+    }
+
     /** Compile a source file that has been accessed by the class finder.
      *  @param c          The class the source file of which needs to be compiled.
      */
@@ -898,12 +879,6 @@
     }
 
     /**
-     * Set needRootClasses to true, in JavaCompiler subclass constructor
-     * that want to collect public apis of classes supplied on the command line.
-     */
-    protected boolean needRootClasses = false;
-
-    /**
      * The list of classes explicitly supplied on the command line for compilation.
      * Not always populated.
      */
@@ -966,7 +941,7 @@
         // If generating source, or if tracking public apis,
         // then remember the classes declared in
         // the original compilation units listed on the command line.
-        if (needRootClasses || sourceOutput || stubOutput) {
+        if (sourceOutput) {
             ListBuffer<JCClassDecl> cdefs = new ListBuffer<>();
             for (JCCompilationUnit unit : roots) {
                 for (List<JCTree> defs = unit.defs;
@@ -1275,11 +1250,6 @@
             if (shouldStop(CompileState.FLOW))
                 return;
 
-            if (relax) {
-                results.add(env);
-                return;
-            }
-
             if (verboseCompilePolicy)
                 printNote("[flow " + env.enclClass.sym + "]");
             JavaFileObject prev = log.useSource(
@@ -1419,9 +1389,9 @@
             TreeMaker localMake = make.forToplevel(env.toplevel);
 
             if (env.tree.hasTag(JCTree.Tag.PACKAGEDEF)) {
-                if (!(stubOutput || sourceOutput || printFlat)) {
+                if (!(sourceOutput)) {
                     if (shouldStop(CompileState.LOWER))
-                        return;
+                       return;
                     List<JCTree> pdef = lower.translateTopLevelClass(env, env.tree, localMake);
                     if (pdef.head != null) {
                         Assert.check(pdef.tail.isEmpty());
@@ -1431,19 +1401,6 @@
                 return;
             }
 
-            if (stubOutput) {
-                //emit stub Java source file, only for compilation
-                //units enumerated explicitly on the command line
-                JCClassDecl cdef = (JCClassDecl)env.tree;
-                if (untranslated instanceof JCClassDecl &&
-                    rootClasses.contains((JCClassDecl)untranslated) &&
-                    ((cdef.mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 ||
-                     cdef.sym.packge().getQualifiedName() == names.java_lang)) {
-                    results.add(new Pair<>(env, removeMethodBodies(cdef)));
-                }
-                return;
-            }
-
             if (shouldStop(CompileState.TRANSTYPES))
                 return;
 
@@ -1504,16 +1461,12 @@
         if (shouldStop(CompileState.GENERATE))
             return;
 
-        boolean usePrintSource = (stubOutput || sourceOutput || printFlat);
-
         for (Pair<Env<AttrContext>, JCClassDecl> x: queue) {
             Env<AttrContext> env = x.fst;
             JCClassDecl cdef = x.snd;
 
             if (verboseCompilePolicy) {
-                printNote("[generate "
-                               + (usePrintSource ? " source" : "code")
-                               + " " + cdef.sym + "]");
+                printNote("[generate " + (sourceOutput ? " source" : "code") + " " + cdef.sym + "]");
             }
 
             if (!taskListener.isEmpty()) {
@@ -1526,9 +1479,9 @@
                                       env.toplevel.sourcefile);
             try {
                 JavaFileObject file;
-                if (usePrintSource)
+                if (sourceOutput) {
                     file = printSource(env, cdef);
-                else {
+                } else {
                     if (fileManager.hasLocation(StandardLocation.NATIVE_HEADER_OUTPUT)
                             && jniWriter.needsHeader(cdef.sym)) {
                         jniWriter.write(cdef.sym);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,11 @@
 
 package com.sun.tools.javac.main;
 
-import java.io.File;
 import java.io.FileWriter;
 import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.LinkedHashMap;
@@ -238,13 +240,7 @@
 
     IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"),
 
-    ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER) {
-        @Override
-        public boolean process(OptionHelper helper, String option, String operand) {
-            return super.process(helper, option, operand);
-        }
-
-    },
+    ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER),
 
     SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
         @Override
@@ -537,16 +533,16 @@
         @Override
         public boolean process(OptionHelper helper, String option) {
             if (option.endsWith(".java") ) {
-                File f = new File(option);
-                if (!f.exists()) {
-                    helper.error("err.file.not.found", f);
+                Path p = Paths.get(option);
+                if (!Files.exists(p)) {
+                    helper.error("err.file.not.found", p);
                     return true;
                 }
-                if (!f.isFile()) {
-                    helper.error("err.file.not.file", f);
+                if (!Files.isRegularFile(p)) {
+                    helper.error("err.file.not.file", p);
                     return true;
                 }
-                helper.addFile(f);
+                helper.addFile(p);
             } else {
                 helper.addClassName(option);
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/OptionHelper.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/OptionHelper.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,10 @@
 
 package com.sun.tools.javac.main;
 
+import java.nio.file.Path;
+
 import com.sun.tools.javac.util.Log;
 import com.sun.tools.javac.util.Log.PrefixKind;
-import java.io.File;
 
 /**
  * Helper object to be used by {@link Option#process}, providing access to
@@ -63,7 +64,7 @@
     abstract void error(String key, Object... args);
 
     /** Record a file to be compiled. */
-    abstract void addFile(File f);
+    abstract void addFile(Path p);
 
     /** Record the name of a class for annotation processing. */
     abstract void addClassName(String s);
@@ -112,8 +113,8 @@
         }
 
         @Override
-        public void addFile(File f) {
-            throw new IllegalArgumentException(f.getPath());
+        public void addFile(Path p) {
+            throw new IllegalArgumentException(p.toString());
         }
 
         @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Feb 29 15:42:34 2016 +0000
@@ -981,10 +981,6 @@
 compiler.err.synthetic.name.conflict=\
     the symbol {0} conflicts with a compiler-synthesized symbol in {1}
 
-# 0: symbol, 1: symbol
-compiler.warn.synthetic.name.conflict=\
-    the symbol {0} conflicts with a compiler-synthesized symbol in {1}
-
 compiler.err.throws.not.allowed.in.intf.annotation=\
     throws clause not allowed in @interface members
 
@@ -1334,16 +1330,6 @@
 compiler.misc.verbose.wrote.file=\
     [wrote {0}]
 
-## extra output when using -verbose (Retro)
-compiler.misc.verbose.retro=\
-    [retrofitting {0}]
-
-compiler.misc.verbose.retro.with=\
-    \tretrofitting {0} with {1}
-
-compiler.misc.verbose.retro.with.list=\
-    \tretrofitting {0} with type parameters {1}, supertype {2}, interfaces {3}
-
 ## extra output when using -verbose (code/ClassReader)
 # 0: string
 compiler.misc.verbose.loading=\
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties	Mon Feb 29 15:42:34 2016 +0000
@@ -124,20 +124,12 @@
     Don't accept generics in the language
 javac.opt.moreinfo=\
     Print extended information for type variables
-javac.opt.printflat=\
-    Print abstract syntax tree after inner class conversion
 javac.opt.printsearch=\
     Print information where classfiles are searched
 javac.opt.prompt=\
     Stop after each error
-javac.opt.retrofit=\
-    Retrofit existing classfiles with generic types
 javac.opt.s=\
     Emit java sources instead of classfiles
-javac.opt.scramble=\
-    Scramble private identifiers in bytecode
-javac.opt.scrambleall=\
-    Scramble package visible identifiers in bytecode
 javac.opt.version=\
     Version information
 javac.opt.arg.pathname=\
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -170,12 +170,6 @@
             }
         },
 
-        new HiddenOption(false, "-stubs") {
-            void process(JavahTask task, String opt, String arg) {
-                 // ignored; for backwards compatibility
-            }
-        },
-
         new Option(false, "-v", "-verbose") {
             void process(JavahTask task, String opt, String arg) {
                 task.verbose = true;
@@ -454,8 +448,6 @@
         if (llni)
             g = new LLNI(doubleAlign, util);
         else {
-//            if (stubs)
-//                throw new BadArgs("jni.no.stubs");
             g = new JNI(util);
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CleanProperties.java	Mon Feb 29 15:42:34 2016 +0000
@@ -75,9 +75,7 @@
                              Map<String, PubApi> dependencyPublicApis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err) {
+                             int numCores) {
         boolean rc = true;
         for (String pkgName : pkgSrcs.keySet()) {
             String pkgNameF = pkgName.replace('.',File.separatorChar);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileJavaPackages.java	Mon Feb 29 15:42:34 2016 +0000
@@ -42,6 +42,8 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import com.sun.tools.sjavac.comp.CompilationService;
 import com.sun.tools.sjavac.options.Options;
@@ -89,9 +91,7 @@
                              final Map<String, PubApi> dependencyPubapis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             final Writer out,
-                             final Writer err) {
+                             int numCores) {
 
         Log.debug("Performing CompileJavaPackages transform...");
 
@@ -219,7 +219,9 @@
             }
 
             String chunkId = id + "-" + String.valueOf(i);
+            Log log = Log.get();
             compilationCalls.add(() -> {
+                Log.setLogForCurrentThread(log);
                 CompilationSubResult result = sjavac.compile("n/a",
                                                              chunkId,
                                                              args.prepJavacArgs(),
@@ -227,8 +229,8 @@
                                                              cc.srcs,
                                                              visibleSources);
                 synchronized (lock) {
-                    safeWrite(result.stdout, out);
-                    safeWrite(result.stderr, err);
+                    Util.getLines(result.stdout).forEach(Log::info);
+                    Util.getLines(result.stderr).forEach(Log::error);
                 }
                 return result;
             });
@@ -246,8 +248,10 @@
                 subResults.add(fut.get());
             } catch (ExecutionException ee) {
                 Log.error("Compilation failed: " + ee.getMessage());
-            } catch (InterruptedException ee) {
-                Log.error("Compilation interrupted: " + ee.getMessage());
+                Log.error(ee);
+            } catch (InterruptedException ie) {
+                Log.error("Compilation interrupted: " + ie.getMessage());
+                Log.error(ie);
                 Thread.currentThread().interrupt();
             }
         }
@@ -292,16 +296,6 @@
         return rc;
     }
 
-    private void safeWrite(String str, Writer w) {
-        if (str.length() > 0) {
-            try {
-                w.write(str);
-            } catch (IOException e) {
-                Log.error("Could not print compilation output.");
-            }
-        }
-    }
-
     /**
      * Split up the sources into compile chunks. If old package dependents information
      * is available, sort the order of the chunks into the most dependent first!
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CompileProperties.java	Mon Feb 29 15:42:34 2016 +0000
@@ -83,9 +83,7 @@
                              Map<String, PubApi> dependencyPublicApis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err) {
+                             int numCores) {
         boolean rc = true;
         for (String pkgName : pkgSrcs.keySet()) {
             String pkgNameF = Util.toFileSystemPath(pkgName);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/CopyFile.java	Mon Feb 29 15:42:34 2016 +0000
@@ -70,9 +70,7 @@
                              Map<String, PubApi> dependencyPubapis,
                              int debugLevel,
                              boolean incremental,
-                             int numCores,
-                             Writer out,
-                             Writer err)
+                             int numCores)
     {
         boolean rc = true;
         String dest_filename;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/JavacState.java	Mon Feb 29 15:42:34 2016 +0000
@@ -123,16 +123,11 @@
     // Setup transform that always exist.
     private CompileJavaPackages compileJavaPackages = new CompileJavaPackages();
 
-    // Where to send stdout and stderr.
-    private Writer out, err;
-
     // Command line options.
     private Options options;
 
-    JavacState(Options op, boolean removeJavacState, Writer o, Writer e) {
+    JavacState(Options op, boolean removeJavacState) {
         options = op;
-        out = o;
-        err = e;
         numCores = options.getNumCores();
         theArgs = options.getStateArgsString();
         binDir = Util.pathToFile(options.getDestDir());
@@ -294,8 +289,8 @@
     /**
      * Load a javac_state file.
      */
-    public static JavacState load(Options options, Writer out, Writer err) {
-        JavacState db = new JavacState(options, false, out, err);
+    public static JavacState load(Options options) {
+        JavacState db = new JavacState(options, false);
         Module  lastModule = null;
         Package lastPackage = null;
         Source  lastSource = null;
@@ -367,22 +362,22 @@
             noFileFound = true;
         } catch (IOException e) {
             Log.info("Dropping old javac_state because of errors when reading it.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
             foundCorrectVerNr = true;
             newCommandLine = false;
             syntaxError = false;
     }
         if (foundCorrectVerNr == false && !noFileFound) {
             Log.info("Dropping old javac_state since it is of an old version.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         } else
         if (newCommandLine == true && !noFileFound) {
             Log.info("Dropping old javac_state since a new command line is used!");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         } else
         if (syntaxError == true) {
             Log.info("Dropping old javac_state since it contains syntax errors.");
-            db = new JavacState(options, true, out, err);
+            db = new JavacState(options, true);
         }
         db.prev.calculateDependents();
         return db;
@@ -812,9 +807,7 @@
                                     dependencyPublicApis,
                                     0,
                                     isIncremental(),
-                                    numCores,
-                                    out,
-                                    err);
+                                    numCores);
             if (!r)
                 rc = false;
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Log.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,11 +26,24 @@
 package com.sun.tools.sjavac;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.Writer;
+import java.util.Locale;
 
 /**
  * Utility class only for sjavac logging.
- * The log level can be set using for example --log=DEBUG on the sjavac command line.
+ *
+ * Logging in sjavac has special requirements when running in server/client
+ * mode. Most of the log messages is generated server-side, but the server
+ * is typically spawned by the client in the background, so the user usually
+ * does not see the server stdout/stderr. For this reason log messages needs
+ * to relayed back to the client that performed the request that generated the
+ * log message. To support this use case this class maintains a per-thread log
+ * instance so that each connected client can have its own instance that
+ * relays messages back to the requesting client.
+ *
+ * On the client-side (or when running sjavac without server-mode) there will
+ * typically just be one Log instance.
  *
  *  <p><b>This is NOT part of any supported API.
  *  If you write code that depends on this, you do so at your own risk.
@@ -38,61 +51,94 @@
  *  deletion without notice.</b>
  */
 public class Log {
-    private static PrintWriter out, err;
+
+    public enum Level {
+        ERROR,
+        WARN,
+        INFO,
+        DEBUG,
+        TRACE;
+    }
+
+    private static Log stdOutErr = new Log(new PrintWriter(System.out), new PrintWriter(System.err));
+    private static ThreadLocal<Log> loggers = new ThreadLocal<>();
+
+    protected PrintWriter err; // Used for error and warning messages
+    protected PrintWriter out; // Used for other messages
+    protected Level level = Level.INFO;
 
-    public final static int WARN = 1;
-    public final static int INFO = 2;
-    public final static int DEBUG = 3;
-    public final static int TRACE = 4;
-    private static int level = WARN;
+    public Log(Writer out, Writer err) {
+        this.out = out == null ? null : new PrintWriter(out, true);
+        this.err = err == null ? null : new PrintWriter(err, true);
+    }
+
+    public static void setLogForCurrentThread(Log log) {
+        loggers.set(log);
+    }
+
+    public static void setLogLevel(String l) {
+        setLogLevel(Level.valueOf(l.toUpperCase(Locale.US)));
+    }
+
+    public static void setLogLevel(Level l) {
+        get().level = l;
+    }
 
     static public void trace(String msg) {
-        if (level >= TRACE) {
-            out.println(msg);
-        }
+        log(Level.TRACE, msg);
     }
 
     static public void debug(String msg) {
-        if (level >= DEBUG) {
-            out.println(msg);
-        }
+        log(Level.DEBUG, msg);
     }
 
     static public void info(String msg) {
-        if (level >= INFO) {
-            out.println(msg);
-        }
+        log(Level.INFO, msg);
     }
 
     static public void warn(String msg) {
-        err.println(msg);
+        log(Level.WARN, msg);
     }
 
     static public void error(String msg) {
-        err.println(msg);
+        log(Level.ERROR, msg);
     }
 
-    static public void initializeLog(Writer o, Writer e) {
-        out = new PrintWriter(o);
-        err = new PrintWriter(e);
+    static public void error(Throwable t) {
+        log(Level.ERROR, t);
     }
 
-    static public void setLogLevel(String l) {
-        switch (l) {
-            case "warn": level = WARN; break;
-            case "info": level = INFO; break;
-            case "debug": level = DEBUG; break;
-            case "trace": level = TRACE; break;
-            default:
-                throw new IllegalArgumentException("No such log level \"" + l + "\"");
-        }
+    static public void log(Level l, String msg) {
+        get().printLogMsg(l, msg);
     }
 
-    static public boolean isTracing() {
-        return level >= TRACE;
+    public static void debug(Throwable t) {
+        log(Level.DEBUG, t);
+    }
+
+    public static void log(Level l, Throwable t) {
+        StringWriter sw = new StringWriter();
+        t.printStackTrace(new PrintWriter(sw, true));
+        log(l, sw.toString());
     }
 
     static public boolean isDebugging() {
-        return level >= DEBUG;
+        return get().isLevelLogged(Level.DEBUG);
+    }
+
+    protected boolean isLevelLogged(Level l) {
+        return l.ordinal() <= level.ordinal();
+    }
+
+    public static Log get() {
+        Log log = loggers.get();
+        return log != null ? log : stdOutErr;
+    }
+
+    protected void printLogMsg(Level msgLevel, String msg) {
+        if (isLevelLogged(msgLevel)) {
+            PrintWriter pw = msgLevel.ordinal() <= Level.WARN.ordinal() ? err : out;
+            pw.println(msg);
+        }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Transformer.java	Mon Feb 29 15:42:34 2016 +0000
@@ -95,9 +95,7 @@
                       Map<String, PubApi>     dependencyApis,
                       int debugLevel,
                       boolean incremental,
-                      int numCores,
-                      Writer out,
-                      Writer err);
+                      int numCores);
 
     void setExtra(String e);
     void setExtra(Options args);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java	Mon Feb 29 15:42:34 2016 +0000
@@ -36,7 +36,9 @@
 import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Utilities.
@@ -236,4 +238,10 @@
         int dotIndex = fileNameStr.indexOf('.');
         return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex);
     }
+
+    public static Stream<String> getLines(String str) {
+        return str.isEmpty()
+                ? Stream.empty()
+                : Stream.of(str.split(Pattern.quote(System.lineSeparator())));
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/ClientMain.java	Mon Feb 29 15:42:34 2016 +0000
@@ -51,7 +51,7 @@
 
     public static int run(String[] args, Writer out, Writer err) {
 
-        Log.initializeLog(out, err);
+        Log.setLogForCurrentThread(new Log(out, err));
 
         Options options;
         try {
@@ -61,6 +61,8 @@
             return -1;
         }
 
+        Log.setLogLevel(options.getLogLevel());
+
         Log.debug("==========================================================");
         Log.debug("Launching sjavac client with the following parameters:");
         Log.debug("    " + options.getStateArgsString());
@@ -68,24 +70,15 @@
 
         // Prepare sjavac object
         boolean useServer = options.getServerConf() != null;
-        Sjavac sjavac;
-        // Create an sjavac implementation to be used for compilation
-        if (useServer) {
-            try {
-                sjavac = new SjavacClient(options);
-            } catch (PortFileInaccessibleException e) {
-                Log.error("Port file inaccessible.");
-                return -1;
-            }
-        } else {
-            sjavac = new SjavacImpl();
-        }
+        Sjavac sjavac = useServer ? new SjavacClient(options) : new SjavacImpl();
 
-        int rc = sjavac.compile(args, out, err);
+        // Perform compilation
+        int rc = sjavac.compile(args);
 
         // If sjavac is running in the foreground we should shut it down at this point
-        if (!useServer)
+        if (!useServer) {
             sjavac.shutdown();
+        }
 
         return rc;
     }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/client/SjavacClient.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.io.Reader;
 import java.io.Writer;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
@@ -40,6 +41,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Scanner;
+import java.util.stream.Stream;
 
 import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.Util;
@@ -50,6 +52,8 @@
 import com.sun.tools.sjavac.server.Sjavac;
 import com.sun.tools.sjavac.server.SjavacServer;
 
+import static java.util.stream.Collectors.joining;
+
 /**
  * Sjavac implementation that delegates requests to a SjavacServer.
  *
@@ -64,8 +68,6 @@
     // JavaCompiler instance for several compiles using the same id.
     private final String id;
     private final PortFile portFile;
-    private final String logfile;
-    private final String stdouterrfile;
 
     // Default keepalive for server is 120 seconds.
     // I.e. it will accept 120 seconds of inactivity before quitting.
@@ -86,7 +88,7 @@
     // Store the server conf settings here.
     private final String settings;
 
-    public SjavacClient(Options options) throws PortFileInaccessibleException {
+    public SjavacClient(Options options) {
         String tmpServerConf = options.getServerConf();
         String serverConf = (tmpServerConf!=null)? tmpServerConf : "";
         String tmpId = Util.extractStringOption("id", serverConf);
@@ -96,14 +98,7 @@
                                         .toAbsolutePath()
                                         .toString();
         String portfileName = Util.extractStringOption("portfile", serverConf, defaultPortfile);
-        try {
-            portFile = SjavacServer.getPortFile(portfileName);
-        } catch (PortFileInaccessibleException e) {
-            Log.error("Port file inaccessable: " + e);
-            throw e;
-        }
-        logfile = Util.extractStringOption("logfile", serverConf, portfileName + ".javaclog");
-        stdouterrfile = Util.extractStringOption("stdouterrfile", serverConf, portfileName + ".stdouterr");
+        portFile = SjavacServer.getPortFile(portfileName);
         sjavacForkCmd = Util.extractStringOption("sjavac", serverConf, "sjavac");
         int poolsize = Util.extractIntOption("poolsize", serverConf);
         keepalive = Util.extractIntOption("keepalive", serverConf, 120);
@@ -121,7 +116,7 @@
     }
 
     @Override
-    public int compile(String[] args, Writer stdout, Writer stderr) {
+    public int compile(String[] args) {
         int result = -1;
         try (Socket socket = tryConnect()) {
             PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
@@ -136,32 +131,36 @@
             // Read server response line by line
             String line;
             while (null != (line = in.readLine())) {
+                if (!line.contains(":")) {
+                    throw new AssertionError("Could not parse protocol line: >>\"" + line + "\"<<");
+                }
                 String[] typeAndContent = line.split(":", 2);
                 String type = typeAndContent[0];
                 String content = typeAndContent[1];
-                switch (type) {
-                case SjavacServer.LINE_TYPE_STDOUT:
-                    stdout.write(content);
-                    stdout.write('\n');
-                    break;
-                case SjavacServer.LINE_TYPE_STDERR:
-                    stderr.write(content);
-                    stderr.write('\n');
-                    break;
-                case SjavacServer.LINE_TYPE_RC:
+
+                try {
+                    Log.log(Log.Level.valueOf(type), "[server] " + content);
+                    continue;
+                } catch (IllegalArgumentException e) {
+                    // Parsing of 'type' as log level failed.
+                }
+
+                if (type.equals(SjavacServer.LINE_TYPE_RC)) {
                     result = Integer.parseInt(content);
-                    break;
                 }
             }
+        } catch (PortFileInaccessibleException e) {
+            Log.error("Port file inaccessible.");
+            result = CompilationSubResult.ERROR_FATAL;
         } catch (IOException ioe) {
-            Log.error("[CLIENT] Exception caught: " + ioe);
+            Log.error("IOException caught during compilation: " + ioe.getMessage());
+            Log.debug(ioe);
             result = CompilationSubResult.ERROR_FATAL;
-            ioe.printStackTrace(new PrintWriter(stderr));
         } catch (InterruptedException ie) {
             Thread.currentThread().interrupt(); // Restore interrupt
-            Log.error("[CLIENT] compile interrupted.");
+            Log.error("Compilation interrupted.");
+            Log.debug(ie);
             result = CompilationSubResult.ERROR_FATAL;
-            ie.printStackTrace(new PrintWriter(stderr));
         }
         return result;
     }
@@ -203,23 +202,22 @@
     private void makeSureServerIsRunning(PortFile portFile)
             throws IOException, InterruptedException {
 
-        portFile.lock();
-        portFile.getValues();
-        portFile.unlock();
+        if (portFile.exists()) {
+            portFile.lock();
+            portFile.getValues();
+            portFile.unlock();
 
-        if (portFile.containsPortInfo()) {
-            // Server seems to already be running
-            return;
+            if (portFile.containsPortInfo()) {
+                // Server seems to already be running
+                return;
+            }
         }
 
         // Fork a new server and wait for it to start
         SjavacClient.fork(sjavacForkCmd,
                           portFile,
-                          logfile,
                           poolsize,
-                          keepalive,
-                          System.err,
-                          stdouterrfile);
+                          keepalive);
     }
 
     @Override
@@ -230,51 +228,53 @@
     /*
      * Fork a server process process and wait for server to come around
      */
-    public static void fork(String sjavacCmd,
-                            PortFile portFile,
-                            String logfile,
-                            int poolsize,
-                            int keepalive,
-                            final PrintStream err,
-                            String stdouterrfile)
-                                    throws IOException, InterruptedException {
+    public static void fork(String sjavacCmd, PortFile portFile, int poolsize, int keepalive)
+            throws IOException, InterruptedException {
         List<String> cmd = new ArrayList<>();
         cmd.addAll(Arrays.asList(OptionHelper.unescapeCmdArg(sjavacCmd).split(" ")));
         cmd.add("--startserver:"
               + "portfile=" + portFile.getFilename()
-              + ",logfile=" + logfile
-              + ",stdouterrfile=" + stdouterrfile
               + ",poolsize=" + poolsize
               + ",keepalive="+ keepalive);
 
-        Process p = null;
+        Process serverProcess;
         Log.info("Starting server. Command: " + String.join(" ", cmd));
         try {
-            // If the cmd for some reason can't be executed (file not found, or
-            // is not executable) this will throw an IOException with a decent
-            // error message.
-            p = new ProcessBuilder(cmd)
-                        .redirectErrorStream(true)
-                        .redirectOutput(new File(stdouterrfile))
-                        .start();
+            // If the cmd for some reason can't be executed (file is not found,
+            // or is not executable for instance) this will throw an
+            // IOException and p == null.
+            serverProcess = new ProcessBuilder(cmd)
+                    .redirectErrorStream(true)
+                    .start();
+        } catch (IOException ex) {
+            // Message is typically something like:
+            // Cannot run program "xyz": error=2, No such file or directory
+            Log.error("Failed to create server process: " + ex.getMessage());
+            Log.debug(ex);
+            throw new IOException(ex);
+        }
 
+        // serverProcess != null at this point.
+        try {
             // Throws an IOException if no valid values materialize
             portFile.waitForValidValues();
-
         } catch (IOException ex) {
-            // Log and rethrow exception
-            Log.error("Faild to launch server.");
-            Log.error("    Message: " + ex.getMessage());
-            String rc = p == null || p.isAlive() ? "n/a" : "" + p.exitValue();
-            Log.error("    Server process exit code: " + rc);
-            Log.error("Server log:");
-            Log.error("------- Server log start -------");
-            try (Scanner s = new Scanner(new File(stdouterrfile))) {
-                while (s.hasNextLine())
-                    Log.error(s.nextLine());
+            // Process was started, but server failed to initialize. This could
+            // for instance be due to the JVM not finding the server class,
+            // or the server running in to some exception early on.
+            Log.error("Sjavac server failed to initialize: " + ex.getMessage());
+            Log.error("Process output:");
+            Reader serverStdoutStderr = new InputStreamReader(serverProcess.getInputStream());
+            try (BufferedReader br = new BufferedReader(serverStdoutStderr)) {
+                br.lines().forEach(Log::error);
             }
-            Log.error("------- Server log end ---------");
-            throw ex;
+            Log.error("<End of process output>");
+            try {
+                Log.error("Process exit code: " + serverProcess.exitValue());
+            } catch (IllegalThreadStateException e) {
+                // Server is presumably still running.
+            }
+            throw new IOException("Server failed to initialize: " + ex.getMessage(), ex);
         }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/CompilationService.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -95,11 +95,8 @@
             for (JavaFileObject jfo : fm.getJavaFileObjectsFromFiles(sourcesToCompileFiles))
                 explicitJFOs.append(SmartFileManager.locWrap(jfo, StandardLocation.SOURCE_PATH));
 
-            // Create a new logger
-            StringWriter stdoutLog = new StringWriter();
+            // Create a log to capture compiler output
             StringWriter stderrLog = new StringWriter();
-            PrintWriter stdout = new PrintWriter(stdoutLog);
-            PrintWriter stderr = new PrintWriter(stderrLog);
             com.sun.tools.javac.main.Main.Result rc = com.sun.tools.javac.main.Main.Result.OK;
             PublicApiCollector pubApiCollector = new PublicApiCollector(context, explicitJFOs);
             PathAndPackageVerifier papVerifier = new PathAndPackageVerifier();
@@ -108,11 +105,10 @@
                 if (explicitJFOs.size() > 0) {
                     sfm.setVisibleSources(visibleSources);
                     sfm.cleanArtifacts();
-                    sfm.setLog(stdout);
 
                     // Do the compilation!
                     JavacTaskImpl task =
-                            (JavacTaskImpl) compiler.getTask(stderr,
+                            (JavacTaskImpl) compiler.getTask(new PrintWriter(stderrLog),
                                                              sfm,
                                                              null,
                                                              Arrays.asList(args),
@@ -144,7 +140,6 @@
 
             compilationResult.packagePubapis = pubApiCollector.getPubApis(true);
             compilationResult.dependencyPubapis = pubApiCollector.getPubApis(false);
-            compilationResult.stdout = stdoutLog.toString();
             compilationResult.stderr = stderrLog.toString();
             compilationResult.returnCode = rc.exitCode;
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PooledSjavac.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,14 @@
 
 package com.sun.tools.sjavac.comp;
 
-import java.io.Writer;
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.server.Sjavac;
+
 import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import com.sun.tools.sjavac.Log;
-import com.sun.tools.sjavac.server.Sjavac;
-
 /**
  * An sjavac implementation that limits the number of concurrent calls by
  * wrapping invocations in Callables and delegating them to a FixedThreadPool.
@@ -55,10 +54,12 @@
     }
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
+        Log log = Log.get();
         try {
             return pool.submit(() -> {
-                return delegate.compile(args, out, err);
+                Log.setLogForCurrentThread(log);
+                return delegate.compile(args);
             }).get();
         } catch (Exception e) {
             e.printStackTrace();
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -27,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -68,7 +69,7 @@
 public class SjavacImpl implements Sjavac {
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
         Options options;
         try {
             options = Options.parseArgs(args);
@@ -77,8 +78,6 @@
             return RC_FATAL;
         }
 
-        Log.setLogLevel(options.getLogLevel());
-
         if (!validateOptions(options))
             return RC_FATAL;
 
@@ -100,18 +99,21 @@
         if (stateDir == null) {
             // Prepare context. Direct logging to our byte array stream.
             Context context = new Context();
-            PrintWriter writer = new PrintWriter(err);
-            com.sun.tools.javac.util.Log.preRegister(context, writer);
+            StringWriter strWriter = new StringWriter();
+            PrintWriter printWriter = new PrintWriter(strWriter);
+            com.sun.tools.javac.util.Log.preRegister(context, printWriter);
             JavacFileManager.preRegister(context);
 
             // Prepare arguments
             String[] passThroughArgs = Stream.of(args)
                                              .filter(arg -> !arg.startsWith(Option.SERVER.arg))
                                              .toArray(String[]::new);
+            // Compile
+            Main.Result result = new Main("javac", printWriter).compile(passThroughArgs, context);
 
-            // Compile
-            com.sun.tools.javac.main.Main compiler = new com.sun.tools.javac.main.Main("javac", writer);
-            Main.Result result = compiler.compile(passThroughArgs, context);
+            // Process compiler output (which is always errors)
+            printWriter.flush();
+            Util.getLines(strWriter.toString()).forEach(Log::error);
 
             // Clean up
             JavaFileManager fileManager = context.get(JavaFileManager.class);
@@ -126,7 +128,7 @@
 
         } else {
             // Load the prev build state database.
-            JavacState javac_state = JavacState.load(options, out, err);
+            JavacState javac_state = JavacState.load(options);
 
             // Setup the suffix rules from the command line.
             Map<String, Transformer> suffixRules = new HashMap<>();
@@ -288,10 +290,12 @@
 
                 return rc[0] ? RC_OK : RC_FATAL;
             } catch (ProblemException e) {
+                // For instance make file list mismatch.
                 Log.error(e.getMessage());
+                Log.debug(e);
                 return RC_FATAL;
             } catch (Exception e) {
-                e.printStackTrace(new PrintWriter(err));
+                Log.error(e);
                 return RC_FATAL;
             }
         }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileManager.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,8 +63,6 @@
     Set<URI> visibleSources = new HashSet<>();
     // Map from modulename:packagename to artifacts.
     Map<String,Set<URI>> packageArtifacts = new HashMap<>();
-    // Where to print informational messages.
-    PrintWriter stdout;
 
     public SmartFileManager(JavaFileManager fileManager) {
         super(fileManager);
@@ -78,10 +76,6 @@
         packageArtifacts = new HashMap<>();
     }
 
-    public void setLog(PrintWriter pw) {
-        stdout = pw;
-    }
-
     /**
      * Set whether or not to use ct.sym as an alternate to rt.jar.
      */
@@ -188,7 +182,7 @@
         if (file == null) return file;
 
         if (location.equals(StandardLocation.NATIVE_HEADER_OUTPUT) && superFile instanceof JavaFileObject) {
-           file = new SmartFileObject((JavaFileObject) file, stdout);
+           file = new SmartFileObject((JavaFileObject) file);
            packageName = ":" + packageNameFromFileName(relativeName);
         }
         if (packageName.equals("")) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartFileObject.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,11 +49,9 @@
 public class SmartFileObject implements JavaFileObject {
 
     JavaFileObject file;
-    PrintWriter stdout;
 
-    public SmartFileObject(JavaFileObject r, PrintWriter pw) {
+    public SmartFileObject(JavaFileObject r) {
         file = r;
-        stdout = pw;
     }
 
     @Override
@@ -113,7 +111,7 @@
         } catch (FileNotFoundException | NoSuchFileException e) {
             // Perfectly ok.
         }
-        return new SmartWriter(file, s.toString(), file.getName(), stdout);
+        return new SmartWriter(file, s.toString(), file.getName());
     }
 
     @DefinedBy(Api.COMPILER)
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SmartWriter.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package com.sun.tools.sjavac.comp;
 
+import com.sun.tools.sjavac.Log;
+
 import java.io.*;
 import javax.tools.JavaFileObject;
 
@@ -45,19 +47,17 @@
     JavaFileObject file;
     String oldContent;
     StringWriter newContent = new StringWriter();
-    PrintWriter stdout;
     boolean closed;
-    public SmartWriter(JavaFileObject f, String s, String n, PrintWriter pw) {
+
+    public SmartWriter(JavaFileObject f, String s, String n) {
         name = n;
         file = f;
         oldContent = s;
         newContent = new StringWriter();
-        stdout = pw;
         closed = false;
     }
 
-    public void write(char[] chars, int i, int i1)
-    {
+    public void write(char[] chars, int i, int i1) {
         newContent.write(chars, i, i1);
     }
 
@@ -70,7 +70,7 @@
             try (Writer writer = file.openWriter()) {
                 writer.write(s);
             }
-            stdout.println("Writing "+file.getName().substring(p+1));
+            Log.debug("Writing " + file.getName().substring(p + 1));
         }
     }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/IdleResetSjavac.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,10 @@
 
 package com.sun.tools.sjavac.server;
 
+import com.sun.tools.sjavac.Log;
+
+import java.io.FileWriter;
+import java.io.IOException;
 import java.io.Writer;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -53,8 +57,8 @@
     private TimerTask idlenessTimerTask;
 
     public IdleResetSjavac(Sjavac delegate,
-                            Terminable toShutdown,
-                            long idleTimeout) {
+                           Terminable toShutdown,
+                           long idleTimeout) {
         this.delegate = delegate;
         this.toShutdown = toShutdown;
         this.idleTimeout = idleTimeout;
@@ -62,10 +66,10 @@
     }
 
     @Override
-    public int compile(String[] args, Writer out, Writer err) {
+    public int compile(String[] args) {
         startCall();
         try {
-            return delegate.compile(args, out, err);
+            return delegate.compile(args);
         } finally {
             endCall();
         }
@@ -95,6 +99,7 @@
             throw new IllegalStateException("Idle timeout already scheduled");
         idlenessTimerTask = new TimerTask() {
             public void run() {
+                Log.setLogForCurrentThread(ServerMain.getErrorLog());
                 toShutdown.shutdown("Server has been idle for " + (idleTimeout / 1000) + " seconds.");
             }
         };
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/LinePrefixFilterWriter.java	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.tools.sjavac.server;
-
-import java.io.FilterWriter;
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Inserts {@literal prefix} in front of each line written.
- *
- * A line is considered to be terminated by any one of a line feed, a carriage
- * return, or a carriage return followed immediately by a line feed.
- */
-public class LinePrefixFilterWriter extends FilterWriter {
-
-    private final String prefix;
-    private boolean atBeginningOfLine = true;
-    private char lastChar = '\0';
-
-    protected LinePrefixFilterWriter(Writer out, String prefix) {
-        super(out);
-        this.prefix = prefix;
-    }
-
-    @Override
-    public void write(String str, int off, int len) throws IOException {
-        for (int i = 0; i < len; i++) {
-            write(str.charAt(off + i));
-        }
-    }
-
-    @Override
-    public void write(char[] cbuf, int off, int len) throws IOException {
-        for (int i = 0; i < len; i++) {
-            write(cbuf[off + i]);
-        }
-    }
-
-    @Override
-    public void write(int c) throws IOException {
-        if (lastChar == '\r' && c == '\n') {
-            // Second character of CR+LF sequence.
-            // Do nothing. We already started a new line on last character.
-        } else {
-            if (atBeginningOfLine) {
-                super.write(prefix, 0, prefix.length());
-            }
-            super.write(c);
-            atBeginningOfLine = c == '\r' || c == '\n';
-        }
-        lastChar = (char) c;
-    }
-}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java	Mon Feb 29 15:42:34 2016 +0000
@@ -81,10 +81,15 @@
      * Create a new portfile.
      * @param fn is the path to the file.
      */
-    public PortFile(String fn) throws PortFileInaccessibleException {
+    public PortFile(String fn) {
         filename = fn;
         file = new File(filename);
         stopFile = new File(filename+".stop");
+        containsPortInfo = false;
+        lock = null;
+    }
+
+    private void initializeChannel() throws PortFileInaccessibleException {
         try {
             rwfile = new RandomAccessFile(file, "rw");
         } catch (FileNotFoundException e) {
@@ -94,14 +99,15 @@
         // The rwfile should only be readable by the owner of the process
         // and no other! How do we do that on a RandomAccessFile?
         channel = rwfile.getChannel();
-        containsPortInfo = false;
-        lock = null;
     }
 
     /**
      * Lock the port file.
      */
     public void lock() throws IOException, InterruptedException {
+        if (channel == null) {
+            initializeChannel();
+        }
         lockSem.acquire();
         lock = channel.lock();
     }
@@ -204,8 +210,8 @@
         if (stopFile.exists()) {
             try {
                 stopFile.delete();
-            } catch (Exception e)
-            {}
+            } catch (Exception e) {
+            }
             return true;
         }
         return false;
@@ -215,7 +221,9 @@
      * Unlock the port file.
      */
     public void unlock() throws IOException {
-        Assert.check(lock != null);
+        if (lock == null) {
+            return;
+        }
         lock.release();
         lock = null;
         lockSem.release();
@@ -230,9 +238,11 @@
         long timeout = startTime + getServerStartupTimeoutSeconds() * 1000;
         while (true) {
             Log.debug("Looking for valid port file values...");
-            lock();
-            getValues();
-            unlock();
+            if (exists()) {
+                lock();
+                getValues();
+                unlock();
+            }
             if (containsPortInfo) {
                 Log.debug("Valid port file values found after " + (System.currentTimeMillis() - startTime) + " ms");
                 return;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFileMonitor.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFileMonitor.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
 
 package com.sun.tools.sjavac.server;
 
+import com.sun.tools.sjavac.Log;
+
 import java.io.IOException;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -56,8 +58,11 @@
     }
 
     public void start() {
+        Log log = Log.get();
         TimerTask shutdownCheck = new TimerTask() {
             public void run() {
+                Log.setLogForCurrentThread(log);
+                Log.debug("Checking port file status...");
                 try {
                     if (!portFile.exists()) {
                         // Time to quit because the portfile was deleted by another
@@ -74,12 +79,11 @@
                         server.shutdown("Quitting because portfile is now owned by another javac server!");
                     }
                 } catch (IOException e) {
-                    e.printStackTrace(server.theLog);
-                    server.flushLog();
+                    Log.error("IOException caught in PortFileMonitor.");
+                    Log.debug(e);
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
-                    e.printStackTrace(server.theLog);
-                    server.flushLog();
+                    Log.error(e);
                 }
             }
         };
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/RequestHandler.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,19 +25,16 @@
 
 package com.sun.tools.sjavac.server;
 
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDERR;
-import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_STDOUT;
+import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.Util;
 
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
 import java.net.Socket;
+import java.nio.file.Path;
 
-import com.sun.tools.sjavac.AutoFlushWriter;
-import com.sun.tools.sjavac.Log;
+import static com.sun.tools.sjavac.server.SjavacServer.LINE_TYPE_RC;
 
 
 /**
@@ -56,7 +53,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class RequestHandler implements Runnable {
+public class RequestHandler extends Thread {
 
     private final Socket socket;
     private final Sjavac sjavac;
@@ -68,9 +65,30 @@
 
     @Override
     public void run() {
+
         try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
              PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
 
+            // Set up logging for this thread. Stream back logging messages to
+            // client on the format format "level:msg".
+            Log.setLogForCurrentThread(new Log(out, out) {
+                @Override
+                protected boolean isLevelLogged(Level l) {
+                    // Make sure it is up to the client to decide whether or
+                    // not this message should be displayed.
+                    return true;
+                }
+
+                @Override
+                protected void printLogMsg(Level msgLevel, String msg) {
+                    // Follow sjavac server/client protocol: Send one line
+                    // at a time and prefix with message with "level:".
+                    Util.getLines(msg)
+                        .map(line -> msgLevel + ":" + line)
+                        .forEach(line -> super.printLogMsg(msgLevel, line));
+                }
+            });
+
             // Read argument array
             int n = Integer.parseInt(in.readLine());
             String[] args = new String[n];
@@ -78,23 +96,32 @@
                 args[i] = in.readLine();
             }
 
+            // If there has been any internal errors, notify client
+            checkInternalErrorLog();
+
             // Perform compilation
-            Writer stdout = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDOUT + ":");
-            Writer stderr = new LinePrefixFilterWriter(new AutoFlushWriter(out), LINE_TYPE_STDERR + ":");
-            int rc = sjavac.compile(args, stdout, stderr);
-            stdout.flush();
-            stderr.flush();
+            int rc = sjavac.compile(args);
 
             // Send return code back to client
             out.println(LINE_TYPE_RC + ":" + rc);
 
+            // Check for internal errors again.
+            checkInternalErrorLog();
         } catch (Exception ex) {
             // Not much to be done at this point. The client side request
             // code will most likely throw an IOException and the
             // compilation will fail.
-            StringWriter sw = new StringWriter();
-            ex.printStackTrace(new PrintWriter(sw));
-            Log.error(sw.toString());
+            Log.error(ex);
+        } finally {
+            Log.setLogForCurrentThread(null);
+        }
+    }
+
+    private void checkInternalErrorLog() {
+        Path errorLog = ServerMain.getErrorLog().getLogDestination();
+        if (errorLog != null) {
+            Log.error("Server has encountered an internal error. See " + errorLog.toAbsolutePath()
+                    + " for details.");
         }
     }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/ServerMain.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,10 +25,20 @@
 
 package com.sun.tools.sjavac.server;
 
+import java.io.FileWriter;
+import java.io.FilterOutputStream;
+import java.io.FilterWriter;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.lang.Thread.UncaughtExceptionHandler;
 
 import com.sun.tools.sjavac.Log;
+import com.sun.tools.sjavac.Log.Level;
+import com.sun.tools.sjavac.server.log.LazyInitFileLog;
+import com.sun.tools.sjavac.server.log.LoggingOutputStream;
+
+import static com.sun.tools.sjavac.Log.Level.ERROR;
+import static com.sun.tools.sjavac.Log.Level.INFO;
 
 /**
  *  <p><b>This is NOT part of any supported API.
@@ -37,20 +47,40 @@
  *  deletion without notice.</b>
  */
 public class ServerMain {
+
+    // For logging server internal (non request specific) errors.
+    private static LazyInitFileLog errorLog;
+
     public static int run(String[] args) {
 
-        Log.initializeLog(new OutputStreamWriter(System.out),
-                          new OutputStreamWriter(System.err));
+        // Under normal operation, all logging messages generated server-side
+        // are due to compilation requests. These logging messages should
+        // be relayed back to the requesting client rather than written to the
+        // server log. The only messages that should be written to the server
+        // log (in production mode) should be errors,
+        Log.setLogForCurrentThread(errorLog = new LazyInitFileLog("server.log"));
+        Log.setLogLevel(ERROR); // should be set to ERROR.
+
+        // Make sure no exceptions go under the radar
+        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+            Log.setLogForCurrentThread(errorLog);
+            Log.error(e);
+        });
+
+        // Inevitably someone will try to print messages using System.{out,err}.
+        // Make sure this output also ends up in the log.
+        System.setOut(new PrintStream(new LoggingOutputStream(System.out, INFO, "[stdout] ")));
+        System.setErr(new PrintStream(new LoggingOutputStream(System.err, ERROR, "[stderr] ")));
 
         // Any options other than --startserver?
         if (args.length > 1) {
-            System.err.println("When spawning a background server, only a single --startserver argument is allowed.");
+            Log.error("When spawning a background server, only a single --startserver argument is allowed.");
             return 1;
         }
 
         int exitCode;
         try {
-            SjavacServer server = new SjavacServer(args[0], System.err);
+            SjavacServer server = new SjavacServer(args[0]);
             exitCode = server.startServer();
         } catch (IOException | InterruptedException ex) {
             ex.printStackTrace();
@@ -59,4 +89,8 @@
 
         return exitCode;
     }
+
+    public static LazyInitFileLog getErrorLog() {
+        return errorLog;
+    }
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/Sjavac.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,6 @@
     final static int RC_FATAL = -1;
     final static int RC_OK = 0;
 
-    int compile(String[] args, Writer stdout, Writer stderr);
+    int compile(String[] args);
     void shutdown();
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java	Mon Feb 29 15:42:34 2016 +0000
@@ -26,6 +26,7 @@
 package com.sun.tools.sjavac.server;
 
 import java.io.FileNotFoundException;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.io.PrintWriter;
@@ -39,6 +40,7 @@
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.Util;
 import com.sun.tools.sjavac.client.PortFileInaccessibleException;
 import com.sun.tools.sjavac.comp.PooledSjavac;
@@ -54,17 +56,12 @@
  */
 public class SjavacServer implements Terminable {
 
-    // Used in protocol to tell the content of each line
+    // Prefix of line containing return code.
     public final static String LINE_TYPE_RC = "RC";
-    public final static String LINE_TYPE_STDOUT = "STDOUT";
-    public final static String LINE_TYPE_STDERR = "STDERR";
 
     final private String portfilename;
-    final private String logfile;
-    final private String stdouterrfile;
     final private int poolsize;
     final private int keepalive;
-    final private PrintStream err;
 
     // The secret cookie shared between server and client through the port file.
     // Used to prevent clients from believing that they are communicating with
@@ -75,9 +72,6 @@
     // Accumulated build time, not counting idle time, used for logging purposes
     private long totalBuildTime;
 
-    // The javac server specific log file.
-    PrintWriter theLog;
-
     // The sjavac implementation to delegate requests to
     Sjavac sjavac;
 
@@ -92,40 +86,28 @@
     // For the client, all port files fetched, one per started javac server.
     // Though usually only one javac server is started by a client.
     private static Map<String, PortFile> allPortFiles;
-    private static Map<String, Long> maxServerMemory;
 
-    public SjavacServer(String settings, PrintStream err) throws FileNotFoundException {
+    public SjavacServer(String settings) throws FileNotFoundException {
         this(Util.extractStringOption("portfile", settings),
-             Util.extractStringOption("logfile", settings),
-             Util.extractStringOption("stdouterrfile", settings),
              Util.extractIntOption("poolsize", settings, Runtime.getRuntime().availableProcessors()),
-             Util.extractIntOption("keepalive", settings, 120),
-             err);
+             Util.extractIntOption("keepalive", settings, 120));
     }
 
     public SjavacServer(String portfilename,
-                        String logfile,
-                        String stdouterrfile,
                         int poolsize,
-                        int keepalive,
-                        PrintStream err)
+                        int keepalive)
                                 throws FileNotFoundException {
         this.portfilename = portfilename;
-        this.logfile = logfile;
-        this.stdouterrfile = stdouterrfile;
         this.poolsize = poolsize;
         this.keepalive = keepalive;
-        this.err = err;
-
-        myCookie = new Random().nextLong();
-        theLog = new PrintWriter(logfile);
+        this.myCookie = new Random().nextLong();
     }
 
 
     /**
      * Acquire the port file. Synchronized since several threads inside an smart javac wrapper client acquires the same port file at the same time.
      */
-    public static synchronized PortFile getPortFile(String filename) throws PortFileInaccessibleException {
+    public static synchronized PortFile getPortFile(String filename) {
         if (allPortFiles == null) {
             allPortFiles = new HashMap<>();
         }
@@ -170,26 +152,6 @@
     }
 
     /**
-     * Log this message.
-     */
-    public void log(String msg) {
-        if (theLog != null) {
-            theLog.println(msg);
-        } else {
-            System.err.println(msg);
-        }
-    }
-
-    /**
-     * Make sure the log is flushed.
-     */
-    public void flushLog() {
-        if (theLog != null) {
-            theLog.flush();
-        }
-    }
-
-    /**
      * Start a server using a settings string. Typically: "--startserver:portfile=/tmp/myserver,poolsize=3" and the string "portfile=/tmp/myserver,poolsize=3"
      * is sent as the settings parameter. Returns 0 on success, -1 on failure.
      */
@@ -203,7 +165,7 @@
             portFile.lock();
             portFile.getValues();
             if (portFile.containsPortInfo()) {
-                err.println("Javac server not started because portfile exists!");
+                Log.info("Javac server not started because portfile exists!");
                 portFile.unlock();
                 return -1;
             }
@@ -230,23 +192,23 @@
         portFileMonitor = new PortFileMonitor(portFile, this);
         portFileMonitor.start();
 
-        log("Sjavac server started. Accepting connections...");
-        log("    port: " + getPort());
-        log("    time: " + new java.util.Date());
-        log("    poolsize: " + poolsize);
-        flushLog();
+        Log.info("Sjavac server started. Accepting connections...");
+        Log.info("    port: " + getPort());
+        Log.info("    time: " + new java.util.Date());
+        Log.info("    poolsize: " + poolsize);
+
 
         keepAcceptingRequests.set(true);
         do {
             try {
                 Socket socket = serverSocket.accept();
-                new Thread(new RequestHandler(socket, sjavac)).start();
+                new RequestHandler(socket, sjavac).start();
             } catch (SocketException se) {
                 // Caused by serverSocket.close() and indicates shutdown
             }
         } while (keepAcceptingRequests.get());
 
-        log("Shutting down.");
+        Log.info("Shutting down.");
 
         // No more connections accepted. If any client managed to connect after
         // the accept() was interrupted but before the server socket is closed
@@ -254,8 +216,7 @@
         // IOException on the client side.
 
         long realTime = System.currentTimeMillis() - serverStart;
-        log("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
-        flushLog();
+        Log.info("Total wall clock time " + realTime + "ms build time " + totalBuildTime + "ms");
 
         // Shut down
         sjavac.shutdown();
@@ -270,8 +231,7 @@
             return;
         }
 
-        log("Quitting: " + quitMsg);
-        flushLog();
+        Log.info("Quitting: " + quitMsg);
 
         portFileMonitor.shutdown(); // No longer any need to monitor port file
 
@@ -280,12 +240,12 @@
         try {
             portFile.delete();
         } catch (IOException | InterruptedException e) {
-            e.printStackTrace(theLog);
+            Log.error(e);
         }
         try {
             serverSocket.close();
         } catch (IOException e) {
-            e.printStackTrace(theLog);
+            Log.error(e);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/log/LazyInitFileLog.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac.server.log;
+
+import com.sun.tools.sjavac.Log;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class LazyInitFileLog extends Log {
+
+    String baseFilename;
+    Path destination = null;
+
+    public LazyInitFileLog(String baseFilename) {
+        super(null, null);
+        this.baseFilename = baseFilename;
+    }
+
+    protected void printLogMsg(Level msgLevel, String msg) {
+        try {
+            // Lazily initialize out/err
+            if (out == null && isLevelLogged(msgLevel)) {
+                destination = getAvailableDestination();
+                out = err = new PrintWriter(new FileWriter(destination.toFile()), true);
+            }
+            // Proceed to log the message
+            super.printLogMsg(msgLevel, msg);
+        } catch (IOException e) {
+            // This could be bad. We might have run into an error and we can't
+            // log it. Resort to printing on stdout.
+            System.out.println("IO error occurred: " + e.getMessage());
+            System.out.println("Original message: [" + msgLevel + "] " + msg);
+        }
+    }
+
+    /**
+     * @return The first available path of baseFilename, baseFilename.1,
+     * basefilename.2, ...
+     */
+    private Path getAvailableDestination() {
+        Path p = Paths.get(baseFilename);
+        int i = 1;
+        while (Files.exists(p)) {
+            p = Paths.get(baseFilename + "." + i++);
+        }
+        return p;
+    }
+
+    public Path getLogDestination() {
+        return destination;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/log/LoggingOutputStream.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.sjavac.server.log;
+
+import com.sun.tools.sjavac.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class LoggingOutputStream extends FilterOutputStream {
+
+    private static final byte[] LINE_SEP = System.lineSeparator().getBytes();
+
+    private final Log.Level level;
+    private final String linePrefix;
+    private EolTrackingByteArrayOutputStream buf = new EolTrackingByteArrayOutputStream();
+
+    public LoggingOutputStream(OutputStream out, Log.Level level, String linePrefix) {
+        super(out);
+        this.level = level;
+        this.linePrefix = linePrefix;
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        super.write(b);
+        buf.write(b);
+        if (buf.isLineComplete()) {
+            String line = new String(buf.toByteArray(), 0, buf.size() - LINE_SEP.length);
+            Log.log(level, linePrefix + line);
+            buf = new EolTrackingByteArrayOutputStream();
+        }
+    }
+
+    private static class EolTrackingByteArrayOutputStream extends ByteArrayOutputStream {
+        private static final byte[] EOL = System.lineSeparator().getBytes();
+        private boolean isLineComplete() {
+            if (count < EOL.length) {
+                return false;
+            }
+            for (int i = 0; i < EOL.length; i++) {
+                if (buf[count - EOL.length + i] != EOL[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java	Mon Feb 29 15:42:34 2016 +0000
@@ -26,6 +26,7 @@
 package jdk.internal.jshell.tool;
 
 import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
 
 import java.awt.event.ActionListener;
@@ -34,8 +35,12 @@
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Supplier;
@@ -144,6 +149,11 @@
         bind(DOCUMENTATION_SHORTCUT, (ActionListener) evt -> documentation(repl));
         bind(CTRL_UP, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::previousSnippet));
         bind(CTRL_DOWN, (ActionListener) evt -> moveHistoryToSnippet(((EditingHistory) in.getHistory())::nextSnippet));
+        for (FixComputer computer : FIX_COMPUTERS) {
+            for (String shortcuts : SHORTCUT_FIXES) {
+                bind(shortcuts + computer.shortcut, (ActionListener) evt -> fixes(computer));
+            }
+        }
     }
 
     @Override
@@ -216,6 +226,11 @@
     private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
     private static final String CTRL_UP = "\033\133\061\073\065\101"; //Ctrl-UP
     private static final String CTRL_DOWN = "\033\133\061\073\065\102"; //Ctrl-DOWN
+    private static final String[] SHORTCUT_FIXES = {
+        "\033\015", //Alt-Enter (Linux)
+        "\033\133\061\067\176", //F6/Alt-F1 (Mac)
+        "\u001BO3P" //Alt-F1 (Linux)
+    };
 
     private void documentation(JShellTool repl) {
         String buffer = in.getCursorBuffer().buffer.toString();
@@ -290,6 +305,185 @@
         history.fullHistoryReplace(source);
     }
 
+    //compute possible options/Fixes based on the selected FixComputer, present them to the user,
+    //and perform the selected one:
+    private void fixes(FixComputer computer) {
+        String input = prefix + in.getCursorBuffer().toString();
+        int cursor = prefix.length() + in.getCursorBuffer().cursor;
+        FixResult candidates = computer.compute(repl, input, cursor);
+
+        try {
+            final boolean printError = candidates.error != null && !candidates.error.isEmpty();
+            if (printError) {
+                in.println(candidates.error);
+            }
+            if (candidates.fixes.isEmpty()) {
+                in.beep();
+                if (printError) {
+                    in.redrawLine();
+                    in.flush();
+                }
+            } else if (candidates.fixes.size() == 1 && !computer.showMenu) {
+                if (printError) {
+                    in.redrawLine();
+                    in.flush();
+                }
+                candidates.fixes.get(0).perform(in);
+            } else {
+                List<Fix> fixes = new ArrayList<>(candidates.fixes);
+                fixes.add(0, new Fix() {
+                    @Override
+                    public String displayName() {
+                        return "Do nothing";
+                    }
+
+                    @Override
+                    public void perform(ConsoleReader in) throws IOException {
+                        in.redrawLine();
+                    }
+                });
+
+                Map<Character, Fix> char2Fix = new HashMap<>();
+                in.println();
+                for (int i = 0; i < fixes.size(); i++) {
+                    Fix fix = fixes.get(i);
+                    char2Fix.put((char) ('0' + i), fix);
+                    in.println("" + i + ": " + fixes.get(i).displayName());
+                }
+                in.print("Choice: ");
+                in.flush();
+                int read;
+
+                read = in.readCharacter();
+
+                Fix fix = char2Fix.get((char) read);
+
+                if (fix == null) {
+                    in.beep();
+                    fix = fixes.get(0);
+                }
+
+                in.println();
+
+                fix.perform(in);
+
+                in.flush();
+            }
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * A possible action which the user can choose to perform.
+     */
+    public interface Fix {
+        /**
+         * A name that should be shown to the user.
+         */
+        public String displayName();
+        /**
+         * Perform the given action.
+         */
+        public void perform(ConsoleReader in) throws IOException;
+    }
+
+    /**
+     * A factory for {@link Fix}es.
+     */
+    public abstract static class FixComputer {
+        private final char shortcut;
+        private final boolean showMenu;
+
+        /**
+         * Construct a new FixComputer. {@code shortcut} defines the key which should trigger this FixComputer.
+         * If {@code showMenu} is {@code false}, and this computer returns exactly one {@code Fix},
+         * no options will be show to the user, and the given {@code Fix} will be performed.
+         */
+        public FixComputer(char shortcut, boolean showMenu) {
+            this.shortcut = shortcut;
+            this.showMenu = showMenu;
+        }
+
+        /**
+         * Compute possible actions for the given code.
+         */
+        public abstract FixResult compute(JShellTool repl, String code, int cursor);
+    }
+
+    /**
+     * A list of {@code Fix}es with a possible error that should be shown to the user.
+     */
+    public static class FixResult {
+        public final List<Fix> fixes;
+        public final String error;
+
+        public FixResult(List<Fix> fixes, String error) {
+            this.fixes = fixes;
+            this.error = error;
+        }
+    }
+
+    private static final FixComputer[] FIX_COMPUTERS = new FixComputer[] {
+        new FixComputer('v', false) { //compute "Introduce variable" Fix:
+            @Override
+            public FixResult compute(JShellTool repl, String code, int cursor) {
+                String type = repl.analysis.analyzeType(code, cursor);
+                if (type == null) {
+                    return new FixResult(Collections.emptyList(), null);
+                }
+                return new FixResult(Collections.singletonList(new Fix() {
+                    @Override
+                    public String displayName() {
+                        return "Create variable";
+                    }
+                    @Override
+                    public void perform(ConsoleReader in) throws IOException {
+                        in.redrawLine();
+                        in.setCursorPosition(0);
+                        in.putString(type + "  = ");
+                        in.setCursorPosition(in.getCursorBuffer().cursor - 3);
+                        in.flush();
+                    }
+                }), null);
+            }
+        },
+        new FixComputer('i', true) { //compute "Add import" Fixes:
+            @Override
+            public FixResult compute(JShellTool repl, String code, int cursor) {
+                QualifiedNames res = repl.analysis.listQualifiedNames(code, cursor);
+                List<Fix> fixes = new ArrayList<>();
+                for (String fqn : res.getNames()) {
+                    fixes.add(new Fix() {
+                        @Override
+                        public String displayName() {
+                            return "import: " + fqn;
+                        }
+                        @Override
+                        public void perform(ConsoleReader in) throws IOException {
+                            repl.state.eval("import " + fqn + ";");
+                            in.println("Imported: " + fqn);
+                            in.redrawLine();
+                        }
+                    });
+                }
+                if (res.isResolvable()) {
+                    return new FixResult(Collections.emptyList(),
+                                         "\nThe identifier is resolvable in this context.");
+                } else {
+                    String error = "";
+                    if (fixes.isEmpty()) {
+                        error = "\nNo candidate fully qualified names found to import.";
+                    }
+                    if (!res.isUpToDate()) {
+                        error += "\nResults may be incomplete; try again later for complete results.";
+                    }
+                    return new FixResult(fixes, error);
+                }
+            }
+        }
+    };
+
     private static final class JShellUnixTerminal extends NoInterruptUnixTerminal {
 
         private final StopDetectingInputStream input;
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Mon Feb 29 15:42:34 2016 +0000
@@ -988,13 +988,19 @@
                 CommandKind.HELP_SUBJECT));
         registerCommand(new Command("shortcuts", "Describe shortcuts",
                 "Supported shortcuts include:\n\n" +
-                "<tab>       -- After entering the first few letters of a Java identifier,\n" +
-                "               a jshell command, or, in some cases, a jshell command argument,\n" +
-                "               press the <tab> key to complete the input.\n" +
-                "               If there is more than one completion, show possible completions.\n" +
-                "Shift-<tab> -- After the name and open parenthesis of a method or constructor invocation,\n" +
-                "               hold the <shift> key and press the <tab> to see a synopsis of all\n" +
-                "               matching methods/constructors.\n",
+                "<tab>            -- After entering the first few letters of a Java identifier,\n" +
+                "                    a jshell command, or, in some cases, a jshell command argument,\n" +
+                "                    press the <tab> key to complete the input.\n" +
+                "                    If there is more than one completion, show possible completions.\n" +
+                "Shift-<tab>      -- After the name and open parenthesis of a method or constructor invocation,\n" +
+                "                    hold the <shift> key and press the <tab> to see a synopsis of all\n" +
+                "                    matching methods/constructors.\n" +
+                "<fix-shortcut> v -- After a complete expression, press \"<fix-shortcut> v\" to introduce a new variable\n" +
+                "                    whose type is based on the type of the expression.\n" +
+                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n" +
+                "<fix-shortcut> i -- After an unresolvable identifier, press \"<fix-shortcut> i\" and jshell will propose\n" +
+                "                    possible fully qualified names based on the content of the specified classpath.\n" +
+                "                    The \"<fix-shortcut>\" is either Alt-F1 or Alt-Enter, depending on the platform.\n",
                 CommandKind.HELP_SUBJECT));
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Mon Feb 29 15:42:34 2016 +0000
@@ -420,7 +420,7 @@
         TaskFactory.AnalyzeTask at = trialCompile(guts);
         if (!at.hasErrors() && at.firstCuTree() != null) {
             return TreeDissector.createByFirstClass(at)
-                    .typeOfReturnStatement(at.messages(), state.maps::fullClassNameAndPackageToClass);
+                    .typeOfReturnStatement(at, state);
         }
         return null;
     }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Mon Feb 29 15:42:34 2016 +0000
@@ -346,10 +346,20 @@
      * @see JShell#onShutdown(java.util.function.Consumer)
      */
     public List<SnippetEvent> eval(String input) throws IllegalStateException {
-        checkIfAlive();
-        List<SnippetEvent> events = eval.eval(input);
-        events.forEach(this::notifyKeyStatusEvent);
-        return Collections.unmodifiableList(events);
+        SourceCodeAnalysisImpl a = sourceCodeAnalysis;
+        if (a != null) {
+            a.suspendIndexing();
+        }
+        try {
+            checkIfAlive();
+            List<SnippetEvent> events = eval.eval(input);
+            events.forEach(this::notifyKeyStatusEvent);
+            return Collections.unmodifiableList(events);
+        } finally {
+            if (a != null) {
+                a.resumeIndexing();
+            }
+        }
     }
 
     /**
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysis.java	Mon Feb 29 15:42:34 2016 +0000
@@ -70,6 +70,28 @@
     public abstract String documentation(String input, int cursor);
 
     /**
+     * Infer the type of the given expression. The expression spans from the beginning of {@code code}
+     * to the given {@code cursor} position. Returns null if the type of the expression cannot
+     * be inferred.
+     *
+     * @param code the expression for which the type should be inferred
+     * @param cursor current cursor position in the given code
+     * @return the inferred type, or null if it cannot be inferred
+     */
+    public abstract String analyzeType(String code, int cursor);
+
+    /**
+     * List qualified names known for the simple name in the given code immediately
+     * to the left of the given cursor position. The qualified names are gathered by inspecting the
+     * classpath used by eval (see {@link JShell#addToClasspath(java.lang.String)}).
+     *
+     * @param code the expression for which the candidate qualified names should be computed
+     * @param cursor current cursor position in the given code
+     * @return the known qualified names
+     */
+    public abstract QualifiedNames listQualifiedNames(String code, int cursor);
+
+    /**
      * Internal only constructor
      */
     SourceCodeAnalysis() {}
@@ -80,7 +102,7 @@
      */
     public static class CompletionInfo {
 
-        public CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
+        CompletionInfo(Completeness completeness, int unitEndPos, String source, String remaining) {
             this.completeness = completeness;
             this.unitEndPos = unitEndPos;
             this.source = source;
@@ -198,4 +220,65 @@
          */
         public final boolean isSmart;
     }
+
+    /**
+     * List of possible qualified names.
+     */
+    public static final class QualifiedNames {
+
+        private final List<String> names;
+        private final int simpleNameLength;
+        private final boolean upToDate;
+        private final boolean resolvable;
+
+        QualifiedNames(List<String> names, int simpleNameLength, boolean upToDate, boolean resolvable) {
+            this.names = names;
+            this.simpleNameLength = simpleNameLength;
+            this.upToDate = upToDate;
+            this.resolvable = resolvable;
+        }
+
+        /**
+         * Known qualified names for the given simple name in the original code.
+         *
+         * @return known qualified names
+         */
+        public List<String> getNames() {
+            return names;
+        }
+
+        /**
+         * The length of the simple name in the original code for which the
+         * qualified names where gathered.
+         *
+         * @return the length of the simple name; -1 if there is no name immediately left to the cursor for
+         *         which the candidates could be computed
+         */
+        public int getSimpleNameLength() {
+            return simpleNameLength;
+        }
+
+        /**
+         * Whether the result is based on up to date data. The
+         * {@link SourceCodeAnalysis#listQualifiedNames(java.lang.String, int) listQualifiedNames}
+         * method may return before the classpath is fully inspected, in which case this method will
+         * return {@code false}. If the result is based on a fully inspected classpath, this method
+         * will return {@code true}.
+         *
+         * @return true iff the results is based on up-to-date data
+         */
+        public boolean isUpToDate() {
+            return upToDate;
+        }
+
+        /**
+         * Whether the given simple name in the original code refers to a resolvable element.
+         *
+         * @return true iff the given simple name in the original code refers to a resolvable element
+         */
+        public boolean isResolvable() {
+            return resolvable;
+        }
+
+    }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Mon Feb 29 15:42:34 2016 +0000
@@ -79,13 +79,23 @@
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
 import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -99,6 +109,7 @@
 import java.util.stream.StreamSupport;
 
 import javax.lang.model.SourceVersion;
+
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.QualifiedNameable;
@@ -118,12 +129,30 @@
  * @author Robert Field
  */
 class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
+
+    private static final Map<Path, ClassIndex> PATH_TO_INDEX = new HashMap<>();
+    private static final ExecutorService INDEXER = Executors.newFixedThreadPool(1, r -> {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        t.setUncaughtExceptionHandler((thread, ex) -> ex.printStackTrace());
+        return t;
+    });
+
     private final JShell proc;
     private final CompletenessAnalyzer ca;
+    private final Map<Path, ClassIndex> currentIndexes = new HashMap<>();
+    private int indexVersion;
+    private int classpathVersion;
+    private final Object suspendLock = new Object();
+    private int suspend;
 
     SourceCodeAnalysisImpl(JShell proc) {
         this.proc = proc;
         this.ca = new CompletenessAnalyzer(proc);
+
+        int cpVersion = classpathVersion = 1;
+
+        INDEXER.submit(() -> refreshIndexes(cpVersion));
     }
 
     @Override
@@ -203,6 +232,15 @@
 
     @Override
     public List<Suggestion> completionSuggestions(String code, int cursor, int[] anchor) {
+        suspendIndexing();
+        try {
+            return completionSuggestionsImpl(code, cursor, anchor);
+        } finally {
+            resumeIndexing();
+        }
+    }
+
+    private List<Suggestion> completionSuggestionsImpl(String code, int cursor, int[] anchor) {
         code = code.substring(0, cursor);
         Matcher m = JAVA_IDENTIFIER.matcher(code);
         String identifier = "";
@@ -390,8 +428,11 @@
 
                 long start = sp.getStartPosition(topLevel, tree);
                 long end = sp.getEndPosition(topLevel, tree);
+                long prevEnd = deepest[0] != null ? sp.getEndPosition(topLevel, deepest[0].getLeaf()) : -1;
 
-                if (start <= pos && pos <= end) {
+                if (start <= pos && pos <= end &&
+                    (start != end || prevEnd != end || deepest[0] == null ||
+                     deepest[0].getParentPath().getLeaf() != getCurrentPath().getLeaf())) {
                     deepest[0] = new TreePath(getCurrentPath(), tree);
                     return super.scan(tree, p);
                 }
@@ -589,32 +630,28 @@
                 .collect(toList());
     }
 
-    private Set<String> emptyContextPackages = null;
+    void classpathChanged() {
+        synchronized (currentIndexes) {
+            int cpVersion = ++classpathVersion;
 
-    void classpathChanged() {
-        emptyContextPackages = null;
+            INDEXER.submit(() -> refreshIndexes(cpVersion));
+        }
     }
 
     private Set<PackageElement> listPackages(AnalyzeTask at, String enclosingPackage) {
-        Set<String> packs;
-
-        if (enclosingPackage.isEmpty() && emptyContextPackages != null) {
-            packs = emptyContextPackages;
-        } else {
-            packs = new HashSet<>();
-
-            listPackages(StandardLocation.PLATFORM_CLASS_PATH, enclosingPackage, packs);
-            listPackages(StandardLocation.CLASS_PATH, enclosingPackage, packs);
-            listPackages(StandardLocation.SOURCE_PATH, enclosingPackage, packs);
-
-            if (enclosingPackage.isEmpty()) {
-                emptyContextPackages = packs;
-            }
+        synchronized (currentIndexes) {
+            return currentIndexes.values()
+                                 .stream()
+                                 .flatMap(idx -> idx.packages.stream())
+                                 .filter(p -> enclosingPackage.isEmpty() || p.startsWith(enclosingPackage + "."))
+                                 .map(p -> {
+                                     int dot = p.indexOf('.', enclosingPackage.length() + 1);
+                                     return dot == (-1) ? p : p.substring(0, dot);
+                                 })
+                                 .distinct()
+                                 .map(p -> createPackageElement(at, p))
+                                 .collect(Collectors.toSet());
         }
-
-        return packs.stream()
-                    .map(pkg -> createPackageElement(at, pkg))
-                    .collect(Collectors.toSet());
     }
 
     private PackageElement createPackageElement(AnalyzeTask at, String packageName) {
@@ -625,79 +662,6 @@
         return existing;
     }
 
-    private void listPackages(Location loc, String enclosing, Set<String> packs) {
-        Iterable<? extends Path> paths = proc.taskFactory.fileManager().getLocationAsPaths(loc);
-
-        if (paths == null)
-            return ;
-
-        for (Path p : paths) {
-            listPackages(p, enclosing, packs);
-        }
-    }
-
-    private void listPackages(Path path, String enclosing, Set<String> packages) {
-        try {
-            if (path.equals(Paths.get("JRT_MARKER_FILE"))) {
-                FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
-                Path modules = jrtfs.getPath("modules");
-                try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
-                    for (Path c : stream) {
-                        listDirectory(c, enclosing, packages);
-                    }
-                }
-            } else if (!Files.isDirectory(path)) {
-                if (Files.exists(path)) {
-                    ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
-
-                    try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
-                        listDirectory(zip.getRootDirectories().iterator().next(), enclosing, packages);
-                    }
-                }
-            } else {
-                listDirectory(path, enclosing, packages);
-            }
-        } catch (IOException ex) {
-            proc.debug(ex, "SourceCodeAnalysisImpl.listPackages(" + path.toString() + ", " + enclosing + ", " + packages + ")");
-        }
-    }
-
-    private void listDirectory(Path path, String enclosing, Set<String> packages) throws IOException {
-        String separator = path.getFileSystem().getSeparator();
-        Path resolved = path.resolve(enclosing.replace(".", separator));
-
-        if (Files.isDirectory(resolved)) {
-            try (DirectoryStream<Path> ds = Files.newDirectoryStream(resolved)) {
-                for (Path entry : ds) {
-                    String name = pathName(entry);
-
-                    if (SourceVersion.isIdentifier(name) &&
-                        Files.isDirectory(entry) &&
-                        validPackageCandidate(entry)) {
-                        packages.add(enclosing + (enclosing.isEmpty() ? "" : ".") + name);
-                    }
-                }
-            }
-        }
-    }
-
-    private boolean validPackageCandidate(Path p) throws IOException {
-        try (Stream<Path> dir = Files.list(p)) {
-            return dir.anyMatch(e -> Files.isDirectory(e) && SourceVersion.isIdentifier(pathName(e)) ||
-                                e.getFileName().toString().endsWith(".class"));
-        }
-    }
-
-    private String pathName(Path p) {
-        String separator = p.getFileSystem().getSeparator();
-        String name = p.getFileName().toString();
-
-        if (name.endsWith(separator)) //jars have '/' appended
-            name = name.substring(0, name.length() - separator.length());
-
-        return name;
-    }
-
     private Element createArrayLengthSymbol(AnalyzeTask at, TypeMirror site) {
         Name length = Names.instance(at.getContext()).length;
         Type intType = Symtab.instance(at.getContext()).intType;
@@ -965,6 +929,15 @@
 
     @Override
     public String documentation(String code, int cursor) {
+        suspendIndexing();
+        try {
+            return documentationImpl(code, cursor);
+        } finally {
+            resumeIndexing();
+        }
+    }
+
+    private String documentationImpl(String code, int cursor) {
         code = code.substring(0, cursor);
         if (code.trim().isEmpty()) { //TODO: comment handling
             code += ";";
@@ -1074,4 +1047,347 @@
         }
         return arrayType;
     }
+
+    @Override
+    public String analyzeType(String code, int cursor) {
+        code = code.substring(0, cursor);
+        CompletionInfo completionInfo = analyzeCompletion(code);
+        if (!completionInfo.completeness.isComplete)
+            return null;
+        if (completionInfo.completeness == Completeness.COMPLETE_WITH_SEMI) {
+            code += ";";
+        }
+
+        OuterWrap codeWrap;
+        switch (guessKind(code)) {
+            case IMPORT: case METHOD: case CLASS: case ENUM:
+            case INTERFACE: case ANNOTATION_TYPE: case VARIABLE:
+                return null;
+            default:
+                codeWrap = wrapInClass(Wrap.methodWrap(code));
+                break;
+        }
+        AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
+        SourcePositions sp = at.trees().getSourcePositions();
+        CompilationUnitTree topLevel = at.firstCuTree();
+        int pos = codeWrap.snippetIndexToWrapIndex(code.length());
+        TreePath tp = pathFor(topLevel, sp, pos);
+        while (ExpressionTree.class.isAssignableFrom(tp.getParentPath().getLeaf().getKind().asInterface()) &&
+               tp.getParentPath().getLeaf().getKind() != Kind.ERRONEOUS &&
+               tp.getParentPath().getParentPath() != null)
+            tp = tp.getParentPath();
+        TypeMirror type = at.trees().getTypeMirror(tp);
+
+        if (type == null)
+            return null;
+
+        switch (type.getKind()) {
+            case ERROR: case NONE: case OTHER:
+            case PACKAGE: case VOID:
+                return null; //not usable
+            case NULL:
+                type = at.getElements().getTypeElement("java.lang.Object").asType();
+                break;
+        }
+
+        return TreeDissector.printType(at, proc, type);
+    }
+
+    @Override
+    public QualifiedNames listQualifiedNames(String code, int cursor) {
+        code = code.substring(0, cursor);
+        if (code.trim().isEmpty()) {
+            return new QualifiedNames(Collections.emptyList(), -1, true, false);
+        }
+        OuterWrap codeWrap;
+        switch (guessKind(code)) {
+            case IMPORT:
+                return new QualifiedNames(Collections.emptyList(), -1, true, false);
+            case METHOD:
+                codeWrap = wrapInClass(Wrap.classMemberWrap(code));
+                break;
+            default:
+                codeWrap = wrapInClass(Wrap.methodWrap(code));
+                break;
+        }
+        AnalyzeTask at = proc.taskFactory.new AnalyzeTask(codeWrap);
+        SourcePositions sp = at.trees().getSourcePositions();
+        CompilationUnitTree topLevel = at.firstCuTree();
+        TreePath tp = pathFor(topLevel, sp, codeWrap.snippetIndexToWrapIndex(code.length()));
+        if (tp.getLeaf().getKind() != Kind.IDENTIFIER) {
+            return new QualifiedNames(Collections.emptyList(), -1, true, false);
+        }
+        Scope scope = at.trees().getScope(tp);
+        TypeMirror type = at.trees().getTypeMirror(tp);
+        Element el = at.trees().getElement(tp);
+
+        boolean erroneous = (type.getKind() == TypeKind.ERROR && el.getKind() == ElementKind.CLASS) ||
+                            (el.getKind() == ElementKind.PACKAGE && el.getEnclosedElements().isEmpty());
+        String simpleName = ((IdentifierTree) tp.getLeaf()).getName().toString();
+        boolean upToDate;
+        List<String> result;
+
+        synchronized (currentIndexes) {
+            upToDate = classpathVersion == indexVersion;
+            result = currentIndexes.values()
+                                   .stream()
+                                   .flatMap(idx -> idx.classSimpleName2FQN.getOrDefault(simpleName,
+                                                                                        Collections.emptyList()).stream())
+                                   .distinct()
+                                   .filter(fqn -> isAccessible(at, scope, fqn))
+                                   .sorted()
+                                   .collect(Collectors.toList());
+        }
+
+        return new QualifiedNames(result, simpleName.length(), upToDate, !erroneous);
+    }
+
+    private boolean isAccessible(AnalyzeTask at, Scope scope, String fqn) {
+        TypeElement type = at.getElements().getTypeElement(fqn);
+        if (type == null)
+            return false;
+        return at.trees().isAccessible(scope, type);
+    }
+
+    //--------------------
+    // classpath indexing:
+    //--------------------
+
+    //the indexing can be suspended when a more important task is running:
+    private void waitIndexingNotSuspended() {
+        boolean suspendedNotified = false;
+        synchronized (suspendLock) {
+            while (suspend > 0) {
+                if (!suspendedNotified) {
+                    suspendedNotified = true;
+                }
+                try {
+                    suspendLock.wait();
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+    }
+
+    public void suspendIndexing() {
+        synchronized (suspendLock) {
+            suspend++;
+        }
+    }
+
+    public void resumeIndexing() {
+        synchronized (suspendLock) {
+            if (--suspend == 0) {
+                suspendLock.notifyAll();
+            }
+        }
+    }
+
+    //update indexes, either initially or after a classpath change:
+    private void refreshIndexes(int version) {
+        try {
+            Collection<Path> paths = new ArrayList<>();
+            MemoryFileManager fm = proc.taskFactory.fileManager();
+
+            appendPaths(fm, StandardLocation.PLATFORM_CLASS_PATH, paths);
+            appendPaths(fm, StandardLocation.CLASS_PATH, paths);
+            appendPaths(fm, StandardLocation.SOURCE_PATH, paths);
+
+            Map<Path, ClassIndex> newIndexes = new HashMap<>();
+
+            //setup existing/last known data:
+            for (Path p : paths) {
+                ClassIndex index = PATH_TO_INDEX.get(p);
+                if (index != null) {
+                    newIndexes.put(p, index);
+                }
+            }
+
+            synchronized (currentIndexes) {
+                //temporary setting old data:
+                currentIndexes.clear();
+                currentIndexes.putAll(newIndexes);
+            }
+
+            //update/compute the indexes if needed:
+            for (Path p : paths) {
+                waitIndexingNotSuspended();
+
+                ClassIndex index = indexForPath(p);
+                newIndexes.put(p, index);
+            }
+
+            synchronized (currentIndexes) {
+                currentIndexes.clear();
+                currentIndexes.putAll(newIndexes);
+            }
+        } catch (Exception ex) {
+            proc.debug(ex, "SourceCodeAnalysisImpl.refreshIndexes(" + version + ")");
+        } finally {
+            synchronized (currentIndexes) {
+                indexVersion = version;
+            }
+        }
+    }
+
+    private void appendPaths(MemoryFileManager fm, Location loc, Collection<Path> paths) {
+        Iterable<? extends Path> locationPaths = fm.getLocationAsPaths(loc);
+        if (locationPaths == null)
+            return ;
+        for (Path path : locationPaths) {
+            if (".".equals(path.toString())) {
+                //skip CWD
+                continue;
+            }
+
+            paths.add(path);
+        }
+    }
+
+    //create/update index a given JavaFileManager entry (which may be a JDK installation, a jar/zip file or a directory):
+    //if an index exists for the given entry, the existing index is kept unless the timestamp is modified
+    private ClassIndex indexForPath(Path path) {
+        if (isJRTMarkerFile(path)) {
+            FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
+            Path modules = jrtfs.getPath("modules");
+            return PATH_TO_INDEX.compute(path, (p, index) -> {
+                try {
+                    long lastModified = Files.getLastModifiedTime(modules).toMillis();
+                    if (index == null || index.timestamp != lastModified) {
+                        try (DirectoryStream<Path> stream = Files.newDirectoryStream(modules)) {
+                            index = doIndex(lastModified, path, stream);
+                        }
+                    }
+                    return index;
+                } catch (IOException ex) {
+                    proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")");
+                    return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+                }
+            });
+        } else if (!Files.isDirectory(path)) {
+            if (Files.exists(path)) {
+                return PATH_TO_INDEX.compute(path, (p, index) -> {
+                    try {
+                        long lastModified = Files.getLastModifiedTime(p).toMillis();
+                        if (index == null || index.timestamp != lastModified) {
+                            ClassLoader cl = SourceCodeAnalysisImpl.class.getClassLoader();
+
+                            try (FileSystem zip = FileSystems.newFileSystem(path, cl)) {
+                                index = doIndex(lastModified, path, zip.getRootDirectories());
+                            }
+                        }
+                        return index;
+                    } catch (IOException ex) {
+                        proc.debug(ex, "SourceCodeAnalysisImpl.indexesForPath(" + path.toString() + ")");
+                        return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+                    }
+                });
+            } else {
+                return new ClassIndex(-1, path, Collections.emptySet(), Collections.emptyMap());
+            }
+        } else {
+            return PATH_TO_INDEX.compute(path, (p, index) -> {
+                //no persistence for directories, as we cannot check timestamps:
+                if (index == null) {
+                    index = doIndex(-1, path, Arrays.asList(p));
+                }
+                return index;
+            });
+        }
+    }
+
+    static boolean isJRTMarkerFile(Path path) {
+        return path.equals(Paths.get("JRT_MARKER_FILE"));
+    }
+
+    //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath.
+    private ClassIndex doIndex(long timestamp, Path originalPath, Iterable<? extends Path> dirs) {
+        Set<String> packages = new HashSet<>();
+        Map<String, Collection<String>> classSimpleName2FQN = new HashMap<>();
+
+        for (Path d : dirs) {
+            try {
+                Files.walkFileTree(d, new FileVisitor<Path>() {
+                    int depth;
+                    @Override
+                    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+                        waitIndexingNotSuspended();
+                        if (depth++ == 0)
+                            return FileVisitResult.CONTINUE;
+                        String dirName = dir.getFileName().toString();
+                        String sep = dir.getFileSystem().getSeparator();
+                        dirName = dirName.endsWith(sep) ? dirName.substring(0, dirName.length() - sep.length())
+                                                        : dirName;
+                        if (SourceVersion.isIdentifier(dirName))
+                            return FileVisitResult.CONTINUE;
+                        return FileVisitResult.SKIP_SUBTREE;
+                    }
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                        waitIndexingNotSuspended();
+                        if (file.getFileName().toString().endsWith(".class")) {
+                            String relativePath = d.relativize(file).toString();
+                            String binaryName = relativePath.substring(0, relativePath.length() - 6).replace('/', '.');
+                            int packageDot = binaryName.lastIndexOf('.');
+                            if (packageDot > (-1)) {
+                                packages.add(binaryName.substring(0, packageDot));
+                            }
+                            String typeName = binaryName.replace('$', '.');
+                            addClassName2Map(classSimpleName2FQN, typeName);
+                        }
+                        return FileVisitResult.CONTINUE;
+                    }
+                    @Override
+                    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
+                        return FileVisitResult.CONTINUE;
+                    }
+                    @Override
+                    public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+                        depth--;
+                        return FileVisitResult.CONTINUE;
+                    }
+                });
+            } catch (IOException ex) {
+                proc.debug(ex, "doIndex(" + d.toString() + ")");
+            }
+        }
+
+        return new ClassIndex(timestamp, originalPath, packages, classSimpleName2FQN);
+    }
+
+    private static void addClassName2Map(Map<String, Collection<String>> classSimpleName2FQN, String typeName) {
+        int simpleNameDot = typeName.lastIndexOf('.');
+        classSimpleName2FQN.computeIfAbsent(typeName.substring(simpleNameDot + 1), n -> new LinkedHashSet<>())
+                           .add(typeName);
+    }
+
+    //holder for indexed data about a given path
+    public static final class ClassIndex {
+        public final long timestamp;
+        public final Path forPath;
+        public final Set<String> packages;
+        public final Map<String, Collection<String>> classSimpleName2FQN;
+
+        public ClassIndex(long timestamp, Path forPath, Set<String> packages, Map<String, Collection<String>> classSimpleName2FQN) {
+            this.timestamp = timestamp;
+            this.forPath = forPath;
+            this.packages = packages;
+            this.classSimpleName2FQN = classSimpleName2FQN;
+        }
+
+    }
+
+    //for tests, to be able to wait until the indexing finishes:
+    public void waitBackgroundTaskFinished() throws Exception {
+        boolean upToDate;
+        synchronized (currentIndexes) {
+            upToDate = classpathVersion == indexVersion;
+        }
+        while (!upToDate) {
+            INDEXER.submit(() -> {}).get();
+            synchronized (currentIndexes) {
+                upToDate = classpathVersion == indexVersion;
+            }
+        }
+    }
 }
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Mon Feb 29 15:42:34 2016 +0000
@@ -41,13 +41,14 @@
 import com.sun.tools.javac.code.Type.MethodType;
 import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.util.JavacMessages;
 import com.sun.tools.javac.util.Name;
 import static jdk.jshell.Util.isDoIt;
+import jdk.jshell.TaskFactory.AnalyzeTask;
 import jdk.jshell.Wrap.Range;
+
 import java.util.List;
 import java.util.Locale;
-import java.util.function.BinaryOperator;
+
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 import javax.lang.model.type.TypeMirror;
@@ -209,7 +210,7 @@
     }
 
 
-    ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
+    ExpressionInfo typeOfReturnStatement(AnalyzeTask at, JShell state) {
         ExpressionInfo ei = new ExpressionInfo();
         Tree unitTree = firstStatement();
         if (unitTree instanceof ReturnTree) {
@@ -219,9 +220,7 @@
                 if (viPath != null) {
                     TypeMirror tm = trees().getTypeMirror(viPath);
                     if (tm != null) {
-                        Type type = (Type)tm;
-                        TypePrinter tp = new TypePrinter(messages, fullClassNameAndPackageToClass, type);
-                        ei.typeName = tp.visit(type, Locale.getDefault());
+                        ei.typeName = printType(at, state, tm);
                         switch (tm.getKind()) {
                             case VOID:
                             case NONE:
@@ -263,6 +262,12 @@
         return sg.toString();
     }
 
+    public static String printType(AnalyzeTask at, JShell state, TypeMirror type) {
+        Type typeImpl = (Type) type;
+        TypePrinter tp = new TypePrinter(at.messages(), state.maps::fullClassNameAndPackageToClass, typeImpl);
+        return tp.visit(typeImpl, Locale.getDefault());
+    }
+
     /**
      * Signature Generation
      */
--- a/langtools/test/TEST.groups	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/TEST.groups	Mon Feb 29 15:42:34 2016 +0000
@@ -22,15 +22,17 @@
 
 # Tiered testing definitions
 
-# All langtools tests are tier 1.
+# (Nearly) all langtools tests are tier 1.
 tier1 = \
     com \
     jdk \
     lib \
-    tools
+    tools \
+    -jdk/jshell/ToolReloadTest.java
 
-# No langtools tests are tier 2.
-tier2 = 
+# (Almost) no langtools tests are tier 2.
+tier2 = \
+    jdk/jshell/ToolReloadTest.java
 
 # No langtools tests are tier 3 either.
 tier3 = 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/ComputeFQNsTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8131027
+ * @summary Test Get FQNs
+ * @library /tools/lib
+ * @build KullaTesting TestingInputStream ToolBox Compiler
+ * @run testng ComputeFQNsTest
+ */
+
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+@Test
+public class ComputeFQNsTest extends KullaTesting {
+
+    private final Compiler compiler = new Compiler();
+    private final Path outDir = Paths.get("ComputeFQNsTest");
+
+    public void testAddImport() throws Exception {
+        compiler.compile(outDir, "package test1; public class TestClass { }", "package test2; public class TestClass { }");
+        String jarName = "test.jar";
+        compiler.jar(outDir, jarName, "test1/TestClass.class", "test2/TestClass.class");
+        addToClasspath(compiler.getPath(outDir).resolve(jarName));
+
+        assertInferredFQNs("LinkedList", "java.util.LinkedList");
+        assertInferredFQNs("ArrayList", "java.util.ArrayList");
+        assertInferredFQNs("TestClass", "test1.TestClass", "test2.TestClass");
+        assertInferredFQNs("CharSequence", "CharSequence".length(), true, "java.lang.CharSequence");
+        assertInferredFQNs("unresolvable");
+        assertInferredFQNs("void test(ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("void test(ArrayList l) throws InvocationTargetException", "InvocationTargetException".length(), false, "java.lang.reflect.InvocationTargetException");
+        assertInferredFQNs("void test(ArrayList l) { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("<T extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("Object l = Arrays", "Arrays".length(), false, "java.util.Arrays");
+        assertInferredFQNs("class X<T extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("class X extends ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+        assertInferredFQNs("class X extends java.util.ArrayList<TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X extends java.util.ArrayList<TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements java.util.List<TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X implements java.util.List<TypeMirror, TypeElement", "TypeElement".length(), false, "javax.lang.model.element.TypeElement");
+        assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
+    }
+
+    @Test(enabled = false) //JDK-8150860
+    public void testSuspendIndexing() throws Exception {
+        compiler.compile(outDir, "package test; public class FQNTest { }");
+        String jarName = "test.jar";
+        compiler.jar(outDir, jarName, "test/FQNTest.class");
+        Path continueMarkFile = outDir.resolve("continuemark").toAbsolutePath();
+        Files.createDirectories(continueMarkFile.getParent());
+        try (Writer w = Files.newBufferedWriter(continueMarkFile)) {}
+
+        Path runMarkFile = outDir.resolve("runmark").toAbsolutePath();
+        Files.deleteIfExists(runMarkFile);
+
+        getState().sourceCodeAnalysis();
+
+        new Thread() {
+            @Override public void run() {
+                assertEval("{new java.io.FileOutputStream(\"" + runMarkFile.toAbsolutePath().toString() + "\").close();" +
+                           " while (java.nio.file.Files.exists(java.nio.file.Paths.get(\"" + continueMarkFile.toString() + "\"))) Thread.sleep(100); }");
+            }
+        }.start();
+
+        while (!Files.exists(runMarkFile))
+            Thread.sleep(100);
+
+        addToClasspath(compiler.getPath(outDir).resolve(jarName));
+
+        String code = "FQNTest";
+
+        QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList(), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(candidates.isUpToDate(), false, "Input: " + code + ", up-to-date=" + candidates.isUpToDate());
+
+        Files.delete(continueMarkFile);
+
+        waitIndexingFinished();
+
+        candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList("test.FQNTest"), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(true, candidates.isUpToDate(), "Input: " + code + ", up-to-date=" + candidates.isUpToDate());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/InferTypeTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8131027
+ * @summary Test Type Inference
+ * @library /tools/lib
+ * @build KullaTesting TestingInputStream ToolBox Compiler
+ * @run testng InferTypeTest
+ */
+
+import org.testng.annotations.Test;
+
+@Test
+public class InferTypeTest extends KullaTesting {
+
+    public void testTypeInference() {
+        assertInferredType("1", "int");
+        assertEval("import java.util.*;");
+        assertInferredType("new ArrayList<String>()", "ArrayList<String>");
+        assertInferredType("null", "Object");
+        assertInferredType("1 + ", null); //incomplete
+        assertInferredType("undef", null);  //unresolvable
+        assertEval("List<String> l1;");
+        assertEval("List<? extends String> l2;");
+        assertEval("List<? super String> l3;");
+        assertInferredType("l1", "List<String>");
+        assertInferredType("l2", "List<? extends String>");
+        assertInferredType("l3", "List<? super String>");
+        assertInferredType("l1.get(0)", "String");
+        assertInferredType("l2.get(0)", "String");
+        assertInferredType("l3.get(0)", "Object");
+        assertInferredType("\"\" + 1", "String");
+        assertEval("int i = 0;");
+        assertInferredType("i++", "int");
+        assertInferredType("++i", "int");
+        assertInferredType("i == 0 ? l1.get(0) : l2.get(0)", "String");
+        assertInferredType("", null);
+        assertInferredType("void test() { }", null);
+        assertInferredType("class Test { }", null);
+        assertInferredType("enum Test { A; }", null);
+        assertInferredType("interface Test { }", null);
+        assertInferredType("@interface Test { }", null);
+        assertInferredType("Object o;", null);
+    }
+
+}
--- a/langtools/test/jdk/jshell/KullaTesting.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/jdk/jshell/KullaTesting.java	Mon Feb 29 15:42:34 2016 +0000
@@ -24,6 +24,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.io.StringWriter;
+import java.lang.reflect.Method;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -61,6 +62,7 @@
 import jdk.jshell.SourceCodeAnalysis;
 import jdk.jshell.SourceCodeAnalysis.CompletionInfo;
 import jdk.jshell.SourceCodeAnalysis.Completeness;
+import jdk.jshell.SourceCodeAnalysis.QualifiedNames;
 import jdk.jshell.SourceCodeAnalysis.Suggestion;
 import jdk.jshell.UnresolvedReferenceException;
 import org.testng.annotations.AfterMethod;
@@ -862,6 +864,8 @@
     }
 
     private List<String> computeCompletions(String code, Boolean isSmart) {
+        waitIndexingFinished();
+
         int cursor =  code.indexOf('|');
         code = code.replace("|", "");
         assertTrue(cursor > -1, "'|' expected, but not found in: " + code);
@@ -874,6 +878,37 @@
                           .collect(Collectors.toList());
     }
 
+    public void assertInferredType(String code, String expectedType) {
+        String inferredType = getAnalysis().analyzeType(code, code.length());
+
+        assertEquals(inferredType, expectedType, "Input: " + code + ", " + inferredType);
+    }
+
+    public void assertInferredFQNs(String code, String... fqns) {
+        assertInferredFQNs(code, code.length(), false, fqns);
+    }
+
+    public void assertInferredFQNs(String code, int simpleNameLen, boolean resolvable, String... fqns) {
+        waitIndexingFinished();
+
+        QualifiedNames candidates = getAnalysis().listQualifiedNames(code, code.length());
+
+        assertEquals(candidates.getNames(), Arrays.asList(fqns), "Input: " + code + ", candidates=" + candidates.getNames());
+        assertEquals(candidates.getSimpleNameLength(), simpleNameLen, "Input: " + code + ", simpleNameLen=" + candidates.getSimpleNameLength());
+        assertEquals(candidates.isResolvable(), resolvable, "Input: " + code + ", resolvable=" + candidates.isResolvable());
+    }
+
+    protected void waitIndexingFinished() {
+        try {
+            Method waitBackgroundTaskFinished = getAnalysis().getClass().getDeclaredMethod("waitBackgroundTaskFinished");
+
+            waitBackgroundTaskFinished.setAccessible(true);
+            waitBackgroundTaskFinished.invoke(getAnalysis());
+        } catch (Exception ex) {
+            throw new AssertionError("Cannot wait for indexing end.", ex);
+        }
+    }
+
     public void assertDocumentation(String code, String... expected) {
         int cursor =  code.indexOf('|');
         code = code.replace("|", "");
--- a/langtools/test/jdk/jshell/ToolReloadTest.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/jdk/jshell/ToolReloadTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -23,6 +23,7 @@
 
 /*
  * @test
+ * @key intermittent
  * @bug 8081845 8147898
  * @summary Tests for /reload in JShell tool
  * @modules jdk.compiler/com.sun.tools.javac.api
--- a/langtools/test/tools/javac/6257443/T6257443.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/javac/6257443/T6257443.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,13 +31,7 @@
  *
  * @clean foo.package-info
  *
- * @compile -XD-printflat package-info.java
- * @run main/othervm T6257443 -no foo/package-info.class
- *
- * @compile -XD-stubs package-info.java
- * @run main/othervm T6257443 -no foo/package-info.class
- *
- * @compile -XD-printsource package-info.java
+ * @compile -printsource package-info.java
  * @run main/othervm T6257443 -no foo/package-info.class
  */
 
--- a/langtools/test/tools/javac/6521805/T6521805a.java	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @bug 6521805
- * @summary Regression: JDK5/JDK6 javac allows write access to outer class reference
- * @author mcimadamore
- *
- * @compile/fail/ref=T6521805a_1.out T6521805a.java -XDrawDiagnostics
- * @compile/ref=T6521805a_2.out T6521805a.java -XDwarnOnSyntheticConflicts -XDrawDiagnostics
- */
-
-class T6521805a {
-
-    static class Outer {
-        T6521805a this$0 = null;
-    }
-
-    public class Inner extends Outer {
-        public void foo() {
-            this$0 = new T6521805a();
-        }
-    }
-}
--- a/langtools/test/tools/javac/6521805/T6521805a_1.out	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-T6521805a.java:17:12: compiler.err.synthetic.name.conflict: this$0, T6521805a.Outer
-1 error
--- a/langtools/test/tools/javac/6521805/T6521805a_2.out	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-T6521805a.java:17:12: compiler.warn.synthetic.name.conflict: this$0, T6521805a.Outer
-1 warning
--- a/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/javac/api/taskListeners/EventsBalancedTest.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,8 +61,6 @@
 
         test(null, Arrays.asList(a, b));
         test(null, Arrays.asList(b, a));
-        test(Arrays.asList("-XD-relax"), Arrays.asList(a, b));
-        test(Arrays.asList("-XD-relax"), Arrays.asList(b, a));
 
         for (CompileState stop : CompileState.values()) {
             test(Arrays.asList("-XDshouldStopPolicyIfNoError=" + stop,
--- a/langtools/test/tools/javac/diags/CheckResourceKeys.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java	Mon Feb 29 15:42:34 2016 +0000
@@ -231,22 +231,15 @@
         "compiler.err.type.var.more.than.once.in.result",   // UNUSED
         "compiler.misc.non.denotable.type",                 // UNUSED
         "compiler.misc.unnamed.package",                    // should be required, CR 6964147
-        "compiler.misc.verbose.retro",                      // UNUSED
-        "compiler.misc.verbose.retro.with",                 // UNUSED
-        "compiler.misc.verbose.retro.with.list",            // UNUSED
         "compiler.warn.proc.type.already.exists",           // TODO in JavacFiler
         "javac.err.invalid.arg",                            // UNUSED ??
         "javac.opt.arg.class",                              // UNUSED ??
         "javac.opt.arg.pathname",                           // UNUSED ??
         "javac.opt.moreinfo",                               // option commented out
         "javac.opt.nogj",                                   // UNUSED
-        "javac.opt.printflat",                              // option commented out
         "javac.opt.printsearch",                            // option commented out
         "javac.opt.prompt",                                 // option commented out
-        "javac.opt.retrofit",                               // UNUSED
-        "javac.opt.s",                                      // option commented out
-        "javac.opt.scramble",                               // option commented out
-        "javac.opt.scrambleall"                             // option commented out
+        "javac.opt.s"                                       // option commented out
         ));
 
     /**
--- a/langtools/test/tools/javac/diags/examples.not-yet.txt	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/javac/diags/examples.not-yet.txt	Mon Feb 29 15:42:34 2016 +0000
@@ -86,9 +86,6 @@
 compiler.misc.undecl.type.var                           # ClassReader
 compiler.misc.unicode.str.not.supported                 # ClassReader
 compiler.misc.malformed.vararg.method                   # ClassReader
-compiler.misc.verbose.retro                             # UNUSED
-compiler.misc.verbose.retro.with                        # UNUSED
-compiler.misc.verbose.retro.with.list                   # UNUSED
 compiler.misc.version.not.available                     # JavaCompiler; implies build error
 compiler.misc.where.description.captured
 compiler.misc.where.typevar.1
--- a/langtools/test/tools/javac/diags/examples/WarnSyntheticNameConflict.java	Fri Feb 26 16:28:42 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-// key: compiler.warn.synthetic.name.conflict
-// options: -XDwarnOnSyntheticConflicts
-
-class WarnSyntheticNameConflict {
-
-    static class Outer {
-        WarnSyntheticNameConflict this$0 = null;
-    }
-
-    public class Inner extends Outer { }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/file/T8150475.java	Mon Feb 29 15:42:34 2016 +0000
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @compile -sourcepath / T8150475.java
+ */
+
+class T8150475 { }
+
--- a/langtools/test/tools/sjavac/IdleShutdown.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/sjavac/IdleShutdown.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -65,11 +65,11 @@
         // Use Sjavac object and wait less than TIMEOUT_MS in between calls
         Thread.sleep(TIMEOUT_MS - 1000);
         log("Compiling");
-        service.compile(new String[0], null, null);
+        service.compile(new String[0]);
 
         Thread.sleep(TIMEOUT_MS - 1000);
         log("Compiling");
-        service.compile(new String[0], null, null);
+        service.compile(new String[0]);
 
         if (timeoutTimestamp.get() != -1)
             throw new AssertionError("Premature timeout detected.");
@@ -103,7 +103,7 @@
         public void shutdown() {
         }
         @Override
-        public int compile(String[] args, Writer out, Writer err) {
+        public int compile(String[] args) {
             // Attempt to trigger idle timeout during a call by sleeping
             try {
                 Thread.sleep(TIMEOUT_MS + 1000);
--- a/langtools/test/tools/sjavac/PooledExecution.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/langtools/test/tools/sjavac/PooledExecution.java	Mon Feb 29 15:42:34 2016 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,12 @@
  * @build Wrapper
  * @run main Wrapper PooledExecution
  */
+import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import com.sun.tools.sjavac.Log;
 import com.sun.tools.sjavac.comp.PooledSjavac;
 import com.sun.tools.sjavac.server.Sjavac;
 
@@ -67,7 +69,7 @@
             for (int i = 0; i < NUM_REQUESTS; i++) {
                 tasks[i] = new Thread() {
                     public void run() {
-                        service.compile(new String[0], null, null);
+                        service.compile(new String[0]);
                         tasksFinished.incrementAndGet();
                     }
                 };
@@ -109,7 +111,7 @@
             AtomicInteger activeRequests = new AtomicInteger(0);
 
             @Override
-            public int compile(String[] args, Writer out, Writer err) {
+            public int compile(String[] args) {
                 leftToStart.countDown();
                 int numActiveRequests = activeRequests.incrementAndGet();
                 System.out.printf("Left to start: %2d / Currently active: %2d%n",
--- a/make/Init.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/make/Init.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -154,6 +154,9 @@
           # Do nothing
         endif
 
+    # Do not let make delete spec files even if aborted while doing a reconfigure
+    .PRECIOUS: $(SPECS)
+
     # Unless reconfigure is explicitely called, let all main targets depend on
     # the spec files to be up to date.
     ifeq ($(findstring reconfigure, $(INIT_TARGETS)), )
--- a/make/common/CORE_PKGS.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/make/common/CORE_PKGS.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -103,6 +103,7 @@
     java.lang.reflect \
     java.math \
     java.net \
+    java.net.http \
     java.net.spi \
     java.nio \
     java.nio.channels \
--- a/make/common/NativeCompilation.gmk	Fri Feb 26 16:28:42 2016 +0100
+++ b/make/common/NativeCompilation.gmk	Mon Feb 29 15:42:34 2016 +0000
@@ -651,12 +651,15 @@
 
       $$($1_RES): $$($1_VERSIONINFO_RESOURCE) $$($1_RES_VARDEPS_FILE)
 		$$(call LogInfo, Compiling resource $$(notdir $$($1_VERSIONINFO_RESOURCE)) (for $$(notdir $$($1_TARGET))))
+		$$(call MakeDir, $$(@D) $$($1_OBJECT_DIR))
 		$$(call ExecuteWithLog, $$@, \
 		    $$($1_RC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) $(CC_OUT_OPTION)$$@ \
 		    $$($1_VERSIONINFO_RESOURCE))
                 # Windows RC compiler does not support -showIncludes, so we mis-use CL for this.
-		$$($1_CC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
-		    $(CC_OUT_OPTION)$$($1_RES_DEP).obj $$($1_VERSIONINFO_RESOURCE) > $$($1_RES_DEP).raw 2>&1 || true ; \
+		$$(call ExecuteWithLog, $$($1_RES_DEP).obj, \
+		    $$($1_CC) $$($1_RC_FLAGS) $$($1_SYSROOT_CFLAGS) -showIncludes -nologo -TC \
+		    $(CC_OUT_OPTION)$$($1_RES_DEP).obj -P -Fi$$($1_RES_DEP).pp \
+		    $$($1_VERSIONINFO_RESOURCE)) > $$($1_RES_DEP).raw 2>&1 || true ; \
 		$(ECHO) $$($1_RES): \\ > $$($1_RES_DEP) ; \
 		$(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEP).raw >> $$($1_RES_DEP) ; \
 		$(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEP) > $$($1_RES_DEP_TARGETS)
@@ -670,7 +673,7 @@
         $1_REAL_MAPFILE := $$($1_OBJECT_DIR)/mapfile
 
         $$($1_REAL_MAPFILE) : $$($1_MAPFILE) $$($1_REORDER)
-		$$(MKDIR) -p $$(@D)
+		$$(call MakeDir, $$(@D))
 		$$(CP) $$($1_MAPFILE) $$@.tmp
 		$$(SED) -e 's=OUTPUTDIR=$$($1_OBJECT_DIR)=' $$($1_REORDER) >> $$@.tmp
 		$$(MV) $$@.tmp $$@
@@ -768,7 +771,10 @@
       $1_EXTRA_LDFLAGS += "-implib:$$($1_OBJECT_DIR)/$$($1_LIBRARY).lib"
     endif
 
-    $1_EXTRA_LIBS += $(GLOBAL_LIBS)
+    # Create loadmap on AIX. Helps in diagnosing some problems.
+    ifneq ($(COMPILER_BINDCMD_FILE_FLAG),)
+      $1_EXTRA_LDFLAGS += $(COMPILER_BINDCMD_FILE_FLAG)$$($1_OBJECT_DIR)/$$($1_NOSUFFIX).loadmap
+    endif
 
     $1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
         $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_CREATE_DEBUGINFO_CMDS) \
@@ -846,8 +852,6 @@
 
   ifneq (,$$($1_PROGRAM))
     # A executable binary has been specified, setup the target for it.
-    $1_EXTRA_LIBS += $(GLOBAL_LIBS)
-
     $1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
         $$($1_LIBS) $$($1_EXTRA_LIBS) $$($1_MT) \
         $$($1_CODESIGN) $$($1_CREATE_DEBUGINFO_CMDS) $$($1_MANIFEST_VERSION) \
--- a/modules.xml	Fri Feb 26 16:28:42 2016 +0100
+++ b/modules.xml	Mon Feb 29 15:42:34 2016 +0000
@@ -316,6 +316,10 @@
       <to>java.instrument</to>
     </export>
     <export>
+      <name>sun.net</name>
+      <to>java.httpclient</to>
+    </export>
+    <export>
       <name>sun.net.dns</name>
       <to>java.security.jgss</to>
       <to>jdk.naming.dns</to>
@@ -496,6 +500,7 @@
       <to>java.logging</to>
       <to>java.management</to>
       <to>java.prefs</to>
+      <to>java.httpclient</to>
     </export>
     <export>
       <name>sun.util.resources</name>
@@ -520,6 +525,7 @@
     <depend re-exports="true">java.compact2</depend>
     <depend re-exports="true">java.compiler</depend>
     <depend re-exports="true">java.instrument</depend>
+    <depend re-exports="true">java.httpclient</depend>
     <depend re-exports="true">java.management</depend>
     <depend re-exports="true">java.naming</depend>
     <depend re-exports="true">java.prefs</depend>
@@ -838,6 +844,13 @@
     </export>
   </module>
   <module>
+    <name>java.httpclient</name>
+    <depend>java.base</depend>
+    <export>
+      <name>java.net.http</name>
+    </export>
+  </module>
+  <module>
     <name>java.instrument</name>
     <depend>java.base</depend>
     <export>
--- a/nashorn/.hgtags	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/.hgtags	Mon Feb 29 15:42:34 2016 +0000
@@ -340,3 +340,4 @@
 a618d3e89fdea5361895ef142a59074fe7ae3d98 jdk-9+104
 4e9749cc32f15251d9b2d0eab4373529952902a3 jdk-9+105
 cfb3167456932b14c16a6d4cffd5fe295fbe01ff jdk-9+106
+8042e81b530e480dfdad41fd53a7a26f69ebba26 jdk-9+107
--- a/nashorn/make/build.xml	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/make/build.xml	Mon Feb 29 15:42:34 2016 +0000
@@ -242,6 +242,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -261,6 +262,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -276,6 +278,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${nashorn.module.src.dir}/overview.html"
         extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
@@ -289,6 +292,7 @@
     <javadoc destdir="${dist.javadoc.dir}" use="yes"
         windowtitle="Dynalink"
         additionalparam="-quiet" failonerror="true" useexternalfile="true">
+      <arg value="${javadoc.option}"/>
       <classpath>
         <pathelement location="${build.classes.dir}"/>
       </classpath>
--- a/nashorn/make/project.properties	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/make/project.properties	Mon Feb 29 15:42:34 2016 +0000
@@ -34,6 +34,8 @@
 javac.source=1.8
 javac.target=1.8
 
+javadoc.option=-tag "implSpec:a:Implementation Requirements:"
+
 # nashorn version information
 nashorn.version=0.1
 nashorn.fullversion=0.1
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/AbstractJSObject.java	Mon Feb 29 15:42:34 2016 +0000
@@ -27,6 +27,7 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -34,19 +35,19 @@
  *
  * This class can also be subclassed by an arbitrary Java class. Nashorn will
  * treat objects of such classes just like nashorn script objects. Usual nashorn
- * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated
  * to appropriate method call of this class.
  *
  * @since 1.8u40
  */
 public abstract class AbstractJSObject implements JSObject {
     /**
-     * Call this object as a JavaScript function. This is equivalent to
-     * 'func.apply(thiz, args)' in JavaScript.
-     *
-     * @param thiz 'this' object to be passed to the function
-     * @param args arguments to method
-     * @return result of call
+     * The default constructor.
+     */
+    public AbstractJSObject() {}
+
+    /**
+     * @implSpec This implementation always throws UnsupportedOperationException
      */
     @Override
     public Object call(final Object thiz, final Object... args) {
@@ -54,11 +55,7 @@
     }
 
     /**
-     * Call this 'constructor' JavaScript function to create a new object.
-     * This is equivalent to 'new func(arg1, arg2...)' in JavaScript.
-     *
-     * @param args arguments to method
-     * @return result of constructor call
+     * @implSpec This implementation always throws UnsupportedOperationException
      */
     @Override
     public Object newObject(final Object... args) {
@@ -66,10 +63,7 @@
     }
 
     /**
-     * Evaluate a JavaScript expression.
-     *
-     * @param s JavaScript expression to evaluate
-     * @return evaluation result
+     * @implSpec This imlementation always throws UnsupportedOperationException
      */
     @Override
     public Object eval(final String s) {
@@ -77,21 +71,16 @@
     }
 
     /**
-     * Retrieves a named member of this JavaScript object.
-     *
-     * @param name of member
-     * @return member
+     * @implSpec This implementation always returns null
      */
     @Override
     public Object getMember(final String name) {
+        Objects.requireNonNull(name);
         return null;
     }
 
     /**
-     * Retrieves an indexed member of this JavaScript object.
-     *
-     * @param index index slot to retrieve
-     * @return member
+     * @implSpec This implementation always returns null
      */
     @Override
     public Object getSlot(final int index) {
@@ -99,21 +88,16 @@
     }
 
     /**
-     * Does this object have a named member?
-     *
-     * @param name name of member
-     * @return true if this object has a member of the given name
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean hasMember(final String name) {
+        Objects.requireNonNull(name);
         return false;
     }
 
     /**
-     * Does this object have a indexed property?
-     *
-     * @param slot index to check
-     * @return true if this object has a slot
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean hasSlot(final int slot) {
@@ -121,31 +105,25 @@
     }
 
     /**
-     * Remove a named member from this JavaScript object
-     *
-     * @param name name of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void removeMember(final String name) {
+        Objects.requireNonNull(name);
         //empty
     }
 
     /**
-     * Set a named member in this JavaScript object
-     *
-     * @param name  name of the member
-     * @param value value of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void setMember(final String name, final Object value) {
+        Objects.requireNonNull(name);
         //empty
     }
 
     /**
-     * Set an indexed member in this JavaScript object
-     *
-     * @param index index of the member slot
-     * @param value value of the member
+     * @implSpec This implementation is a no-op
      */
     @Override
     public void setSlot(final int index, final Object value) {
@@ -155,9 +133,7 @@
     // property and value iteration
 
     /**
-     * Returns the set of all property names of this object.
-     *
-     * @return set of property names
+     * @implSpec This implementation returns empty set
      */
     @Override
     public Set<String> keySet() {
@@ -165,9 +141,7 @@
     }
 
     /**
-     * Returns the set of all property values of this object.
-     *
-     * @return set of property values.
+     * @implSpec This implementation returns empty set
      */
     @Override
     public Collection<Object> values() {
@@ -177,22 +151,13 @@
     // JavaScript instanceof check
 
     /**
-     * Checking whether the given object is an instance of 'this' object.
-     *
-     * @param instance instance to check
-     * @return true if the given 'instance' is an instance of this 'function' object
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isInstance(final Object instance) {
         return false;
     }
 
-    /**
-     * Checking whether this object is an instance of the given 'clazz' object.
-     *
-     * @param clazz clazz to check
-     * @return true if this object is an instance of the given 'clazz'
-     */
     @Override
     public boolean isInstanceOf(final Object clazz) {
         if (clazz instanceof JSObject) {
@@ -202,20 +167,13 @@
         return false;
     }
 
-    /**
-     * ECMA [[Class]] property
-     *
-     * @return ECMA [[Class]] property value of this object
-     */
     @Override
     public String getClassName() {
         return getClass().getName();
     }
 
     /**
-     * Is this a function object?
-     *
-     * @return if this mirror wraps a ECMAScript function instance
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isFunction() {
@@ -223,9 +181,7 @@
     }
 
     /**
-     * Is this a 'use strict' function object?
-     *
-     * @return true if this mirror represents a ECMAScript 'use strict' function
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isStrictFunction() {
@@ -233,9 +189,7 @@
     }
 
     /**
-     * Is this an array object?
-     *
-     * @return if this mirror wraps a ECMAScript array object
+     * @implSpec This implementation always returns false
      */
     @Override
     public boolean isArray() {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/JSObject.java	Mon Feb 29 15:42:34 2016 +0000
@@ -32,7 +32,7 @@
 /**
  * This interface can be implemented by an arbitrary Java class. Nashorn will
  * treat objects of such classes just like nashorn script objects. Usual nashorn
- * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be glued
+ * operations like obj[i], obj.foo, obj.func(), delete obj.foo will be delegated
  * to appropriate method call of this interface.
  *
  * @since 1.8u40
@@ -42,7 +42,7 @@
      * Call this object as a JavaScript function. This is equivalent to
      * 'func.apply(thiz, args)' in JavaScript.
      *
-     * @param thiz 'this' object to be passed to the function
+     * @param thiz 'this' object to be passed to the function. This may be null.
      * @param args arguments to method
      * @return result of call
      */
@@ -70,6 +70,7 @@
      *
      * @param name of member
      * @return member
+     * @throws NullPointerException if name is null
      */
     public Object getMember(final String name);
 
@@ -101,6 +102,7 @@
      * Remove a named member from this JavaScript object
      *
      * @param name name of the member
+     * @throws NullPointerException if name is null
      */
     public void removeMember(final String name);
 
@@ -109,6 +111,7 @@
      *
      * @param name  name of the member
      * @param value value of the member
+     * @throws NullPointerException if name is null
      */
     public void setMember(final String name, final Object value);
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornException.java	Mon Feb 29 15:42:34 2016 +0000
@@ -46,6 +46,8 @@
  */
 @SuppressWarnings("serial")
 public abstract class NashornException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
     // script file name
     private String fileName;
     // script line number
@@ -58,7 +60,7 @@
     private Object ecmaError;
 
     /**
-     * Constructor
+     * Constructor to initialize error message, file name, line and column numbers.
      *
      * @param msg       exception message
      * @param fileName  file name
@@ -70,7 +72,7 @@
     }
 
     /**
-     * Constructor
+     * Constructor to initialize error message, cause exception, file name, line and column numbers.
      *
      * @param msg       exception message
      * @param cause     exception cause
@@ -86,7 +88,7 @@
     }
 
     /**
-     * Constructor
+     * Constructor to initialize error message and cause exception.
      *
      * @param msg       exception message
      * @param cause     exception cause
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java	Mon Feb 29 15:42:34 2016 +0000
@@ -154,7 +154,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given class loader.
+     * Create a new Script engine initialized with the given class loader.
      *
      * @param appLoader class loader to be used as script "app" class loader.
      * @return newly created script engine.
@@ -167,7 +167,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given class filter.
+     * Create a new Script engine initialized with the given class filter.
      *
      * @param classFilter class filter to use.
      * @return newly created script engine.
@@ -181,7 +181,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments.
      *
      * @param args arguments array passed to script engine.
      * @return newly created script engine.
@@ -195,7 +195,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments and the given class loader.
      *
      * @param args arguments array passed to script engine.
      * @param appLoader class loader to be used as script "app" class loader.
@@ -210,7 +210,7 @@
     }
 
     /**
-     * Create a new Script engine initialized by given arguments.
+     * Create a new Script engine initialized with the given arguments, class loader and class filter.
      *
      * @param args arguments array passed to script engine.
      * @param appLoader class loader to be used as script "app" class loader.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Mon Feb 29 15:42:34 2016 +0000
@@ -287,22 +287,21 @@
         });
     }
 
-
     @Override
-    public boolean isInstance(final Object obj) {
-        if (! (obj instanceof ScriptObjectMirror)) {
+    public boolean isInstance(final Object instance) {
+        if (! (instance instanceof ScriptObjectMirror)) {
             return false;
         }
 
-        final ScriptObjectMirror instance = (ScriptObjectMirror)obj;
+        final ScriptObjectMirror mirror = (ScriptObjectMirror)instance;
         // if not belongs to my global scope, return false
-        if (global != instance.global) {
+        if (global != mirror.global) {
             return false;
         }
 
         return inGlobal(new Callable<Boolean>() {
             @Override public Boolean call() {
-                return sobj.isInstance(instance.sobj);
+                return sobj.isInstance(mirror.sobj);
             }
         });
     }
@@ -653,10 +652,10 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+     * Make a script object mirror on given object if needed.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @return wrapped/converted object
      */
     public static Object wrap(final Object obj, final Object homeGlobal) {
@@ -664,13 +663,13 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. The
-     * created wrapper will implement the Java {@code List} interface if {@code obj} is a JavaScript
-     * {@code Array} object; this is compatible with Java JSON libraries expectations. Arrays retrieved through its
+     * Make a script object mirror on given object if needed. The created wrapper will implement
+     * the Java {@code List} interface if {@code obj} is a JavaScript {@code Array} object;
+     * this is compatible with Java JSON libraries expectations. Arrays retrieved through its
      * properties (transitively) will also implement the list interface.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @return wrapped/converted object
      */
     public static Object wrapAsJSONCompatible(final Object obj, final Object homeGlobal) {
@@ -678,10 +677,10 @@
     }
 
     /**
-     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+     * Make a script object mirror on given object if needed.
      *
      * @param obj object to be wrapped/converted
-     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param homeGlobal global to which this object belongs.
      * @param jsonCompatible if true, the created wrapper will implement the Java {@code List} interface if
      * {@code obj} is a JavaScript {@code Array} object. Arrays retrieved through its properties (transitively)
      * will also implement the list interface.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptUtils.java	Mon Feb 29 15:42:34 2016 +0000
@@ -74,9 +74,15 @@
      * @param func the function to wrap
      * @param sync the object to synchronize on
      * @return a synchronizing wrapper function
+     * @throws IllegalArgumentException if func does not represent a script function
      */
-    public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
-        return func.createSynchronized(unwrap(sync));
+    public static Object makeSynchronizedFunction(final Object func, final Object sync) {
+        final Object unwrapped = unwrap(func);
+        if (unwrapped instanceof ScriptFunction) {
+            return ((ScriptFunction)unwrapped).createSynchronized(unwrap(sync));
+        }
+
+        throw new IllegalArgumentException();
     }
 
     /**
@@ -84,9 +90,19 @@
      *
      * @param obj object to be wrapped
      * @return wrapped object
+     * @throws IllegalArgumentException if obj cannot be wrapped
      */
-    public static ScriptObjectMirror wrap(final ScriptObject obj) {
-        return (ScriptObjectMirror) ScriptObjectMirror.wrap(obj, Context.getGlobal());
+    public static ScriptObjectMirror wrap(final Object obj) {
+        if (obj instanceof ScriptObjectMirror) {
+            return (ScriptObjectMirror)obj;
+        }
+
+        if (obj instanceof ScriptObject) {
+            final ScriptObject sobj = (ScriptObject)obj;
+            return (ScriptObjectMirror) ScriptObjectMirror.wrap(sobj, Context.getGlobal());
+        }
+
+        throw new IllegalArgumentException();
     }
 
     /**
@@ -135,7 +151,8 @@
      * Convert the given object to the given type.
      *
      * @param obj object to be converted
-     * @param type destination type to convert to
+     * @param type destination type to convert to. type is either a Class
+     * or nashorn representation of a Java type returned by Java.type() call in script.
      * @return converted object
      */
     public static Object convert(final Object obj, final Object type) {
--- a/nashorn/test/script/basic/JDK-8026367.js	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/test/script/basic/JDK-8026367.js	Mon Feb 29 15:42:34 2016 +0000
@@ -37,10 +37,12 @@
     // Sync called with one argument will synchronize on this-object of invocation
     inc: sync(function(d) {
         this.count += d;
+        Assert.assertTrue(java.lang.Thread.holdsLock(this));
     }),
     // Pass explicit object to synchronize on as second argument
     dec: sync(function(d) {
         this.count -= d;
+        Assert.assertTrue(java.lang.Thread.holdsLock(obj));
     }, obj)
 };
 
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8148140_Test.java	Fri Feb 26 16:28:42 2016 +0100
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JDK_8148140_Test.java	Mon Feb 29 15:42:34 2016 +0000
@@ -22,7 +22,7 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package jdk.nashorn.internal.runtime.test;
+package jdk.nashorn.api.scripting.test;
 
 import java.util.Arrays;
 import javax.script.ScriptEngine;
@@ -70,4 +70,4 @@
         assertEquals(RESULT, engine.eval("Function.prototype.apply.call(f, null, [1,2,3])"));
     }
 
-}
\ No newline at end of file
+}