Use Java 11 HttpClient 18/96918/6
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 19 Jul 2021 10:00:58 +0000 (12:00 +0200)
committerTomas Cere <tomas.cere@pantheon.tech>
Fri, 30 Jul 2021 09:11:05 +0000 (09:11 +0000)
Reduce dependencies by using JRE-provided HTTP client.

JIRA: NETCONF-751
Change-Id: I49a51306a042ed534bafd7174633e300f00ce305
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
netconf/tools/netconf-testtool/pom.xml
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/Execution.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/ScaleUtil.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/AsyncExecutionStrategy.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/PerfClientCallable.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/RequestMessageUtils.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/http/perf/SyncExecutionStrategy.java

index 108983bc0d6cb8c29766da716be58c154e0b3bff..fa3c8f9c41d0f39ab8a84e33bde0da7a53b02d77 100644 (file)
             <artifactId>logback-classic</artifactId>
             <scope>compile</scope>
         </dependency>
-        <dependency>
-            <groupId>com.ning</groupId>
-            <artifactId>async-http-client</artifactId>
-            <version>1.9.40</version>
-        </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcpkix-jdk15on</artifactId>
index 4b1470a497697e54335e67326a8c2a2ea5fc09b1..208ee76c84eeff086fc2f17469ae724e1e2b287b 100644 (file)
@@ -7,25 +7,26 @@
  */
 package org.opendaylight.netconf.test.tool;
 
