<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one
  ~ or more contributor license agreements. See the NOTICE file
  ~ distributed with this work for additional information
  ~ regarding copyright ownership. The ASF licenses this file
  ~ to you 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.
  -->

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" version="-//W3C//DTDXHTML1.1//EN">
<head>
  <meta http-equiv="content-type" content=""/>
  <title>HTTP/2 Transport</title>
</head>

<body lang="en">

<a name="H2TransportSender"></a>
<h2>H2TransportSender (HTTP/2 Transport)</h2>

<h3>🚀 TL;DR - Quick Start for Large Payloads (50MB+)</h3>

<p><strong>Most Common Use Case:</strong> Processing 50MB+ JSON payloads with optimal performance</p>

<p><strong>Production Configuration (axis2.xml) - AWS/Cloudflare Ready:</strong></p>
<pre>
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;

   &lt;!-- ALPN Support (Required for AWS ALB, Cloudflare) --&gt;
   &lt;parameter name="alpnProtocols"&gt;h2,http/1.1&lt;/parameter&gt;
   &lt;parameter name="tlsRequired"&gt;true&lt;/parameter&gt;

   &lt;!-- Large Payload Optimization --&gt;
   &lt;parameter name="maxConcurrentStreams"&gt;20&lt;/parameter&gt;
   &lt;parameter name="initialWindowSize"&gt;2097152&lt;/parameter&gt; &lt;!-- 2MB window --&gt;
   &lt;!-- Timeouts --&gt;
   &lt;parameter name="connectionTimeout"&gt;30000&lt;/parameter&gt; &lt;!-- 30s connect --&gt;
   &lt;parameter name="responseTimeout"&gt;300000&lt;/parameter&gt; &lt;!-- 5min response --&gt;

   &lt;!-- HTTP/2 fallback to HTTP/1.1 is automatic via TLS ALPN --&gt;
&lt;/transportSender&gt;
</pre>

<p><strong>Client Access for 50MB JSON Payloads:</strong></p>
<p>Most JSON clients will use <strong>curl</strong> or <strong>Apache HTTP Components</strong> directly:</p>

<pre>
# curl with HTTP/2 for large JSON payloads (AWS/Cloudflare compatible)
curl --http2-prior-knowledge -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "User-Agent: MyApp/1.0" \
  --max-time 300 --connect-timeout 30 \
  --compressed \
  --data @large-payload.json \
  https://server:8443/services/BigDataService

# Apache HTTP Components 5.x (Java clients)
CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
    .setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
    .build();
httpClient.start();

HttpPost request = new HttpPost("https://server:8443/services/BigDataService");
request.setEntity(new StringEntity(jsonPayload, ContentType.APPLICATION_JSON));
</pre>

<p><strong>Expected Performance:</strong> 40-70% faster than HTTP/1.1 for 50MB+ JSON payloads with 20% less memory usage</p>

<p><strong>Note:</strong> Server push is disabled by default as it's not beneficial for JSON APIs
(see "Server Push Capabilities" section below for detailed explanation).</p>

<hr/>

<p>H2TransportSender provides enterprise-grade HTTP/2 transport capabilities using HttpClient 5.x
with advanced features for large payload processing, connection multiplexing, and performance optimization.
This transport is specifically designed for big data applications requiring 50MB+ JSON payload support
with memory-efficient 64 KB flush intervals.</p>

<p>HTTP/2 offers significant advantages over HTTP/1.1:</p>
<ul>
  <li>Binary protocol with header compression (HPACK)</li>
  <li>Stream multiplexing - multiple concurrent requests over single connection</li>
  <li>Server push capabilities (configurable)</li>
  <li>Improved flow control with window scaling</li>
  <li>Enhanced performance for large payloads</li>
  <li>Reduced connection overhead and latency</li>
</ul>

<h3>Basic HTTP/2 Configuration</h3>

<p>The &lt;transportSender/&gt; element for HTTP/2 transport:</p>
<pre>
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;
   &lt;parameter name="maxConcurrentStreams"&gt;100&lt;/parameter&gt;
   &lt;parameter name="initialWindowSize"&gt;2097152&lt;/parameter&gt; &lt;!-- 2MB -- see note below --&gt;
   &lt;parameter name="serverPushEnabled"&gt;false&lt;/parameter&gt;
   &lt;parameter name="memoryOptimized"&gt;true&lt;/parameter&gt;
&lt;/transportSender&gt;
</pre>

<div style="background-color: #fff8e1; border: 1px solid #f9a825; padding: 15px; margin: 15px 0;">
<h4>Flow-control window vs. streaming flush interval</h4>
<p><code>initialWindowSize</code> and the <code>FlushingOutputStream</code>
64 KB flush interval are <strong>independent settings that should not be
"aligned"</strong> to the same value.</p>
<ul>
  <li><strong>FlushingOutputStream flush (server-side, 64 KB)</strong> —
      controls when serialized bytes are pushed into the HTTP/2 framing
      layer. 64 KB is a good cadence: it gives early time-to-first-byte
      and prevents reverse proxy timeouts on long-running serializations.
      This value is correct and should not change.</li>
  <li><strong>initialWindowSize (client-side, per-stream)</strong> —
      controls how much data a stream may have in-flight before the
      sender pauses for a WINDOW_UPDATE acknowledgement from the
      receiver. A 10 MB response with a 64 KB window requires ~156
      WINDOW_UPDATE round-trips; with a 2 MB window it requires ~5.
      Under concurrent load, these round-trips serialize on each TCP
      connection, adding significant latency.</li>
</ul>
<p>A server flushing at 64 KB works well with a client whose
window is 2 MB — the server sends 64 KB, the framing layer
accumulates up to 2 MB of in-flight data, and the client
acknowledges in bulk. Setting both to 64 KB forces the client to
acknowledge every single flush, converting each 64 KB chunk into a
synchronous round-trip.</p>
</div>

<h3>HTTP/2 Configuration Parameters</h3>

<table border="1">
<tr><th>Parameter</th><th>Description</th><th>Default</th><th>Range</th></tr>
<tr><td>maxConcurrentStreams</td><td>Maximum concurrent streams per connection. Lower values (4-8) force the connection pool to spread streams across multiple TCP connections — better for workloads with few concurrent large payloads. Higher values (50-100) maximize multiplexing efficiency for many small concurrent requests.</td><td>100</td><td>1-1000</td></tr>
<tr><td>initialWindowSize</td><td>HTTP/2 per-stream flow-control window (bytes). Determines how much data can be in-flight per stream before the sender waits for a WINDOW_UPDATE. For payloads above 1 MB, use at least 1-2 MB to avoid excessive round-trips. Not related to the server-side FlushingOutputStream 64 KB flush interval.</td><td>2097152</td><td>64KB-16MB</td></tr>
<tr><td>streamingBufferSize</td><td>Buffer size for streaming flush interval</td><td>65536</td><td>8KB-1MB</td></tr>
<tr><td>connectionTimeout</td><td>Connection establishment timeout (ms)</td><td>30000</td><td>1000-60000</td></tr>
<tr><td>responseTimeout</td><td>Response timeout for large payloads (ms)</td><td>300000</td><td>30000-600000</td></tr>
</table>

<h3>Tuning for Different Workloads</h3>

<p>The optimal <code>maxConcurrentStreams</code> and
<code>initialWindowSize</code> depend on your traffic pattern. With
Apache HttpComponents 5.x, the <code>PoolingAsyncClientConnectionManager</code>
only opens a new TCP connection when all existing connections have reached
their <code>maxConcurrentStreams</code> limit. If this value is higher
than your typical concurrency, the pool will multiplex all streams onto a
single connection — which is efficient for many small requests but creates
flow-control contention for concurrent large payloads.</p>

<table border="1">
<tr><th>Workload</th><th>Example</th><th>maxConcurrentStreams</th><th>initialWindowSize</th><th>maxConnPerRoute</th></tr>
<tr><td>Many small concurrent requests</td><td>Microservice mesh, API gateway</td><td>50-100</td><td>2 MB</td><td>10</td></tr>
<tr><td>Few large concurrent payloads</td><td>Batch processing, ETL, report generation</td><td>4-8</td><td>8 MB</td><td>16-32</td></tr>
<tr><td>Mixed traffic</td><td>General-purpose service client</td><td>8-16</td><td>2 MB</td><td>16</td></tr>
</table>

<h4>Client-side vs. server-side window: where tuning matters</h4>

<p>HTTP/2 flow control is bidirectional — both client and server
advertise an <code>initialWindowSize</code>. For typical Axis2
deployments where the server produces large JSON responses and the
client sends smaller requests (query parameters, filter criteria),
the <strong>client-side window is the critical tuning point</strong>.
It governs how much response data the server can push before pausing
for a WINDOW_UPDATE from the client. A 64 KB client window on a
10 MB response means ~156 pause-and-acknowledge cycles.</p>

<p>The server's inbound window (configured in the application server —
e.g., WildFly's <code>http2-initial-window-size</code>, Tomcat's
<code>http2InitialWindowSize</code>) controls how much
<em>request</em> data the server allows in-flight. Since requests
are typically small relative to responses, the server-side default
(64 KB per the HTTP/2 spec) is usually adequate. Focus tuning effort
on the <code>H2TransportSender</code> client-side
<code>initialWindowSize</code> shown above.</p>

<p>If a single client consumes both small and large payload endpoints on
different hosts, consider configuring separate
<code>CloseableHttpAsyncClient</code> instances with per-workload tuning.
The connection pool's <code>maxConnPerRoute</code> already isolates
traffic by host, but <code>maxConcurrentStreams</code> and
<code>initialWindowSize</code> apply to the entire client.</p>

<h3>Enterprise Big Data Configuration</h3>

<p>For enterprise applications processing large JSON datasets (50MB+), use the following optimized configuration.
Note the lower <code>maxConcurrentStreams</code> (forces the pool to open multiple TCP connections under concurrent
load) and larger <code>initialWindowSize</code> (eliminates per-stream flow-control round-trips):</p>
<pre>
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;

   &lt;!-- Stream Management: low stream count forces connection pooling
        instead of multiplexing all large payloads onto one TCP connection --&gt;
   &lt;parameter name="maxConcurrentStreams"&gt;4&lt;/parameter&gt;
   &lt;parameter name="initialWindowSize"&gt;8388608&lt;/parameter&gt; &lt;!-- 8MB -- a 50MB payload completes in ~6 window updates --&gt;
   &lt;parameter name="maxFrameSize"&gt;32768&lt;/parameter&gt;

   &lt;!-- Large Payload Optimization --&gt;
   &lt;parameter name="streamingBufferSize"&gt;65536&lt;/parameter&gt;
   &lt;parameter name="memoryOptimized"&gt;true&lt;/parameter&gt;

   &lt;!-- Connection Management: sized for concurrent large-payload fan-out --&gt;
   &lt;parameter name="maxConnTotal"&gt;64&lt;/parameter&gt;
   &lt;parameter name="maxConnPerRoute"&gt;32&lt;/parameter&gt;

   &lt;!-- Timeouts for Large Payloads --&gt;
   &lt;parameter name="connectionTimeout"&gt;30000&lt;/parameter&gt;
   &lt;parameter name="responseTimeout"&gt;300000&lt;/parameter&gt;
&lt;/transportSender&gt;
</pre>

<h3>HTTPS with HTTP/2 (ALPN)</h3>

<p>HTTP/2 over HTTPS requires Application-Layer Protocol Negotiation (ALPN). The H2TransportSender
automatically handles ALPN negotiation when used with HTTPS endpoints:</p>

<pre>
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;
   &lt;parameter name="tlsRequired"&gt;true&lt;/parameter&gt;
   &lt;parameter name="alpnProtocols"&gt;h2,http/1.1&lt;/parameter&gt;
&lt;/transportSender&gt;
</pre>

<h3>Stream Multiplexing Configuration</h3>

<p>HTTP/2 stream multiplexing allows multiple concurrent requests over a single connection,
significantly improving performance for concurrent operations:</p>

<pre>
// Enable HTTP/2 multiplexing in client code
Options options = new Options();
options.setProperty(HTTPConstants.TRANSPORT_NAME, "h2");
// HTTP/2 multiplexing is automatic when using the h2 transport.
// No additional boolean flags are needed.
</pre>

<h3>Large Payload Processing</h3>

<p>The H2TransportSender provides three processing modes optimized for different payload sizes:</p>

<ul>
  <li><strong>Standard Processing</strong> (0MB-10MB): Regular HTTP/2 features</li>
  <li><strong>Multiplexing Mode</strong> (10-50MB): Enhanced concurrent processing</li>
  <li><strong>Streaming Mode</strong> (50MB+): Memory-efficient streaming with chunked processing</li>
</ul>

<p>Streaming and memory optimization are controlled by the message formatter
selected in axis2.xml (e.g. <code>MoshiStreamingMessageFormatter</code>).
No client-side <code>Options</code> properties are required — the transport
sender negotiates HTTP/2 framing and flow control automatically.</p>

<h3>Performance Monitoring</h3>

<p>For production monitoring, use Micrometer with Prometheus/Grafana or
Spring Boot Actuator endpoints.  Application-level logging via the
Axis2 log configuration provides per-request timing details.</p>

<p>Available metrics include:</p>
<ul>
  <li>Stream allocation and utilization</li>
  <li>Memory usage and buffer efficiency</li>
  <li>Processing time and throughput</li>
  <li>Compression ratios and bandwidth savings</li>
  <li>Connection reuse statistics</li>
</ul>

<h3>Flow Control</h3>

<p>HTTP/2 flow control is handled automatically by the transport layer.
The <code>initialWindowSize</code> parameter on the transport sender controls
the initial flow-control window; beyond that, the HTTP/2 implementation
manages window updates and back-pressure without additional configuration.</p>

<h3>Compression</h3>

