http-client-branch: merge http-client-branch
authorprappo
Wed, 06 Jun 2018 15:52:48 +0100
branchhttp-client-branch
changeset 56681 5bc3d3bb145b
parent 56680 84fc885b019d (current diff)
parent 56677 f57700f449bd (diff)
child 56682 9822bbe48b9b
http-client-branch: merge
--- a/src/java.net.http/share/classes/java/net/http/HttpClient.java	Wed Jun 06 15:23:38 2018 +0100
+++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java	Wed Jun 06 15:52:48 2018 +0100
@@ -57,7 +57,7 @@
  * and can be used to send multiple requests.
  *
  * <p> An {@code HttpClient} provides configuration information, and resource
- * sharing, for all requests send through it.
+ * sharing, for all requests sent through it.
  *
  * <p> A {@link BodyHandler BodyHandler} must be supplied for each {@link
  * HttpRequest} sent. The {@code BodyHandler} determines how to handle the
--- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java	Wed Jun 06 15:23:38 2018 +0100
+++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java	Wed Jun 06 15:52:48 2018 +0100
@@ -830,7 +830,7 @@
      * BodySubscriber} provides implementations of many common body subscribers.
      *
      * <p> The object acts as a {@link Flow.Subscriber}&lt;{@link List}&lt;{@link
-     * ByteBuffer}&gt;&gt; to the HTTP client implementation, which publishes
+     * ByteBuffer}&gt;&gt; to the HTTP Client implementation, which publishes
      * lists of ByteBuffers containing the response body. The Flow of data, as
      * well as the order of ByteBuffers in the Flow lists, is a strictly ordered
      * representation of the response body. Both the Lists and the ByteBuffers,
--- a/src/java.net.http/share/classes/java/net/http/package-info.java	Wed Jun 06 15:23:38 2018 +0100
+++ b/src/java.net.http/share/classes/java/net/http/package-info.java	Wed Jun 06 15:52:48 2018 +0100
@@ -42,10 +42,14 @@
  * Hypertext Transfer Protocol (HTTP/1.1)</a>, and
  * <a href="https://tools.ietf.org/html/rfc6455">The WebSocket Protocol</a>.
  *
- * <p> Asynchronous tasks and dependent actions of returned {@link
- * java.util.concurrent.CompletableFuture} instances are executed on the threads
- * supplied by the client's {@link java.util.concurrent.Executor}, where
- * practical.
+ * <p> In general, asynchronous tasks are executed either by the thread
+ * performing the send operation, or by the threads supplied by the client's
+ * {@link java.net.http.HttpClient#executor() executor}. Dependent tasks, those
+ * that are triggered by returned CompletionStages or CompletableFutures, that
+ * do not explicitly specify an executor, are executed in the same
+ * {@link java.util.concurrent.CompletableFuture#defaultExecutor() default
+ * executor} as that of CompletableFuture, or the invoking thread if the send
+ * operation completes before the dependent task is registered.
  *
  * <p> {@code CompletableFuture}s returned by this API will throw {@link
  * java.lang.UnsupportedOperationException} for their {@link
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java	Wed Jun 06 15:23:38 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java	Wed Jun 06 15:52:48 2018 +0100
@@ -28,6 +28,7 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLParameters;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import java.net.Authenticator;
@@ -56,6 +57,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -531,6 +533,8 @@
         }
     }
 
+    private static final Executor ASYNC_POOL = new CompletableFuture<Void>().defaultExecutor();
+
     @Override
     public <T> CompletableFuture<HttpResponse<T>>
     sendAsync(HttpRequest userRequest, BodyHandler<T> responseHandler)
@@ -538,7 +542,6 @@
         return sendAsync(userRequest, responseHandler, null);
     }
 
-
     @Override
     public <T> CompletableFuture<HttpResponse<T>>
     sendAsync(HttpRequest userRequest,
@@ -596,13 +599,11 @@
                         (b,t) -> debugCompleted("ClientImpl (async)", start, userRequest));
             }
 