-import com.ning.http.client.AsyncCompletionHandler;
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig;
-import com.ning.http.client.HttpResponseStatus;
-import com.ning.http.client.Realm;
-import com.ning.http.client.Request;
-import com.ning.http.client.Response;
 import java.io.IOException;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpRequest.BodyPublishers;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Semaphore;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class Execution implements Callable<Void> {
 
-    private final ArrayList<Request> payloads;
-    private final AsyncHttpClient asyncHttpClient;
+    private final ArrayList<HttpRequest> payloads;
+    private final HttpClient httpClient;
     private static final Logger LOG = LoggerFactory.getLogger(Execution.class);
     private final boolean invokeAsync;
     private final Semaphore semaphore;
@@ -59,48 +60,44 @@ public class Execution implements Callable<Void> {
         }
         this.semaphore = new Semaphore(this.throttle);
 
-        this.asyncHttpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder()
-                .setConnectTimeout(Integer.MAX_VALUE)
-                .setRequestTimeout(Integer.MAX_VALUE)
-                .setAllowPoolingConnections(true)
-                .build());
-
+        this.httpClient = HttpClient.newBuilder()
+                .authenticator(new Authenticator() {
+                    @Override
+                    protected PasswordAuthentication getPasswordAuthentication() {
+                        return new PasswordAuthentication(params.controllerAuthUsername,
+                                params.controllerAuthPassword.toCharArray());
+                    }
+                })
+                .build();
         this.payloads = new ArrayList<>();
         for (DestToPayload payload : payloads) {
-            AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.preparePost(payload.getDestination())
-                    .addHeader("Content-Type", "application/json")
-                    .addHeader("Accept", "application/json")
-                    .setBody(payload.getPayload())
-                    .setRequestTimeout(Integer.MAX_VALUE);
-
-            requestBuilder.setRealm(new Realm.RealmBuilder()
-                    .setScheme(Realm.AuthScheme.BASIC)
-                    .setPrincipal(params.controllerAuthUsername)
-                    .setPassword(params.controllerAuthPassword)
-                    .setMethodName("POST")
-                    .setUsePreemptiveAuth(true)
-                    .build());
-
-            this.payloads.add(requestBuilder.build());
+            HttpRequest request = HttpRequest.newBuilder(URI.create(payload.getDestination()))
+                    .POST(BodyPublishers.ofString(payload.getPayload(), StandardCharsets.UTF_8))
+                    .header("Content-Type", "application/json")
+                    .header("Accept", "application/json")
+                    .build();
+
+            this.payloads.add(request);
         }
     }
 
     private void invokeSync() {
         LOG.info("Begin sending sync requests");
-        for (Request request : payloads) {
+        for (HttpRequest request : payloads) {
             try {
-                Response response = asyncHttpClient.executeRequest(request).get();
-                if (response.getStatusCode() != 200 && response.getStatusCode() != 204) {
-                    if (response.getStatusCode() == 409) {
+                HttpResponse<String> response = httpClient.send(request, BodyHandlers.ofString());
+
+                if (response.statusCode() != 200 && response.statusCode() != 204) {
+                    if (response.statusCode() == 409) {
                         LOG.warn("Request failed, status code: {} - one or more of the devices"
-                                + " is already configured, skipping the whole batch", response.getStatusCode());
+                                + " is already configured, skipping the whole batch", response.statusCode());
                     } else {
-                        LOG.warn("Status code: {}", response.getStatusCode());
-                        LOG.warn("url: {}", request.getUrl());
-                        LOG.warn("body: {}", response.getResponseBody());
+                        LOG.warn("Status code: {}", response.statusCode());
+                        LOG.warn("url: {}", request.uri());
+                        LOG.warn("body: {}", response.body());
                     }
                 }
-            } catch (InterruptedException | ExecutionException | IOException e) {
+            } catch (InterruptedException | IOException e) {
                 LOG.warn("Failed to execute request", e);
             }
         }
@@ -110,34 +107,23 @@ public class Execution implements Callable<Void> {
     private void invokeAsync() {
         LOG.info("Begin sending async requests");
 
-        for (final Request request : payloads) {
+        for (final HttpRequest request : payloads) {
             try {
                 semaphore.acquire();
             } catch (InterruptedException e) {
                 LOG.warn("Semaphore acquire interrupted");
             }
-            asyncHttpClient.executeRequest(request, new AsyncCompletionHandler<Response>() {
-                @Override
-                public STATE onStatusReceived(final HttpResponseStatus status) throws Exception {
-                    super.onStatusReceived(status);
-                    if (status.getStatusCode() != 200 && status.getStatusCode() != 204) {
-                        if (status.getStatusCode() == 409) {
-                            LOG.warn("Request failed, status code: {} - one or more of the devices"
-                                    + " is already configured, skipping the whole batch", status.getStatusCode());
-                        } else {
-                            LOG.warn("Request failed, status code: {}",
-                                status.getStatusCode() + status.getStatusText());
-                            LOG.warn("request: {}", request.toString());
-                        }
+            httpClient.sendAsync(request, BodyHandlers.ofString()).whenComplete((response, error) -> {
+                if (response.statusCode() != 200 && response.statusCode() != 204) {
+                    if (response.statusCode() == 409) {
+                        LOG.warn("Request failed, status code: {} - one or more of the devices"
+                                + " is already configured, skipping the whole batch", response.statusCode());
+                    } else {
+                        LOG.warn("Request failed, status code: {}", response.statusCode());
+                        LOG.warn("request: {}", request);
                     }
-                    return STATE.CONTINUE;
-                }
-
-                @Override
-                public Response onCompleted(final Response response) {
-                    semaphore.release();
-                    return response;
                 }
+                semaphore.release();
             });
         }
         LOG.info("Requests sent, waiting for responses");
index 5a65a5f88741d50ae1a7dd9f4c917e49e1d6fe01..ad8d49b6519df03c9cd0ed08f6e165fea50b4f83 100644 (file)
@@ -11,19 +11,18 @@ package org.opendaylight.netconf.test.tool;
 import ch.qos.logback.classic.Level;
 import com.google.common.base.Stopwatch;
 import com.google.common.io.CharStreams;
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig.Builder;
-import com.ning.http.client.Request;
-import com.ning.http.client.Response;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.ConnectException;
+import java.net.URI;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
 import java.util.List;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -190,36 +189,32 @@ public final class ScaleUtil {
                 + "network-topology:network-topology/topology/topology-netconf/";
         private static final Pattern PATTERN = Pattern.compile("connected");
 
-        private final AsyncHttpClient asyncHttpClient = new AsyncHttpClient(new Builder()
-                .setConnectTimeout(Integer.MAX_VALUE)
-                .setRequestTimeout(Integer.MAX_VALUE)
-                .setAllowPoolingConnections(true)
-                .build());
+        private final HttpClient httpClient = HttpClient.newBuilder().build();
         private final NetconfDeviceSimulator simulator;
         private final int deviceCount;
-        private final Request request;
+        private final HttpRequest request;
 
         ScaleVerifyCallable(final NetconfDeviceSimulator simulator, final int deviceCount) {
             LOG.info("New callable created");
             this.simulator = simulator;
             this.deviceCount = deviceCount;
-            AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.prepareGet(RESTCONF_URL)
-                    .addHeader("content-type", "application/xml")
-                    .addHeader("Accept", "application/xml")
-                    .setRequestTimeout(Integer.MAX_VALUE);
-            request = requestBuilder.build();
+            request = HttpRequest.newBuilder(URI.create(RESTCONF_URL))
+                    .GET()
+                    .header("Content-Type", "application/xml")
+                    .header("Accept", "application/xml")
+                    .build();
         }
 
         @Override
         public Void call() throws Exception {
             try {
-                final Response response = asyncHttpClient.executeRequest(request).get();
+                final HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
 
-                if (response.getStatusCode() != 200 && response.getStatusCode() != 204) {
-                    LOG.warn("Request failed, status code: {}", response.getStatusCode() + response.getStatusText());
+                if (response.statusCode() != 200 && response.statusCode() != 204) {
+                    LOG.warn("Request failed, status code: {}", response.statusCode());
                     EXECUTOR.schedule(new ScaleVerifyCallable(simulator, deviceCount), RETRY_DELAY, TimeUnit.SECONDS);
                 } else {
-                    final String body = response.getResponseBody();
+                    final String body = response.body();
                     final Matcher matcher = PATTERN.matcher(body);
                     int count = 0;
                     while (matcher.find()) {
@@ -236,7 +231,7 @@ public final class ScaleUtil {
                         SEMAPHORE.release();
                     }
                 }
-            } catch (ConnectException | ExecutionException e) {
+            } catch (ConnectException e) {
                 LOG.warn("Failed to connect to Restconf, is the controller running?", e);
                 EXECUTOR.schedule(new ScaleVerifyCallable(simulator, deviceCount), RETRY_DELAY, TimeUnit.SECONDS);
             }
index 1b23dcc47571d58066adac59aa3b79adf004eb2f..1895e4c3bffb2ea8b9bd55e11dc501815713083b 100644 (file)
@@ -5,16 +5,13 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
 import static org.opendaylight.netconf.test.tool.client.http.perf.RequestMessageUtils.formRequest;
 
-import com.ning.http.client.AsyncCompletionHandler;
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.HttpResponseStatus;
-import com.ning.http.client.Request;
-import com.ning.http.client.Response;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse.BodyHandlers;
 import java.util.concurrent.Semaphore;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
 import org.slf4j.Logger;
@@ -24,15 +21,15 @@ public class AsyncExecutionStrategy implements ExecutionStrategy {
 
     private static final Logger LOG = LoggerFactory.getLogger(AsyncExecutionStrategy.class);
 
+    private final HttpClient httpClient;
     private final Parameters params;
-    private final AsyncHttpClient asyncHttpClient;
     private final Semaphore semaphore;
     RestPerfClient.RequestData payloads;
 
-    AsyncExecutionStrategy(final Parameters params, final AsyncHttpClient asyncHttpClient,
-                           final RestPerfClient.RequestData payloads) {
+    AsyncExecutionStrategy(final Parameters params, final HttpClient httpClient,
+            final RestPerfClient.RequestData payloads) {
         this.params = params;
-        this.asyncHttpClient = asyncHttpClient;
+        this.httpClient = httpClient;
         this.payloads = payloads;
         this.semaphore = new Semaphore(RestPerfClient.throttle);
     }
@@ -42,30 +39,25 @@ public class AsyncExecutionStrategy implements ExecutionStrategy {
         LOG.info("Begin sending async requests");
 
         for (int i = 0; i < payloads.getRequests(); i++) {
-            String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
+            final String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
                     payloads.getContentString(), payloads.getPort());
-            Request request = formRequest(asyncHttpClient, payloads.getDestination(), params, message);
+            final String url = payloads.getDestination();
+            final HttpRequest request = formRequest(url, message);
             try {
                 semaphore.acquire();
             } catch (InterruptedException e) {
                 LOG.warn("Semaphore acquire interrupted");
             }
-            asyncHttpClient.executeRequest(request, new AsyncCompletionHandler<Response>() {
-                @Override
-                public STATE onStatusReceived(HttpResponseStatus status) throws Exception {
-                    super.onStatusReceived(status);
-                    if (status.getStatusCode() != 200 && status.getStatusCode() != 204) {
-                        LOG.warn("Request failed, status code: {}", status.getStatusCode() + status.getStatusText());
-                        LOG.warn("request: {}", request.toString());
-                    }
-                    return STATE.CONTINUE;
-                }
-
-                @Override
-                public Response onCompleted(Response response) {
-                    semaphore.release();
-                    return response;
+            httpClient.sendAsync(request, BodyHandlers.ofString()).whenComplete((response, error) -> {
+                switch (response.statusCode()) {
+                    case 200:
+                    case 204:
+                        break;
+                    default:
+                        LOG.warn("Request failed, status code: {}", response.statusCode());
+                        LOG.warn("request: {}", request);
                 }
+                semaphore.release();
             });
         }
         LOG.info("Requests sent, waiting for responses");
index 2ec721f29ee7401b9e305b2c0c6ed762e455f36f..02323933a5b2d23dff8c7b298d8571d5a4ec64a7 100644 (file)
@@ -5,46 +5,38 @@
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
-
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.net.http.HttpClient;
+import java.net.http.HttpClient.Builder;
 import java.util.concurrent.Callable;
 import org.opendaylight.netconf.test.tool.client.http.perf.RestPerfClient.RequestData;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class PerfClientCallable implements Callable<Void> {
-    private static final Logger LOG = LoggerFactory.getLogger(PerfClientCallable.class);
-
-    private final Parameters params;
-    private final AsyncHttpClient asyncHttpClient;
-    private ExecutionStrategy executionStrategy;
-    private RequestData payloads;
+    private final ExecutionStrategy executionStrategy;
 
-    public PerfClientCallable(Parameters params, RequestData payloads) {
-        this.params = params;
-        this.payloads = payloads;
-        this.asyncHttpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder()
-                .setConnectTimeout(Integer.MAX_VALUE)
-                .setRequestTimeout(Integer.MAX_VALUE)
-                .setAllowPoolingConnections(true)
-                .build());
-        executionStrategy = getExecutionStrategy();
-    }
+    public PerfClientCallable(final Parameters params, final RequestData payloads) {
+        final Builder builder = HttpClient.newBuilder();
+        if (params.auth != null) {
+            builder.authenticator(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(params.auth.get(0), params.auth.get(1).toCharArray());
+                }
+            });
+        }
 
-    private ExecutionStrategy getExecutionStrategy() {
-        return params.async
-                ? new AsyncExecutionStrategy(params, asyncHttpClient, payloads)
-                : new SyncExecutionStrategy(params, asyncHttpClient, payloads);
+        this.executionStrategy = params.async
+            ? new AsyncExecutionStrategy(params, builder.build(), payloads)
+            : new SyncExecutionStrategy(builder.build(), payloads);
     }
 
     @Override
     public Void call() {
         executionStrategy.invoke();
-        asyncHttpClient.closeAsynchronously();
         return null;
     }
 }
index 0b83cce0b518bf8bb432f25ca765431507eeb53e..2562e456982a742704b861ac523788d874dd5792 100644 (file)
@@ -7,9 +7,10 @@
  */
 package org.opendaylight.netconf.test.tool.client.http.perf;
 
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.Realm;
-import com.ning.http.client.Request;
+import java.net.URI;
+import java.net.http.HttpRequest;
+import java.net.http.HttpRequest.BodyPublishers;
+import java.nio.charset.StandardCharsets;
 import org.opendaylight.netconf.test.tool.TestToolUtils;
 
 public final class RequestMessageUtils {
@@ -63,8 +64,8 @@ public final class RequestMessageUtils {
         return messageBuilder.toString();
     }
 
-    public static RestPerfClient.RequestData formPayload(Parameters parameters, String editContentString,
-                                                         int threadId, int requests) {
+    public static RestPerfClient.RequestData formPayload(final Parameters parameters, final String editContentString,
+                                                         final int threadId, final int requests) {
         final int devicePort = parameters.sameDevice
                 ? parameters.devicePortRangeStart : parameters.devicePortRangeStart + threadId;
         final StringBuilder destBuilder = new StringBuilder(DEST);
@@ -90,23 +91,11 @@ public final class RequestMessageUtils {
                 threadId, devicePort, requests);
     }
 
-    public static Request formRequest(AsyncHttpClient asyncHttpClient, String url, Parameters params, String msg) {
-        AsyncHttpClient.BoundRequestBuilder requestBuilder = asyncHttpClient.preparePost(url)
-                .addHeader("content-type", "application/json")
-                .addHeader("Accept", "application/xml")
-                .setBody(msg)
-                .setRequestTimeout(Integer.MAX_VALUE);
-
-        if (params.auth != null) {
-            requestBuilder.setRealm(new Realm.RealmBuilder()
-                    .setScheme(Realm.AuthScheme.BASIC)
-                    .setPrincipal(params.auth.get(0))
-                    .setPassword(params.auth.get(1))
-                    .setUsePreemptiveAuth(true)
-                    .build());
-        }
-        return requestBuilder.build();
+    public static HttpRequest formRequest(final String url, final String msg) {
+        return HttpRequest.newBuilder(URI.create(url))
+            .POST(BodyPublishers.ofString(msg, StandardCharsets.UTF_8))
+            .header("content-type", "application/json")
+            .header("Accept", "application/xml")
+            .build();
     }
-
-
 }
index 79cb2450ee6f9ce00c92a67d057a61119738294a..94e3277963269f62471afb16aa1140ab03896292 100644 (file)
@@ -9,28 +9,22 @@ package org.opendaylight.netconf.test.tool.client.http.perf;
 
 import static org.opendaylight.netconf.test.tool.client.http.perf.RequestMessageUtils.formRequest;
 
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.Request;
-import com.ning.http.client.Response;
 import java.io.IOException;
-import java.util.concurrent.ExecutionException;
+import java.net.http.HttpClient;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandlers;
 import org.opendaylight.netconf.test.tool.client.stress.ExecutionStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 public class SyncExecutionStrategy implements ExecutionStrategy {
-
     private static final Logger LOG = LoggerFactory.getLogger(SyncExecutionStrategy.class);
 
-    private final Parameters params;
+    private final HttpClient httpClient;
     private final RestPerfClient.RequestData payloads;
-    private final AsyncHttpClient asyncHttpClient;
 
-    SyncExecutionStrategy(final Parameters params, final AsyncHttpClient asyncHttpClient,
-                          final RestPerfClient.RequestData payloads) {
-        this.params = params;
-        this.asyncHttpClient = asyncHttpClient;
+    SyncExecutionStrategy(final HttpClient httpClient, final RestPerfClient.RequestData payloads) {
+        this.httpClient = httpClient;
         this.payloads = payloads;
     }
 
@@ -39,21 +33,22 @@ public class SyncExecutionStrategy implements ExecutionStrategy {
 
         LOG.info("Begin sending sync requests");
         for (int i = 0; i < payloads.getRequests(); i++) {
-            String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
+            final String message = RequestMessageUtils.prepareMessage(payloads.getThreadId(), i,
                     payloads.getContentString(), payloads.getPort());
-            Request request = formRequest(asyncHttpClient, payloads.getDestination(), params, message);
+            final HttpResponse<String> response;
             try {
-                Response response = asyncHttpClient.executeRequest(request).get();
-                if (response.getStatusCode() != 200 && response.getStatusCode() != 204) {
-                    LOG.warn("Status code: {}", response.getStatusCode());
-                    LOG.warn("url: {}", request.getUrl());
-                    LOG.warn("body: {}", response.getResponseBody());
-                }
-            } catch (InterruptedException | ExecutionException | IOException e) {
+                response = httpClient.send(formRequest(payloads.getDestination(), message), BodyHandlers.ofString());
+            } catch (InterruptedException | IOException e) {
                 LOG.warn("Failed to execute request", e);
+                return;
+            }
+
+            if (response.statusCode() != 200 && response.statusCode() != 204) {
+                LOG.warn("Status code: {}", response.statusCode());
+                LOG.warn("url: {}", response.uri());
+                LOG.warn("body: {}", response.body());
             }
         }
         LOG.info("End sending sync requests");
-
     }
 }