HttpClient 5.x migration guide
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 @@
       </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"/>