<p>Response compression is handled by the servlet container (Tomcat, WildFly, etc.),
not by the Axis2 transport. Configure compression in your container's server
configuration (e.g., Tomcat's <code>server.xml</code> <code>compression</code>
attribute, or WildFly's Undertow content-encoding filter). HTTP/2 header
compression (HPACK) is always active and requires no Axis2 configuration.</p>

<h3>Memory Management</h3>

<p>Buffer management is handled internally by Apache HttpComponents 5.x.
The JVM's default direct memory limit (equal to <code>-Xmx</code>) is
sufficient for most deployments. No additional JVM flags are needed
for HTTP/2 buffer management.</p>

<h3>Error Handling and Fallback</h3>

<p>When the remote server does not support HTTP/2, the TLS ALPN negotiation
falls back to HTTP/1.1 automatically. No explicit fallback parameters are
required — Apache HttpComponents handles protocol negotiation.</p>

<h3>Server Push</h3>

<p>Server push is <strong>disabled by default</strong> — REST/JSON APIs follow
request-response patterns where push provides no benefit. Enable only
for web-app use cases with predictable resource dependencies:</p>
<pre>
&lt;parameter name="serverPushEnabled"&gt;false&lt;/parameter&gt; &lt;!-- default --&gt;
</pre>

<h3>Service-Level HTTP/2 Configuration</h3>

<p>Individual services can specify HTTP/2 preferences in their services.xml:</p>

<p>HTTP/2 is enabled at the transport level in axis2.xml, not per-service.
Select the H2TransportSender in the <code>&lt;transportSender&gt;</code> section
and configure its parameters there.  For streaming large payloads, use the
streaming message formatter (e.g. <code>MoshiStreamingMessageFormatter</code>
or <code>JSONStreamingMessageFormatter</code>) in the service's message
receiver configuration.  No service-level parameters are required.</p>

<h3>Client-Side HTTP/2 Usage for SOAP (for JSON, see curl and Apache HTTPComponents section)</h3>

<p>Complete client configuration example:</p>

<pre>
// Create HTTP/2 enabled service client
ConfigurationContext configContext = ConfigurationContextFactory
        .createConfigurationContextFromFileSystem(null, null);

ServiceClient serviceClient = new ServiceClient(configContext, null);

// Configure HTTP/2 transport
Options options = new Options();
options.setProperty(HTTPConstants.TRANSPORT_NAME, "h2");
options.setTo(new EndpointReference("https://localhost:8443/services/BigDataService"));

// HTTP/2 is negotiated by the transport sender selected in axis2.xml.
// No additional boolean flags are needed — the h2 transport handles
// multiplexing, streaming, and flow control automatically.

// Timeout settings for large payloads
options.setTimeOutInMilliSeconds(300000); // 5 minutes
options.setProperty(HTTPConstants.CONNECTION_TIMEOUT, 30000);
options.setProperty(HTTPConstants.SO_TIMEOUT, 300000);

serviceClient.setOptions(options);
</pre>

<h3>Performance Comparison: HTTP/1.1 vs HTTP/2</h3>

<p>HTTP/2 transport can provide substantial improvements over HTTP/1.1.
The following are illustrative estimates — actual results depend on payload size,
network conditions, and JVM configuration:</p>

<table border="1">
<tr><th>Metric</th><th>HTTP/1.1</th><th>HTTP/2</th><th>Improvement</th></tr>
<tr><td>Connection Multiplexing</td><td>6-8 connections</td><td>100 concurrent streams</td><td>1,150-1,567%</td></tr>
<tr><td>Memory Efficiency</td><td>Standard allocation</td><td>Pooled buffers</td><td>30-50%</td></tr>
<tr><td>Large Payload (50MB)</td><td>Baseline</td><td>Streaming optimization</td><td>50-200%</td></tr>
<tr><td>Compression</td><td>Basic gzip</td><td>JSON-aware optimization</td><td>50-70%</td></tr>
<tr><td>Overall Throughput</td><td>Baseline</td><td>Combined optimizations</td><td>70-150%</td></tr>
</table>

<h3>Troubleshooting HTTP/2</h3>

<p>Common HTTP/2 configuration issues and solutions:</p>

<h4>ALPN Not Available</h4>
<pre>
// Ensure ALPN support is available
System.setProperty("java.security.properties", "jdk.tls.alpnCharset=UTF-8");
</pre>

<h4>Memory Issues with Large Payloads</h4>
<pre>
// Increase heap size for large JSON payloads
-Xmx4g -XX:+UseG1GC
</pre>

<h4>Connection Issues</h4>
<p>HTTP/2 fallback to HTTP/1.1 is automatic via TLS ALPN negotiation.
If the server does not advertise h2, the client falls back transparently.
Increase <code>connectionTimeout</code> on the transport sender if ALPN
negotiation is slow on your network.</p>

<h3>Migration from HTTP/1.1 to HTTP/2</h3>

<p>To migrate existing HTTP/1.1 configurations to HTTP/2:</p>

<ol>
  <li>Change transport sender class to H2TransportSender</li>
  <li>Update protocol parameter to HTTP/2.0</li>
  <li>Add HTTP/2 specific parameters</li>
  <li>Configure HTTPS with ALPN support</li>
  <li>Test with fallback enabled</li>
</ol>

<p>Example migration:</p>
<pre>
&lt;!-- HTTP/1.1 Configuration --&gt;
&lt;transportSender name="http" class="org.apache.axis2.transport.http.impl.httpclient5.HTTPClient5TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/1.1&lt;/parameter&gt;
   &lt;parameter name="Transfer-Encoding"&gt;chunked&lt;/parameter&gt;
&lt;/transportSender&gt;

&lt;!-- HTTP/2 Configuration --&gt;
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;
   &lt;parameter name="maxConcurrentStreams"&gt;100&lt;/parameter&gt;
   &lt;parameter name="initialWindowSize"&gt;2097152&lt;/parameter&gt;
   &lt;!-- Fallback to HTTP/1.1 is automatic via TLS ALPN negotiation --&gt;
&lt;/transportSender&gt;
</pre>

<h3>SSL Client Authentication (2-Way SSL) with HTTP/2</h3>

<p>HTTP/2 transport supports SSL client authentication (mutual TLS) similar to HTTP/1.1, with enhanced
features for certificate management and ALPN negotiation. You can configure your own HttpAsyncClient
with custom SSL context and certificate handling.</p>

<p>The HTTP/2 transport supports the same certificate management as HTTP/1.1 but uses async client
architecture. To control max connections per host, SSL configuration, or other advanced parameters,
set the cached HTTP/2 client using the CACHED_HTTP2_ASYNC_CLIENT property before making requests.</p>

<p>The following example shows SSL client authentication configuration tested with Axis2 on WildFly 32:</p>

<pre>
        // Certificate and TrustStore setup (same as HTTP/1.1)
        String wildflyserver_cert_path = "src/wildflyserver.crt";
        Certificate certificate = CertificateFactory.getInstance("X.509")
                .generateCertificate(new FileInputStream(new File(wildflyserver_cert_path)));
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("server", certificate);

        TrustManagerFactory trustManagerFactory = null;
        trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new Exception("Unexpected default trust managers:" + Arrays.toString(trustManagers));
        }

        // SSL Context with TLS 1.3 support for HTTP/2
        SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
        sslContext.init(null, trustManagers, new SecureRandom());

        // HTTP/2 specific TLS strategy with ALPN support
        TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
                .setSslContext(sslContext)
                .setHostnameVerifier(NoopHostnameVerifier.INSTANCE) // For self-signed certificates
                .setTlsDetailsFactory(sslEngine -&gt; {
                    // Configure ALPN protocols for HTTP/2 negotiation
                    SSLParameters sslParams = sslEngine.getSSLParameters();
                    sslParams.setApplicationProtocols(new String[]{"h2", "http/1.1"});
                    sslEngine.setSSLParameters(sslParams);
                    return null;
                })
                .build();

        // HTTP/2 async connection manager with SSL configuration
        PoolingAsyncClientConnectionManager connManager = PoolingAsyncClientConnectionManagerBuilder.create()
                .setTlsStrategy(tlsStrategy)
                .setMaxConnTotal(100)
                .setMaxConnPerRoute(100)
                .build();

        // Create HTTP/2 async client with SSL configuration
        CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()
                .setConnectionManager(connManager)
                .setConnectionManagerShared(true)
                .setVersionPolicy(HttpVersionPolicy.NEGOTIATE) // Allow HTTP/2 negotiation
                .build();

        httpAsyncClient.start(); // Important: Start the async client

        // Configure service client with HTTP/2 SSL client
        Options options = new Options();
        options.setTo(new EndpointReference("https://myserver:8443/services/MyService"));
        options.setProperty(HTTPConstants.TRANSPORT_NAME, "h2"); // Use HTTP/2 transport
        options.setTimeOutInMilliSeconds(120000);

        // Set the cached HTTP/2 async client (HTTP/2 equivalent of CACHED_HTTP_CLIENT)
        options.setProperty("CACHED_HTTP2_ASYNC_CLIENT", httpAsyncClient);

        ServiceClient sender = new ServiceClient();
        sender.setOptions(options);
