Skip to content

Instantly share code, notes, and snippets.

@sshark
Last active March 29, 2017 06:26
Show Gist options
  • Save sshark/934fecd48618272e7754b419424ea2ad to your computer and use it in GitHub Desktop.
Save sshark/934fecd48618272e7754b419424ea2ad to your computer and use it in GitHub Desktop.
HTTP pool test between JDK URLConnection and Apache HTTPClient
package org.teckhooi;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.*;
import java.util.function.Supplier;
import static org.teckhooi.HttpPoolTest.RunOption.RunA;
import static org.teckhooi.HttpPoolTest.RunOption.RunB;
import static org.teckhooi.HttpPoolTest.RunOption.RunB1;
/**
* Bulk of the code is the same except this code does not POST to the server. It demonstrates GET from
* the server of different paths uses the same connection socket.
*/
public class HttpPoolGetTest {
// Refactor RunOption to use direct methods
public enum RunOption {RunA, RunB, RunB1, RunAll}
public static void main(String[] args) throws Exception {
System.out.println("http.maxConnections (default: 5): " + System.getProperty("http.maxConnections"));
System.out.println("http.keepAlive (default: true): " + System.getProperty("http.keepAlive"));
new HttpPoolGetTest().run(new URL("http://myrest.getsandbox.com"), RunA, 100, new ProxyAddress("localhost", 8080));
}
public void run(URL url, RunOption option, int numOfConnections, ProxyAddress proxyAddress) throws Exception {
switch (option) {
case RunA:
reportElaspedTime(() -> runWithHttpClient(url, numOfConnections, new HttpHost(proxyAddress.getHost(), proxyAddress.getPort())));
break;
case RunB:
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), true));
break;
case RunB1:
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), false));
break;
default:
reportElaspedTime(() -> runWithHttpClient(url, numOfConnections, new HttpHost(proxyAddress.getHost(), proxyAddress.getPort())));
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), true));
break;
}
}
private boolean runWithHttpClient(URL url, int numOfClients, HttpHost proxy) {
HttpClientBuilder httpClientBuilder = HttpClients.custom()
.setConnectionManager(cm)
.setMaxConnTotal(5)
.setMaxConnPerRoute(1);
CloseableHttpClient httpClient = proxy == null ?
httpClientBuilder.build() :
httpClientBuilder.setProxy(proxy).build();
/*
Option A: Using Apache HTTP Client
Preferred way to do HTTP connection in term of ease of use and predictability.
NOTE: Connecting to a different path of the same server does not create another connection socket.
*/
try {
generateAndStart(numOfClients, httpClient, new URIBuilder(url.toURI()), 0);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private boolean runWithURL(URL url, int numClients, Proxy proxy, boolean runConcurrent) {
/*
Option B: JDK 8 URL connections
Bad connection will result closing current socket and use a new socket. Using URLConnection instances created
from the same URL instance in a multi threaded environment will create multiple sockets to the server. To use
persistent connection, close the input stream and request for a new URLConnection instance from the URL
instance again. Closing the URLConnection does not equal to closing the socket.
No connection is open to the server until URLConnection.getInputStream() is executed.
NOTE: Connecting to a different path of the same server does not create another connection socket.
*/
try {
if (runConcurrent) {
concurrentGenerateAndStart(numClients, url, proxy, 0);
} else {
generateAndStart(numClients, url, proxy, 0);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private void concurrentGenerateAndStart(int num, URL baseUrl, Proxy proxy, long delay) throws Exception {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
URL url = baseUrl.toURI().resolve("/users/" + i).toURL();
URLConnection urlConnection = proxy == null ? url.openConnection() : url.openConnection(proxy);
urlConnection.setRequestProperty("Accept", "application/json");
System.out.println("Starting JDK URL worker: " + i);
int ndx = i;
workers[i] = new Thread(() -> connect(urlConnection, delay, ndx));
workers[i].start();
}
for (int j = 0; j < workers.length; j++) {
try {
workers[j].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void generateAndStart(int num, URL baseUrl, Proxy proxy, long delay) throws Exception {
for (int i = 0; i < num; i++) {
URL url = baseUrl.toURI().resolve("/users/" + i).toURL();
URLConnection urlConnection = proxy == null ? url.openConnection() : url.openConnection(proxy);
urlConnection.setRequestProperty("Accept", "application/json");
System.out.println("Starting JDK URL worker: " + i);
int ndx = i;
connect(urlConnection, delay, ndx);
}
}
private void connect(URLConnection urlConnection, long delay, int ndx) {
try {
System.out.println(urlConnection.getURL().toString() + " started.");
} catch (Exception e) {
e.printStackTrace();
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
printResponse(reader, urlConnection.getURL().toURI().getPath(), ndx);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void generateAndStart(int num, CloseableHttpClient httpClient, URIBuilder uriBuilder, long delay) throws Exception {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
System.out.println("Starting worker: " + i);
final int j = i;
uriBuilder.setPath("/users/" + i);
HttpGet request = new HttpGet(uriBuilder.build());
request.addHeader("Content-type", "application/json");
request.addHeader("Accept", "application/json");
workers[i] = new Thread(() -> {
try {
connect(httpClient, request, delay, j);
} catch (IOException e) {
e.printStackTrace();
}
});
workers[i].start();
}
for (int i = 0; i < workers.length; i++) {
try {
workers[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void connect(CloseableHttpClient httpClient, HttpGet request, long delay, int ndx) throws IOException {
System.out.println(request.getURI().toString() + " started.");
try (
BufferedReader reader = new BufferedReader(
new InputStreamReader(httpClient.execute(request, HttpClientContext.create()).getEntity().getContent()))) {
printResponse(reader, request.getURI().getPath(), ndx);
} catch (Exception e) {
e.printStackTrace();
}
}
private void printResponse(BufferedReader reader, String message, int ndx) throws IOException {
String line;
System.out.println("Status return for " + ndx + ": " + message);
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (Exception e) {
e.printStackTrace();
}
}
private void reportElaspedTime(Supplier<Boolean> supplier) {
long start = System.currentTimeMillis();
System.out.println("Time elapsed: " + (supplier.get() ? (System.currentTimeMillis() - start) : "** Exception **"));
}
static class ProxyAddress {
private String host;
private int port;
public ProxyAddress(String host, int port) {
this.host = host;
this.port = port;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
}
}
package org.teckhooi;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import java.io.*;
import java.net.*;
import java.util.function.Supplier;
import static org.teckhooi.HttpPoolTest.RunOption.RunA;
import static org.teckhooi.HttpPoolTest.RunOption.RunB;
import static org.teckhooi.HttpPoolTest.RunOption.RunB1;
public class HttpPoolTest {
// Refactor RunOption to use direct methods
public enum RunOption {RunA, RunB, RunB1, RunAll}
public static void main(String[] args) throws Exception {
System.out.println("http.maxConnections (default: 5): " + System.getProperty("http.maxConnections"));
System.out.println("http.keepAlive (default: true): " + System.getProperty("http.keepAlive"));
new HttpPoolTest().run(new URL("http://myrest.getsandbox.com/users"), RunB1, 20, new ProxyAddress("localhost", 8080));
}
public void run(URL url, RunOption option, int numOfConnections, ProxyAddress proxyAddress) throws Exception {
switch (option) {
case RunA:
reportElaspedTime(() -> runWithHttpClient(url, numOfConnections, new HttpHost(proxyAddress.getHost(), proxyAddress.getPort())));
break;
case RunB:
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), true));
break;
case RunB1:
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), false));
break;
default:
reportElaspedTime(() -> runWithHttpClient(url, numOfConnections, new HttpHost(proxyAddress.getHost(), proxyAddress.getPort())));
reportElaspedTime(() -> runWithURL(url, numOfConnections, new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyAddress.getHost(), proxyAddress.getPort())), true));
break;
}
}
private boolean runWithHttpClient(URL url, int numOfClients, HttpHost proxy) {
HttpClientBuilder httpClientBuilder = HttpClients.custom()
.setConnectionManager(cm)
.setMaxConnTotal(5)
.setMaxConnPerRoute(1);
CloseableHttpClient httpClient = proxy == null ?
httpClientBuilder.build() :
httpClientBuilder.setProxy(proxy).build();
/*
Option A: Using Apache HTTP Client
Preferred way to do HTTP connection in term of ease of use and predictability.
NOTE: Connecting to a different path of the same server does not create another connection socket.
*/
try {
HttpPost request = new HttpPost(url.toURI());
request.addHeader("Content-type", "application/json");
request.addHeader("Accept", "application/json");
generateAndStart(numOfClients, httpClient, request, 0);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private boolean runWithURL(URL url, int numClients, Proxy proxy, boolean runConcurrent) {
/*
Option B: JDK 8 URL connections
Bad connection will result closing current socket and use a new socket. Using URLConnection instances created
from the same URL instance in a multi threaded environment will create multiple sockets to the server. To use
persistent connection, close the input stream and request for a new URLConnection instance from the URL
instance again. Closing the URLConnection does not equal to closing the socket.
NOTE: Connecting to a different path of the same server does not create another connection socket.
*/
try {
if (runConcurrent) {
concurrentGenerateAndStart(numClients, url, proxy, 0);
} else {
generateAndStart(numClients, url, proxy, 0);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
private void concurrentGenerateAndStart(int num, URL url, Proxy proxy, long delay) throws IOException {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
HttpURLConnection urlConnection = (HttpURLConnection) (proxy == null ? url.openConnection() : url.openConnection(proxy));
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestProperty("Content-type", "application/json");
urlConnection.setDoOutput(true);
System.out.println("Starting JDK URL worker: " + i);
int ndx = i;
workers[i] = new Thread(() -> connect(urlConnection, delay, ndx));
workers[i].start();
}
for (int j = 0; j < workers.length; j++) {
try {
workers[j].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void generateAndStart(int num, URL url, Proxy proxy, long delay) throws IOException {
for (int i = 0; i < num; i++) {
HttpURLConnection urlConnection = (HttpURLConnection) (proxy == null ? url.openConnection() : url.openConnection(proxy));
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestProperty("Content-type", "application/json");
urlConnection.setDoOutput(true);
System.out.println("Starting JDK URL worker: " + i);
int ndx = i;
connect(urlConnection, delay, ndx);
}
}
private void connect(URLConnection urlConnection, long delay, int ndx) {
try {
System.out.println(urlConnection.getURL().toString() + " started.");
} catch (Exception e) {
e.printStackTrace();
}
String message = "{\"name\":\"Mr. " + i + "\"}";
PrintWriter writer = null;
BufferedReader reader = null;
try {
writer = new PrintWriter(new OutputStreamWriter(urlConnection.getOutputStream()));
writer.print(message);
writer.flush();
reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
printResponse(reader, message, ndx);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void generateAndStart(int num, CloseableHttpClient httpClient, HttpPost request, long delay) throws Exception {
Thread[] workers = new Thread[num];
for (int i = 0; i < num; i++) {
System.out.println("Starting worker: " + i);
final int j = i;
workers[i] = new Thread(() -> {
try {
connect(httpClient, request, delay, j);
} catch (IOException e) {
e.printStackTrace();
}
});
workers[i].start();
}
for (int i = 0; i < workers.length; i++) {
try {
workers[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void connect(CloseableHttpClient httpClient, HttpPost request, long delay, int ndx) throws IOException {
System.out.println(request.getURI().toString() + " started.");
String message = "{\"name\":\"Mr. " + i + "\"}";
request.setEntity(new StringEntity(message));
try (
BufferedReader reader = new BufferedReader(
new InputStreamReader(httpClient.execute(request, HttpClientContext.create()).getEntity().getContent()))) {
printResponse(reader, message, ndx);
} catch (Exception e) {
e.printStackTrace();
}
}
private void printResponse(BufferedReader reader, String message, int ndx) throws IOException {
String line;
System.out.println("Status return for " + ndx + ": " + message);
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (Exception e) {
e.printStackTrace();
}
}
private void reportElaspedTime(Supplier<Boolean> supplier) {
long start = System.currentTimeMillis();
System.out.println("Time elapsed: " + (supplier.get() ? (System.currentTimeMillis() - start) : "** Exception **"));
}
static class ProxyAddress {
private String host;
private int port;
public ProxyAddress(String host, int port) {
this.host = host;
this.port = port;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment