You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2021/02/27 12:52:45 UTC
[httpcomponents-website] branch master updated: HttpClient 5.x
migration guide
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-website.git
The following commit(s) were added to refs/heads/master by this push:
new 93ce8cc HttpClient 5.x migration guide
93ce8cc is described below
commit 93ce8ccdbf8137cc8735d3a7db0d17dc6417b01b
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sat Feb 27 13:52:16 2021 +0100
HttpClient 5.x migration guide
---
pom.xml | 13 +-
samples/pom.xml | 33 +++++
.../migration/examples/HttpClient4Example.java | 114 +++++++++++++++++
.../examples/HttpClient5AsyncSimpleExample.java | 135 +++++++++++++++++++++
.../examples/HttpClient5AsyncStreamExample.java | 131 ++++++++++++++++++++
.../HttpClient5AsyncStreamHttp2Example.java | 117 ++++++++++++++++++
.../examples/HttpClient5ClassicExample.java | 122 +++++++++++++++++++
.../migration-guide/index.md | 26 ++++
.../migration-guide/migration-to-async-http2.md | 80 ++++++++++++
.../migration-guide/migration-to-async-simple.md | 125 +++++++++++++++++++
.../migration-to-async-streaming.md | 115 ++++++++++++++++++
.../migration-guide/migration-to-classic.md | 121 ++++++++++++++++++
.../migration-guide/preparation.md | 113 +++++++++++++++++
src/site/site.xml | 7 ++
14 files changed, 1243 insertions(+), 9 deletions(-)
diff --git a/pom.xml b/pom.xml
index 85d9fe9..109e4b0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,10 @@
</site>
</distributionManagement>
+ <modules>
+ <module>samples</module>
+ </modules>
+
<reporting>
<plugins>
<plugin>
@@ -144,13 +148,4 @@
</plugins>
</build>
- <profiles>
- <profile>
- <id>sample-code</id>
- <modules>
- <module>samples</module>
- </modules>
- </profile>
- </profiles>
-
</project>
diff --git a/samples/pom.xml b/samples/pom.xml
index d3392b3..78d82b1 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -38,8 +38,12 @@
<packaging>jar</packaging>
<properties>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
<hc4.client.version>4.5.13</hc4.client.version>
<hc5.client.version>5.0.3</hc5.client.version>
+ <jackson.version>2.9.6</jackson.version>
+ <asyncjson.version>0.2.0</asyncjson.version>
</properties>
<dependencies>
@@ -63,8 +67,37 @@
<artifactId>httpclient5-fluent</artifactId>
<version>${hc5.client.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.ok2c.hc5</groupId>
+ <artifactId>hc5-async-json</artifactId>
+ <version>${asyncjson.version}</version>
+ </dependency>
</dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ <skipDeploy>true</skipDeploy>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
<reporting>
<plugins>
diff --git a/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient4Example.java b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient4Example.java
new file mode 100644
index 0000000..5d6bc36
--- /dev/null
+++ b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient4Example.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 OK2 Consulting Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hc.client5.migration.examples;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.CookieStore;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.EntityTemplate;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.ssl.SSLContexts;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class HttpClient4Example {
+
+ public static void main(String... args) throws Exception {
+ CloseableHttpClient client = HttpClients.custom()
+ .setSSLSocketFactory(new SSLConnectionSocketFactory(
+ SSLContexts.createSystemDefault(),
+ new String[] { "TLSv1.2" },
+ null,
+ SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
+ .setConnectionTimeToLive(1, TimeUnit.MINUTES)
+ .setDefaultSocketConfig(SocketConfig.custom()
+ .setSoTimeout(5000)
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(5000)
+ .setSocketTimeout(5000)
+ .setCookieSpec(CookieSpecs.STANDARD_STRICT)
+ .build())
+ .build();
+
+ CookieStore cookieStore = new BasicCookieStore();
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(10000)
+ .setSocketTimeout(10000)
+ .setCookieSpec(CookieSpecs.STANDARD)
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpPost httpPost = new HttpPost("https://httpbin.org/post");
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+
+ EntityTemplate requestEntity = new EntityTemplate(outstream -> {
+ objectMapper.writeValue(outstream, requestData);
+ outstream.flush();
+
+ });
+ requestEntity.setContentType(ContentType.APPLICATION_JSON.toString());
+ httpPost.setEntity(requestEntity);
+
+ JsonNode responseData = client.execute(httpPost, response -> {
+ if (response.getStatusLine().getStatusCode() >= 300) {
+ throw new ClientProtocolException(Objects.toString(response.getStatusLine()));
+ }
+ final HttpEntity responseEntity = response.getEntity();
+ if (responseEntity == null) {
+ return null;
+ }
+ try (InputStream inputStream = responseEntity.getContent()) {
+ return objectMapper.readTree(inputStream);
+ }
+ });
+ System.out.println(responseData);
+
+ client.close();
+ }
+
+}
diff --git a/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncSimpleExample.java b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncSimpleExample.java
new file mode 100644
index 0000000..c94451b
--- /dev/null
+++ b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncSimpleExample.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2018 OK2 Consulting Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hc.client5.migration.examples;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
+import org.apache.hc.client5.http.async.methods.SimpleHttpRequests;
+import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.BasicCookieStore;
+import org.apache.hc.client5.http.cookie.CookieStore;
+import org.apache.hc.client5.http.cookie.StandardCookieSpec;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.ssl.TLS;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.pool.PoolReusePolicy;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.ssl.SSLContexts;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class HttpClient5AsyncSimpleExample {
+
+ public static void main(String... args) throws Exception {
+ PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+
+ CloseableHttpAsyncClient client = HttpAsyncClients.custom()
+ .setConnectionManager(connectionManager)
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
+ .build();
+ client.start();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ SimpleHttpRequest httpPost = SimpleHttpRequests.post("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+
+ httpPost.setBody(objectMapper.writeValueAsString(requestData), ContentType.APPLICATION_JSON);
+
+ Future<?> future = client.execute(httpPost, new FutureCallback<SimpleHttpResponse>() {
+
+ @Override
+ public void completed(SimpleHttpResponse response) {
+ try {
+ JsonNode responseData = objectMapper.readTree(response.getBodyText());
+ System.out.println(responseData);
+ } catch (IOException ex) {
+ System.out.println("Error processing jSON content: " + ex.getMessage());
+ }
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+
+ future.get();
+ client.close(CloseMode.GRACEFUL);
+ }
+
+}
diff --git a/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamExample.java b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamExample.java
new file mode 100644
index 0000000..05f22fe
--- /dev/null
+++ b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamExample.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2018 OK2 Consulting Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hc.client5.migration.examples;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.apache.hc.client5.http.async.methods.BasicHttpRequests;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.BasicCookieStore;
+import org.apache.hc.client5.http.cookie.CookieStore;
+import org.apache.hc.client5.http.cookie.StandardCookieSpec;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.Message;
+import org.apache.hc.core5.http.ssl.TLS;
+import org.apache.hc.core5.http2.HttpVersionPolicy;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.pool.PoolReusePolicy;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.ssl.SSLContexts;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+import org.apache.http.NameValuePair;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ok2c.hc5.json.http.JsonRequestProducers;
+import com.ok2c.hc5.json.http.JsonResponseConsumers;
+
+public class HttpClient5AsyncStreamExample {
+
+ public static void main(String... args) throws Exception {
+ PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+
+ CloseableHttpAsyncClient client = HttpAsyncClients.custom()
+ .setConnectionManager(connectionManager)
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
+ .build();
+ client.start();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpRequest httpPost = BasicHttpRequests.post("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new org.apache.http.message.BasicNameValuePair("name1", "value1"),
+ new org.apache.http.message.BasicNameValuePair("name2", "value2"));
+
+ Future<?> future = client.execute(
+ JsonRequestProducers.create(httpPost, requestData, objectMapper),
+ JsonResponseConsumers.create(jsonFactory),
+ new FutureCallback<Message<HttpResponse, JsonNode>>() {
+
+ @Override
+ public void completed(Message<HttpResponse, JsonNode> message) {
+ System.out.println(message.getBody());
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+
+ future.get();
+ client.close(CloseMode.GRACEFUL);
+ }
+
+}
diff --git a/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamHttp2Example.java b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamHttp2Example.java
new file mode 100644
index 0000000..c35e2df
--- /dev/null
+++ b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5AsyncStreamHttp2Example.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 OK2 Consulting Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hc.client5.migration.examples;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+
+import org.apache.hc.client5.http.async.methods.BasicHttpRequests;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.BasicCookieStore;
+import org.apache.hc.client5.http.cookie.CookieStore;
+import org.apache.hc.client5.http.cookie.StandardCookieSpec;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.Message;
+import org.apache.hc.core5.http.ssl.TLS;
+import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.ssl.SSLContexts;
+import org.apache.hc.core5.util.Timeout;
+import org.apache.http.NameValuePair;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ok2c.hc5.json.http.JsonRequestProducers;
+import com.ok2c.hc5.json.http.JsonResponseConsumers;
+
+public class HttpClient5AsyncStreamHttp2Example {
+
+ public static void main(String... args) throws Exception {
+ CloseableHttpAsyncClient client = HttpAsyncClients.customHttp2()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .build();
+ client.start();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpRequest httpPost = BasicHttpRequests.post("https://nghttp2.org/httpbin/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new org.apache.http.message.BasicNameValuePair("name1", "value1"),
+ new org.apache.http.message.BasicNameValuePair("name2", "value2"));
+
+ Future<?> future = client.execute(
+ JsonRequestProducers.create(httpPost, requestData, objectMapper),
+ JsonResponseConsumers.create(jsonFactory),
+ new FutureCallback<Message<HttpResponse, JsonNode>>() {
+
+ @Override
+ public void completed(Message<HttpResponse, JsonNode> message) {
+ System.out.println(message.getBody());
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+
+ future.get();
+ client.close(CloseMode.GRACEFUL);
+ }
+
+}
diff --git a/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5ClassicExample.java b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5ClassicExample.java
new file mode 100644
index 0000000..8e19779
--- /dev/null
+++ b/samples/src/main/java/org/apache/hc/client5/migration/examples/HttpClient5ClassicExample.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2018 OK2 Consulting Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hc.client5.migration.examples;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.cookie.BasicCookieStore;
+import org.apache.hc.client5.http.cookie.CookieStore;
+import org.apache.hc.client5.http.cookie.StandardCookieSpec;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.NameValuePair;
+import org.apache.hc.core5.http.io.SocketConfig;
+import org.apache.hc.core5.http.io.entity.HttpEntities;
+import org.apache.hc.core5.http.message.BasicNameValuePair;
+import org.apache.hc.core5.http.message.StatusLine;
+import org.apache.hc.core5.http.ssl.TLS;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.pool.PoolReusePolicy;
+import org.apache.hc.core5.ssl.SSLContexts;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class HttpClient5ClassicExample {
+
+ public static void main(String... args) throws Exception {
+ PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
+ .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setDefaultSocketConfig(SocketConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+
+ CloseableHttpClient client = HttpClients.custom()
+ .setConnectionManager(connectionManager)
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .build();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpPost httpPost = new HttpPost("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+ httpPost.setEntity(HttpEntities.create(outstream -> {
+ objectMapper.writeValue(outstream, requestData);
+ outstream.flush();
+ }, ContentType.APPLICATION_JSON));
+
+ JsonNode responseData = client.execute(httpPost, response -> {
+ if (response.getCode() >= 300) {
+ throw new ClientProtocolException(new StatusLine(response).toString());
+ }
+ final HttpEntity responseEntity = response.getEntity();
+ if (responseEntity == null) {
+ return null;
+ }
+ try (InputStream inputStream = responseEntity.getContent()) {
+ return objectMapper.readTree(inputStream);
+ }
+ });
+ System.out.println(responseData);
+
+ client.close();
+ }
+
+}
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/index.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/index.md
new file mode 100644
index 0000000..447f8e2
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/index.md
@@ -0,0 +1,26 @@
+# Apache HttpClient 5.0 migration guide
+
+1. [Migration from HttpClient 4.x](preparation.md)
+
+ Prior to migration from HttpClient 4.x to HttpClient 5.0 it is highly recommended to ensure that HttpClient 4.x is up
+ to date and is being used in accordance with the best practices and recommendations.
+
+1. [Migration to HttpClient 5.0 classic APIs](migration-to-classic.md)
+
+ When migrating from HttpClient 4.x to HttpClient 5.0 it is generally recommended to migrate to the classic APIs as
+ the first step.
+
+1. [Migration to HttpClient 5.0 async APIs with simple handlers](migration-to-async-simple.md)
+
+ When migrating to HttpClient 5.0 async APIs it might be easier to start off by using simple (using in-memory buffers)
+ asynchronous handlers.
+
+1. [Migration to HttpClient 5.0 async APIs](migration-to-async-streaming.md)
+
+ The ultimate goal of the migration process should be to use HttpClient 5.0 async APIs with full content streaming
+ over full-duplex HTTP/1.1 or HTTP/2 connections.
+
+1. [Migration to HttpClient 5.0 async APIs for HTTP/2 only](migration-to-async-http2.md)
+
+ For those scenarios where HTTP/1.1 compatibility is no longer required HttpClient 5.0 provides HTTP/2 optimized
+ clients.
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-http2.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-http2.md
new file mode 100644
index 0000000..2719383
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-http2.md
@@ -0,0 +1,80 @@
+# Migration to Apache HttpClient 5.0 async APIs for HTTP/2 only
+
+For those scenarios where HTTP/1.1 compatibility is no longer required HttpClient 5.0
+provides `CloseableHttpAsyncClient` optimized for HTTP/2 protocol with full support for multiplexed request execution
+over a single HTTP/2 connection.
+
+## Migration steps
+
+- Replace the default client builder with HTTP/2 specific one. Request and response handlers do not require any
+ modification.
+
+ Please note HTTP/2 clients do not have a connection manager. They maintain an internal map of active connections,
+ one per distinct origin host. Therefore, TLS settings can be applied directly to the client instance, not a
+ connection manager.
+
+ Please note that presently HTTP/2 clients do not support request execution via an HTTP proxy.
+
+ ```java
+ CloseableHttpAsyncClient client = HttpAsyncClients.customHttp2()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .build();
+ client.start();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpRequest httpPost = BasicHttpRequests.post("https://nghttp2.org/httpbin/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new org.apache.http.message.BasicNameValuePair("name1", "value1"),
+ new org.apache.http.message.BasicNameValuePair("name2", "value2"));
+
+ Future<?> future = client.execute(
+ JsonRequestProducers.create(httpPost, requestData, objectMapper),
+ JsonResponseConsumers.create(jsonFactory),
+ new FutureCallback<Message<HttpResponse, JsonNode>>() {
+
+ @Override
+ public void completed(Message<HttpResponse, JsonNode> message) {
+ System.out.println(message.getBody());
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+
+ future.get();
+ client.close(CloseMode.GRACEFUL);
+ ```
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-simple.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-simple.md
new file mode 100644
index 0000000..eb4db96
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-simple.md
@@ -0,0 +1,125 @@
+# Migration to Apache HttpClient 5.0 async APIs with simple message handlers
+
+While HttpClient 5.0 classic APIs are largely compatible with HttpClient 4.0 APIs and can work with
+any `InputStream / OutputStream` based content processing library, the HttpClient 5.0 async APIs are completely
+different.
+
+HttpClient 5.0 async APIs use an event-driven, reactive programming model based on the concept of channels and event
+handlers. The channels act as conduits for asynchronous data output. The event handlers react to asynchronous signals or
+events and communicate with the opposite endpoint through available channels.
+
+Both the classic and the async models have their merits. The event-driven, reactive model tends to be efficient and
+convenient for communication protocols with message multiplexing such as HTTP/2. However async APIs generally not
+integrate well with `InputStream / OutputStream` based content processing libraries.
+
+HttpClient 5.0 provides simplified request and response handlers that hide the complexity of the event-driven model by
+buffering message content in memory. Simplified APIs are intended as a temporary, intermediate step in the migration
+process or for productive use in scenarios where messages known to be limited in length and the opposite endpoints are
+either known to be well-behaved or specifically designed for simple message handlers.
+
+## Migration steps
+
+- Replace `PoolingHttpClientConnectionManager` with `PoolingAsyncClientConnectionManager`
+
+ ```java
+ PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+ ```
+
+ Please note that `PoolingAsyncClientConnectionManager` uses different `TLS/SSL` configuration. It also does not
+ support `SocketConfig` configuration due to differences in the I/O model.
+
+- Replace `CloseableHttpClient` with `CloseableHttpAsyncClient`.
+
+- Select appropriate HTTP version policy. Presently supported policies are: `NEGOTIATE`, `FORCE_HTTP_1`
+ and `FORCE_HTTP_2`. When the `NEGOTIATE` policy is chosen, HttpClient attempts to negotiate the use of HTTP/2 through
+ the TLS ALPN (application protocol negotiation) extension as long as it is supported by the default JSSE .
+
+ ```java
+ CloseableHttpAsyncClient client = HttpAsyncClients.custom()
+ .setConnectionManager(connectionManager)
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
+ .build();
+ ```
+
+ When running on Java 9 or newer HttpClient can use TLS ALPN supported provided by the standard JSSE provider via
+ reflection. When running on Java 1.7 or Java 1.8 it can automatically detect Conscrypt TLS library if it is present
+ on the classpath and use its JSSE provider instead of the standard one shipped with the platform.
+
+- Unlike the classic client the asynchronous one needs to be started in order to be able to execute requests.
+
+ ```java
+ client.start();
+ ```
+- Request execution with simple asynchronous handlers is not that radically different than with the classic APIs. The
+ major difference is that the result of the operation is controlled with a `Future` interface and is signalled
+ with `FutureCallback` events.
+
+ Message content processing for simple asynchronous handlers can be implemented with any library that can work with
+ I/O streams (`InputStream`/`OutputStream`) or strings.
+
+ ```java
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ SimpleHttpRequest httpPost = SimpleHttpRequests.post("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+
+ httpPost.setBody(objectMapper.writeValueAsString(requestData), ContentType.APPLICATION_JSON);
+
+ Future<?> future = client.execute(httpPost, new FutureCallback<SimpleHttpResponse>() {
+
+ @Override
+ public void completed(SimpleHttpResponse response) {
+ try {
+ JsonNode responseData = objectMapper.readTree(response.getBodyText());
+ System.out.println(responseData);
+ } catch (IOException ex) {
+ System.out.println("Error processing jSON content: " + ex.getMessage());
+ }
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+ ```
+- `CloseableHttpAsyncClient` instances should be closed when no longer needed or about to go out of score.
+
+ ```java
+ client.close(CloseMode.GRACEFUL);
+ ```
\ No newline at end of file
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-streaming.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-streaming.md
new file mode 100644
index 0000000..497dd94
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-async-streaming.md
@@ -0,0 +1,115 @@
+# Migration to Apache HttpClient 5.0 async APIs
+
+HttpClient ships with a number of standard message handlers for the most common scenarios as well as a number of
+abstract classes that can be used as a base for custom handlers.
+
+* `BasicAsyncEntityConsumer`, `BasicAsyncEntityProducer` entity handlers that buffer entity content in memory and
+ therefore are not much different than simple handlers.
+
+* `AbstractBinAsyncEntityConsumer` and `AbstractBinAsyncEntityProducer` handlers can server as the base classes for
+ custom binary entity consumers or producers.
+
+* `AbstractCharAsyncEntityConsumer` and `AbstractCharAsyncEntityProducer` handlers can server as the base classes for
+ custom character entity consumers or producers.
+
+* `FileEntityProducer` entity handler that generates data stream from a file.
+
+* `AbstractClassicEntityConsumer` and `AbstractClassicEntityProducer` entity handlers that acts as a compatibility layer
+ for classic `InputStream` / `OutputStream` based interfaces. Blocking input / output processing is executed through
+ an `Executor`.
+
+* `BasicRequestProducer` and `BasicResponseConsumer` messages handlers that perform no message head transformation and
+ can use any custom entity producer or consumer to handler the message body.
+
+* `AbstractBinResponseConsumer` response handler can server as the base class for custom binary response consumers.
+
+* `AbstractCharResponseConsumer` response handler can server as the base class for custom character response consumers.
+
+There are also third-party libraries that can provide specialized message handlers, for instance,
+for [JSON message processing](https://github.com/ok2c/httpcomponents-jackson) using
+[Jackson JSON processor](https://github.com/FasterXML/jackson).
+
+## Migration steps
+
+- Depending on the preferred migration path it one might consider migrating to HttpClient 5.0 classic APIs or
+ HttpClient 5.0 async APIs with simple message handlers as the first step.
+
+- Replace the existing request generation and response processing code with optimized message handlers shipped with
+ HttpClient 5.0 or custom-built handlers.
+
+ In this particular instance [JSON message handlers](https://github.com/ok2c/httpcomponents-jackson)
+ are used to process JSON messages of arbitrary length without intermediate buffering of the entire message.
+
+ The general use pattern remains the same as with simple message handlers.
+
+ ```java
+ PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
+ .setTlsStrategy(ClientTlsStrategyBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+
+ CloseableHttpAsyncClient client = HttpAsyncClients.custom()
+ .setConnectionManager(connectionManager)
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .setVersionPolicy(HttpVersionPolicy.NEGOTIATE)
+ .build();
+ client.start();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpRequest httpPost = BasicHttpRequests.post("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new org.apache.http.message.BasicNameValuePair("name1", "value1"),
+ new org.apache.http.message.BasicNameValuePair("name2", "value2"));
+
+ Future<?> future = client.execute(
+ JsonRequestProducers.create(httpPost, requestData, objectMapper),
+ JsonResponseConsumers.create(jsonFactory),
+ new FutureCallback<Message<HttpResponse, JsonNode>>() {
+
+ @Override
+ public void completed(Message<HttpResponse, JsonNode> message) {
+ System.out.println(message.getBody());
+ }
+
+ @Override
+ public void failed(Exception ex) {
+ System.out.println("Error executing HTTP request: " + ex.getMessage());
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println("HTTP request execution cancelled");
+ }
+
+ });
+
+ future.get();
+ client.close(CloseMode.GRACEFUL);
+ ```
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-classic.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-classic.md
new file mode 100644
index 0000000..66bdf6b
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/migration-to-classic.md
@@ -0,0 +1,121 @@
+# Migration to Apache HttpClient 5.0 classic APIs
+
+HttpClient 5.0 releases can be co-located with earlier major versions on the same classpath due to versioned package
+namespace and Maven module coordinates.
+
+HttpClient 5.0 classic APIs are largely compatible with HttpClient 4.0 APIs. Major differences are related to connection
+management configuration, SSL/TLS and timeout settings when building HttpClient instances.
+
+## Migration steps
+
+- Add HttpClient 5.0 as a new dependency to the project and optionally remove HttpClient 4.x
+
+- Remove old `org.apache.http` imports and re-import HttpClient classes from
+ `org.apache.hc.httpclient5` package namespace. Most old interfaces and classes should resolve automatically. One
+ notable exception is `HttpEntityEnclosingRequest` interface In HttpClient 5.0 one can enclose a request entity with
+ any HTTP method even if violates semantic of the method.
+
+- There will be compilation errors due to API incompatibilities between version series 4.x and 5.x mostly related to
+ SSL/TLS and timeout settings and `CloseableHttpClient` instance creation. Several modifications are likely to be
+ necessary.
+
+- Use `PoolingHttpClientConnectionManagerBuilder` class to create connection managers with custom parameters
+
+- Use `SSLConnectionSocketFactoryBuilder` class to create SSL connection socket factories with custom parameters
+
+- Explicitly specify TLSv1.2 or TLSv1.3 in order to disable older less versions of the SSL/TLS protocol. Please note
+ all SSL versions are excluded by default.
+
+- Use `Timeout` class to define timeouts.
+
+- Use `TimeValue` class to define time values (duration).
+
+- Optionally choose a connection pool concurrency policy: `STRICT` for strict connection max limit guarantees; `LAX`
+ for higher concurrency but with lax connection maximum limit guarantees. With `LAX` policy HttpClient can exceed the
+ per route maximum limit under high load and does not enforce the total maximum limit.
+
+- Optionally choose a connection pool re-use policy: `FILO` to re-use as few connections as possible making it possible
+ for connections to become idle and expire; `LILO` to re-use all connections equally preventing them from becoming
+ idle and expiring.
+
+ ```java
+ PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
+ .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create()
+ .setSslContext(SSLContexts.createSystemDefault())
+ .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
+ .build())
+ .setDefaultSocketConfig(SocketConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(5))
+ .build())
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
+ .setConnPoolPolicy(PoolReusePolicy.LIFO)
+ .setConnectionTimeToLive(TimeValue.ofMinutes(1L))
+ .build();
+ ```
+
+- Favor `standard-strict` cookie policy when using HttpClient 5.0.
+
+- Use response timeout to define the maximum period of inactivity until receipt of response data.
+
+- All base principles and good practices of HttpClient programing still apply. Always re-use client instances. Client
+ instances are expensive to create and are thread safe in both HttpClient 4.x and 5.0 series.
+
+ ```java
+ CloseableHttpClient client = HttpClients.custom()
+ .setConnectionManager(connectionManager)
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(5))
+ .setResponseTimeout(Timeout.ofSeconds(5))
+ .setCookieSpec(StandardCookieSpec.STRICT)
+ .build())
+ .build();
+
+ CookieStore cookieStore = new BasicCookieStore();
+
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setResponseTimeout(Timeout.ofSeconds(10))
+ .build());
+
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpPost httpPost = new HttpPost("https://httpbin.org/post");
+
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+ httpPost.setEntity(HttpEntities.create(outstream -> {
+ objectMapper.writeValue(outstream, requestData);
+ outstream.flush();
+ }, ContentType.APPLICATION_JSON));
+ ```
+
+- HTTP response messages in HttpClient 5.x no longer have a status line. Use response code directly.
+
+ ```java
+ JsonNode responseData = client.execute(httpPost, response -> {
+ if (response.getCode() >= 300) {
+ throw new ClientProtocolException(new StatusLine(response).toString());
+ }
+ final HttpEntity responseEntity = response.getEntity();
+ if (responseEntity == null) {
+ return null;
+ }
+ try (InputStream inputStream = responseEntity.getContent()) {
+ return objectMapper.readTree(inputStream);
+ }
+ });
+ System.out.println(responseData);
+ ```
+
+- `CloseableHttpClient` instances should be closed when no longer needed or about to go out of score.
+
+ ```java
+ client.close();
+ ```
\ No newline at end of file
diff --git a/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/preparation.md b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/preparation.md
new file mode 100644
index 0000000..ed36ccc
--- /dev/null
+++ b/src/site/markdown/httpcomponents-client-5.0.x/migration-guide/preparation.md
@@ -0,0 +1,113 @@
+# Migration from Apache HttpClient 4.x APIs
+
+It is strongly encouraged to follow the best practices and common use patterns in programming with Apache HttpClient
+4.x. They remain largely unchanged between 4.x and 5.x release series. Correctly written code will be easier to port to
+5.0 APIs and from the classic I/O model to the async I/O model.
+
+## Preparation steps
+
+1. Make sure there are no references to deprecated functions or classes
+
+1. HttpClient uses tries to use sensible defaults but it is generally recommended to adjust SSL/TLS parameters and
+ timeout settings for the specific application context.
+
+1. Explicitly specify TLSv1.2 in order to disable older, less secure versions of the SSL/TLS protocol. Please note
+ HttpClient 4.5 disables all SSL versions by default.
+
+1. Set finite socket and connect timeouts.
+
+1. Set finite connection total time to live (TTL).
+
+1. Favor `standard` and `standard-strict` cookie policies.
+
+1. IMPORTANT: Always re-use `CloseableHttpClient` instances. They are expensive to create, but they are also fully
+ thread safe, so multiple threads can use the same instance of `CloseableHttpClient` to execute multiple requests
+ concurrently taking full advantage of persistent connection re-use and connection pooling.
+
+ ```java
+ CloseableHttpClient client = HttpClients.custom()
+ .setSSLSocketFactory(new SSLConnectionSocketFactory(
+ SSLContexts.createSystemDefault(),
+ new String[] { "TLSv1.2" },
+ null,
+ SSLConnectionSocketFactory.getDefaultHostnameVerifier()))
+ .setConnectionTimeToLive(1, TimeUnit.MINUTES)
+ .setDefaultSocketConfig(SocketConfig.custom()
+ .setSoTimeout(5000)
+ .build())
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(5000)
+ .setSocketTimeout(5000)
+ .setCookieSpec(CookieSpecs.STANDARD_STRICT)
+ .build())
+ .build();
+ ```
+
+1. Cookie store and credentials providers can be shared by multiple execution threads. They can still be shared by
+ multiple message exchnages without being set at
+ `CloseableHttpClient` construction time.
+
+ ```java
+ CookieStore cookieStore = new BasicCookieStore();
+ CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+ ```
+
+1. While `CloseableHttpClient` should have the default configuration applicable to all all messages exchanges one can
+ use `HttpContext` to customize individual request execution parameters.
+
+ ```java
+ HttpClientContext clientContext = HttpClientContext.create();
+ clientContext.setCookieStore(cookieStore);
+ clientContext.setCredentialsProvider(credentialsProvider);
+ clientContext.setRequestConfig(RequestConfig.custom()
+ .setConnectTimeout(10000)
+ .setSocketTimeout(10000)
+ .setCookieSpec(CookieSpecs.STANDARD)
+ .build());
+ ```
+
+1. Always set content type and content encoding on the entity and let HttpClient generate request headers automatically.
+
+ ```java
+ JsonFactory jsonFactory = new JsonFactory();
+ ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
+
+ HttpPost httpPost = new HttpPost("https://httpbin.org/post");
+ List<NameValuePair> requestData = Arrays.asList(
+ new BasicNameValuePair("name1", "value1"),
+ new BasicNameValuePair("name2", "value2"));
+
+ EntityTemplate requestEntity = new EntityTemplate(outstream -> {
+ objectMapper.writeValue(outstream, requestData);
+ outstream.flush();
+
+ });
+ requestEntity.setContentType(ContentType.APPLICATION_JSON.toString());
+ httpPost.setEntity(requestEntity);
+ ```
+
+1. Consume response content directly from the content stream and convert it to a higher level object without converting
+ it to an intermediate string or byte array.
+
+1. Favor HTTP response handlers for response processing, thus making connection release automatic.
+
+ ```java
+ JsonNode responseData = client.execute(httpPost, response -> {
+ if (response.getStatusLine().getStatusCode() >= 300) {
+ throw new ClientProtocolException(Objects.toString(response.getStatusLine()));
+ }
+ final HttpEntity responseEntity = response.getEntity();
+ if (responseEntity == null) {
+ return null;
+ }
+ try (InputStream inputStream = responseEntity.getContent()) {
+ return objectMapper.readTree(inputStream);
+ }
+ });
+ System.out.println(responseData);
+ ```
+1. `CloseableHttpClient` instances should be closed when no longer needed or about to go out of score.
+
+ ```java
+ client.close();
+ ```
diff --git a/src/site/site.xml b/src/site/site.xml
index 8edb441..f40ba3c 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -82,6 +82,13 @@ under the License.
</item>
<item name="HttpClient 5.0" collapse="true" href="httpcomponents-client-5.0.x/index.html">
<item name="Quick Start" href="httpcomponents-client-5.0.x/quickstart.html"/>
+ <item name="Migration Guide" collapse="true" href="httpcomponents-client-5.0.x/migration-guide/index.html">
+ <item name="Preparation" href="httpcomponents-client-5.0.x/migration-guide/preparation.html"/>
+ <item name="Classic" href="httpcomponents-client-5.0.x/migration-guide/migration-to-classic.html"/>
+ <item name="Async Simple" href="httpcomponents-client-5.0.x/migration-guide/migration-to-async-simple.html"/>
+ <item name="Async Streaming" href="httpcomponents-client-5.0.x/migration-guide/migration-to-async-streaming.html"/>
+ <item name="Async HTTP/2 only" href="httpcomponents-client-5.0.x/migration-guide/migration-to-async-http2.html"/>
+ </item>
<item name="Examples (Classic)" href="httpcomponents-client-5.0.x/examples.html"/>
<item name="Examples (Async)" href="httpcomponents-client-5.0.x/examples-async.html"/>
<item name="Examples (Reactive)" href="httpcomponents-client-5.0.x/examples-reactive.html"/>