</pre>

<h3>HTTP/2 SSL Configuration Parameters</h3>

<p>The HTTP/2 transport provides additional SSL-specific parameters:</p>

<table border="1">
<tr><th>Parameter</th><th>Description</th><th>Default</th><th>HTTP/1.1 Equivalent</th></tr>
<tr><td>CACHED_HTTP2_ASYNC_CLIENT</td><td>Custom HTTP/2 async client with SSL config</td><td>None</td><td>CACHED_HTTP_CLIENT</td></tr>
<tr><td>tlsRequired</td><td>Enforce HTTPS-only for HTTP/2</td><td>true</td><td>N/A</td></tr>
<tr><td>alpnProtocols</td><td>ALPN protocol preferences</td><td>h2,http/1.1</td><td>N/A</td></tr>
<tr><td>supportedTLSVersions</td><td>Supported TLS versions</td><td>TLSv1.2,TLSv1.3</td><td>Similar</td></tr>
<tr><td>cipherSuites</td><td>Allowed cipher suites</td><td>TLS 1.3 defaults</td><td>Similar</td></tr>
</table>

<h3>Advanced SSL Configuration for HTTP/2</h3>

<p>For enterprise deployments requiring specific SSL configurations:</p>

<pre>
&lt;transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"&gt;
   &lt;parameter name="PROTOCOL"&gt;HTTP/2.0&lt;/parameter&gt;

   &lt;!-- SSL/TLS Configuration --&gt;
   &lt;parameter name="tlsRequired"&gt;true&lt;/parameter&gt;
   &lt;parameter name="supportedTLSVersions"&gt;TLSv1.2,TLSv1.3&lt;/parameter&gt;
   &lt;parameter name="alpnProtocols"&gt;h2,http/1.1&lt;/parameter&gt;

   &lt;!-- ALPN Configuration --&gt;
   &lt;parameter name="alpnTimeout"&gt;5000&lt;/parameter&gt;
   &lt;parameter name="alpnFallbackEnabled"&gt;true&lt;/parameter&gt;

   &lt;!-- Certificate Validation --&gt;
   &lt;parameter name="hostnameVerification"&gt;strict&lt;/parameter&gt;
   &lt;parameter name="certificateValidation"&gt;strict&lt;/parameter&gt;
