Skip to content

Commit 5fb9fe4

Browse files
rojyateslor6
andauthored
BAEL-5720 Java HttpClient Connection Management (#13452)
* BAEL-5642 Using @NotNull as a method parameter * BAEL-5642 Add Spring Boot and bump spring and hibernate-validator versions * BAEL-5720 Java HttpClient Connection Management * BAEL-5720 Java HttpClient Connection Management * BAEL-5720 move JavaHttpClient test to core-java-httpclient module * BAEL-5720 move jetty-logging-properties to core-java-httpclient module * BAEL-5720 add wiremock to pom * Update pom.xml * Delete jetty-logging.properties --------- Co-authored-by: Loredana Crusoveanu <lore.crusoveanu@gmail.com>
1 parent 5c9dcf7 commit 5fb9fe4

5 files changed

Lines changed: 159 additions & 2 deletions

File tree

apache-httpclient/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,4 @@
120120
<httpclient5-fluent.version>5.2</httpclient5-fluent.version>
121121
</properties>
122122

123-
</project>
123+
</project>

core-java-modules/core-java-httpclient/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
<version>${assertj.version}</version>
3333
<scope>test</scope>
3434
</dependency>
35+
<dependency>
36+
<groupId>com.github.tomakehurst</groupId>
37+
<artifactId>wiremock</artifactId>
38+
<version>${wiremock.version}</version>
39+
<scope>test</scope>
40+
</dependency>
3541
</dependencies>
3642

3743
<build>
@@ -53,6 +59,7 @@
5359
<maven.compiler.target.version>11</maven.compiler.target.version>
5460
<assertj.version>3.22.0</assertj.version>
5561
<mockserver.version>5.11.2</mockserver.version>
62+
<wiremock.version>2.27.2</wiremock.version>
5663
</properties>
5764

5865
</project>
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.baeldung.httpclient.conn;
2+
3+
import com.github.tomakehurst.wiremock.WireMockServer;
4+
import com.github.tomakehurst.wiremock.client.WireMock;
5+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
6+
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
7+
import org.junit.After;
8+
import org.junit.Before;
9+
import org.junit.Test;
10+
11+
import java.io.IOException;
12+
import java.net.http.HttpClient;
13+
import java.net.http.HttpRequest;
14+
import java.net.http.HttpResponse;
15+
import java.util.List;
16+
17+
import static java.net.URI.create;
18+
19+
20+
public class HttpClientConnectionManagementUnitTest {
21+
22+
WireMockConfiguration firstConfiguration = WireMockConfiguration
23+
.options()
24+
.dynamicPort();
25+
WireMockConfiguration secondConfiguration = WireMockConfiguration
26+
.options()
27+
.dynamicPort();
28+
WireMockServer firstServer = new WireMockServer(firstConfiguration);
29+
WireMockServer secondServer = new WireMockServer(secondConfiguration);
30+
private String firstUrl;
31+
private String secondUrl;
32+
33+
private HttpClient client = HttpClient.newHttpClient();
34+
private HttpClient secondClient = HttpClient.newHttpClient();
35+
36+
private HttpRequest getRequest;
37+
private HttpRequest secondGet;
38+
39+
@Before
40+
public void setup() {
41+
firstServer.start();
42+
secondServer.start();
43+
44+
// add some request matchers
45+
firstServer.stubFor(WireMock
46+
.get(WireMock.anyUrl())
47+
.willReturn(WireMock
48+
.aResponse()
49+
.withStatus(200)));
50+
secondServer.stubFor(WireMock
51+
.get(WireMock.anyUrl())
52+
.willReturn(WireMock
53+
.aResponse()
54+
.withStatus(200)));
55+
56+
firstUrl = "http://localhost:" + firstServer.port() + "/first";
57+
secondUrl = "http://localhost:" + secondServer.port() + "/second";
58+
59+
getRequest = HttpRequest
60+
.newBuilder()
61+
.uri(create(firstUrl))
62+
.version(HttpClient.Version.HTTP_1_1)
63+
.build();
64+
65+
secondGet = HttpRequest
66+
.newBuilder()
67+
.uri(create(secondUrl))
68+
.version(HttpClient.Version.HTTP_1_1)
69+
.build();
70+
}
71+
72+
@After
73+
public void tearDown() {
74+
// display all the requests that the WireMock servers handled
75+
List<ServeEvent> firstWiremockAllServeEvents = firstServer.getAllServeEvents();
76+
List<ServeEvent> secondWiremockAllServeEvents = secondServer.getAllServeEvents();
77+
firstWiremockAllServeEvents
78+
.stream()
79+
.map(event -> event
80+
.getRequest()
81+
.getAbsoluteUrl())
82+
.forEach(System.out::println);
83+
secondWiremockAllServeEvents
84+
.stream()
85+
.map(event -> event
86+
.getRequest()
87+
.getAbsoluteUrl())
88+
.forEach(System.out::println);
89+
90+
// stop the WireMock servers
91+
firstServer.stop();
92+
secondServer.stop();
93+
}
94+
95+
// Example 1. Use an HttpClient to connect to the same endpoint - reuses a connection from the internal pool
96+
@Test
97+
public final void givenAnHttpClient_whenTwoConnectionsToSameEndpointMadeSequentially_thenConnectionReused() throws InterruptedException, IOException {
98+
99+
// given two requests to the same destination
100+
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
101+
final HttpResponse<String> secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
102+
103+
assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200);
104+
}
105+
106+
// Example 2. Use separate HttpClients to connect to the same endpoint - creates a connection per client
107+
@Test
108+
public final void givenTwoHttpClients_whenEachClientMakesConnectionSequentially_thenConnectionCreatedForEach() throws InterruptedException, IOException {
109+
110+
// given requests from two different client to same destination
111+
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
112+
final HttpResponse<String> secondResponse = secondClient.send(getRequest, HttpResponse.BodyHandlers.ofString());
113+
114+
assert (firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200);
115+
}
116+
117+
// Example 3. Use an HttpClient to Connect to first, second, then first endpoint again.
118+
// New connections made each time when pool size is 1, or re-used when not restricted.
119+
// Make sure to set the JVM arg when running the test:
120+
// -Djdk.httpclient.connectionPoolSize=1
121+
@Test
122+
public final void givenAnHttpClientAndAPoolSizeOfOne_whenTwoConnectionsMadeBackToOriginal_thenFirstConnectionPurged() throws InterruptedException, IOException {
123+
124+
// given 3 requests, two to the first server and one to the second server
125+
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
126+
final HttpResponse<String> secondResponse = client.send(secondGet, HttpResponse.BodyHandlers.ofString());
127+
final HttpResponse<String> thirdResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
128+
129+
assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200) && (thirdResponse.statusCode() == 200));
130+
}
131+
132+
// Example 4. Use an HttpClient to connect, wait for connection keepalive to pass, then connect again. New connection made for both calls.
133+
// Make sure to set the JVM arg when running the test:
134+
// -Djdk.httpclient.keepalive.timeout=2
135+
@Test
136+
public final void givenAnHttpClientAndConnectionKeepAliveOfTwoSeconds_whenCallMadeAfterKeepaliveExpires_thenNewConnection() throws InterruptedException, IOException {
137+
138+
// given 2 requests to the same destination with the second call made after the keepalive timeout has passed
139+
final HttpResponse<String> firstResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
140+
Thread.sleep(3000); // exceeds 2 seconds configured by JVM arg
141+
final HttpResponse<String> secondResponse = client.send(getRequest, HttpResponse.BodyHandlers.ofString());
142+
143+
assert ((firstResponse.statusCode() == 200) && (secondResponse.statusCode() == 200));
144+
}
145+
146+
}
147+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StrErrLog
2+
org.eclipse.jetty.LEVEL=DEBUG
3+
jetty.logs=logs

javaxval/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<scope>test</scope>
4747
</dependency>
4848
</dependencies>
49-
49+
5050
<!-- uncomment in order to enable Hibernate Validator Anotation Processor -->
5151
<!-- <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> -->
5252
<!--<version>${maven.compiler.version}</version> <configuration> <source>${maven.compiler.source}</source> -->

0 commit comments

Comments
 (0)