-            // makes sure that any dependent actions happen in the executor.
-            // we only need to do that for sendAsync(...), when exchangeExecutor
-            // is non null.
+            // makes sure that any dependent actions happen in the CF default
+            // executor. This is only needed for sendAsync(...), when
+            // exchangeExecutor is non-null.
             if (exchangeExecutor != null) {
-                executor = acc == null ? executor
-                        : new PrivilegedExecutor(executor, acc);
-                res = res.whenCompleteAsync((r, t) -> { /* do nothing */}, executor);
+                res = res.whenCompleteAsync((r, t) -> { /* do nothing */}, ASYNC_POOL);
             }
             return res;
         } catch(Throwable t) {
--- a/test/jdk/java/net/httpclient/DependentActionsTest.java	Wed Jun 06 15:23:38 2018 +0100
+++ b/test/jdk/java/net/httpclient/DependentActionsTest.java	Wed Jun 06 15:52:48 2018 +0100
@@ -82,12 +82,14 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static java.lang.System.out;
 import static java.lang.String.format;
+import static java.util.stream.Collectors.toList;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
 
@@ -374,13 +376,13 @@
     }
 
     final List<String> extractStream(HttpResponse<Stream<String>> resp) {
-        return resp.body().collect(Collectors.toList());
+        return resp.body().collect(toList());
     }
 
     final List<String> extractInputStream(HttpResponse<InputStream> resp) {
         try (InputStream is = resp.body()) {
             return new BufferedReader(new InputStreamReader(is))
-                    .lines().collect(Collectors.toList());
+                    .lines().collect(toList());
         } catch (IOException x) {
             throw new CompletionException(x);
         }
@@ -399,43 +401,27 @@
                 .findFirst();
     }
 
+    static final Predicate<StackFrame> DAT = sfe ->
+            sfe.getClassName().startsWith("DependentActionsTest");
+    static final Predicate<StackFrame> JUC = sfe ->
+            sfe.getClassName().startsWith("java.util.concurrent");
+    static final Predicate<StackFrame> JLT = sfe ->
+            sfe.getClassName().startsWith("java.lang.Thread");
+    static final Predicate<StackFrame> NotDATorJUCorJLT = Predicate.not(DAT.or(JUC).or(JLT));
+
+
     <T> void checkThreadAndStack(Thread thread,
                                  AtomicReference<RuntimeException> failed,
                                  T result,
                                  Throwable error) {
-        if (Thread.currentThread() == thread) {
-            //failed.set(new RuntimeException("Dependant action was executed in " + thread));
-            List<StackFrame> httpStack = WALKER.walk(s -> s.filter(f -> f.getDeclaringClass()
-                    .getModule().equals(HttpClient.class.getModule()))
-                    .collect(Collectors.toList()));
-            if (!httpStack.isEmpty()) {
-                System.out.println("Found unexpected trace: ");
-                httpStack.forEach(f -> System.out.printf("\t%s%n", f));
-                failed.set(new RuntimeException("Dependant action has unexpected frame in " +
-                        Thread.currentThread() + ": " + httpStack.get(0)));
+        //failed.set(new RuntimeException("Dependant action was executed in " + thread));
+        List<StackFrame> otherFrames = WALKER.walk(s -> s.filter(NotDATorJUCorJLT).collect(toList()));
+        if (!otherFrames.isEmpty()) {
+            System.out.println("Found unexpected trace: ");
+            otherFrames.forEach(f -> System.out.printf("\t%s%n", f));
+            failed.set(new RuntimeException("Dependant action has unexpected frame in " +
+                       Thread.currentThread() + ": " + otherFrames.get(0)));
 
-            }
-            return;
-        } else if (System.getSecurityManager() != null) {
-            Optional<StackFrame> sf = WALKER.walk(s -> findFrame(s, "PrivilegedRunnable"));
-            if (!sf.isPresent()) {
-                failed.set(new RuntimeException("Dependant action does not have expected frame in "
-                        + Thread.currentThread()));
-                return;
-            } else {
-                System.out.println("Found expected frame: " + sf.get());
-            }
-        } else {
-            List<StackFrame> httpStack = WALKER.walk(s -> s.filter(f -> f.getDeclaringClass()
-                    .getModule().equals(HttpClient.class.getModule()))
-                    .collect(Collectors.toList()));
-            if (!httpStack.isEmpty()) {
-                System.out.println("Found unexpected trace: ");
-                httpStack.forEach(f -> System.out.printf("\t%s%n", f));
-                failed.set(new RuntimeException("Dependant action has unexpected frame in " +
-                        Thread.currentThread() + ": " + httpStack.get(0)));
-
-            }
         }
     }