&lt;/transportSender&gt;
</pre>

<h3>Client Certificate Authentication</h3>

<p>For mutual TLS (client certificate authentication) with HTTP/2:</p>

<pre>
        // Load client certificate and private key
        KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
        clientKeyStore.load(new FileInputStream("client-cert.p12"), "password".toCharArray());

        KeyManagerFactory keyManagerFactory = KeyManagerFactory
                .getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(clientKeyStore, "password".toCharArray());

        // SSL Context with client certificate
        SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom());

        // Configure HTTP/2 client with client certificate authentication
        TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
                .setSslContext(sslContext)
                .setTlsDetailsFactory(sslEngine -&gt; {
                    SSLParameters sslParams = sslEngine.getSSLParameters();
                    sslParams.setApplicationProtocols(new String[]{"h2", "http/1.1"});
                    sslParams.setNeedClientAuth(true); // Require client authentication
                    sslEngine.setSSLParameters(sslParams);
                    return null;
                })
                .build();
</pre>

<h3>HTTP/2 vs HTTP/1.1 SSL Differences</h3>

<p>Key differences in SSL handling between HTTP/1.1 and HTTP/2:</p>

<ul>
  <li><strong>ALPN Support</strong>: HTTP/2 requires ALPN negotiation for protocol selection</li>
  <li><strong>TLS Version</strong>: HTTP/2 requires TLS 1.2 or higher (TLS 1.3 recommended)</li>
  <li><strong>Cipher Suites</strong>: HTTP/2 has specific cipher suite requirements (RFC 7540)</li>
  <li><strong>Async Architecture</strong>: Uses CloseableHttpAsyncClient instead of CloseableHttpClient</li>
  <li><strong>Connection Multiplexing</strong>: Single SSL connection handles multiple streams</li>
  <li><strong>Fallback Handling</strong>: Automatic fallback to HTTP/1.1 if HTTP/2 negotiation fails</li>
</ul>

<h3>SSL Notes</h3>

<p>HTTP/2 requires TLS 1.2+ with ALPN. Use OpenJDK 11+ (ALPN built in).
If ALPN negotiation fails, the transport falls back to HTTP/1.1
automatically (no configuration flag required).</p>

</body>
</html>
