You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2021/10/30 15:29:00 UTC

[cxf] branch master updated: CXF-8605: Introduce HTTP/2 Transport: server-side support (#861)

This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/master by this push:
     new 965e1bb  CXF-8605: Introduce HTTP/2 Transport: server-side support (#861)
965e1bb is described below

commit 965e1bb9e9658f4024f33bf832308f8b8dfce4b6
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Sat Oct 30 11:28:48 2021 -0400

    CXF-8605: Introduce HTTP/2 Transport: server-side support (#861)
---
 .../samples/jax_rs/basic_http2_jetty/README.txt    |  92 +++++
 .../samples/jax_rs/basic_http2_jetty/pom.xml       | 136 +++++++
 .../src/main/config/KeyREADME.txt                  |   8 +
 .../src/main/config/serviceKeystore.jks            | Bin 0 -> 3743 bytes
 .../src/main/java/http2demo/common/Customer.java   |  43 +++
 .../java/http2demo/common/CustomerService.java     |  52 +++
 .../java/http2demo/server/CustomerServiceImpl.java |  89 +++++
 .../src/main/java/http2demo/server/h2/Server.java  |  59 +++
 .../src/main/java/http2demo/server/h2c/Server.java |  59 +++
 .../src/main/resources/ServerConfig.xml            |  48 +++
 .../samples/jax_rs/basic_http2_netty/README.txt    |  92 +++++
 .../samples/jax_rs/basic_http2_netty/pom.xml       | 100 +++++
 .../src/main/config/KeyREADME.txt                  |   8 +
 .../src/main/config/serviceKeystore.jks            | Bin 0 -> 3742 bytes
 .../src/main/java/http2demo/common/Customer.java   |  43 +++
 .../java/http2demo/common/CustomerService.java     |  52 +++
 .../java/http2demo/server/CustomerServiceImpl.java |  89 +++++
 .../src/main/java/http2demo/server/h2/Server.java  |  59 +++
 .../src/main/java/http2demo/server/h2c/Server.java |  59 +++
 .../src/main/resources/ServerConfig.xml            |  48 +++
 .../samples/jax_rs/basic_http2_undertow/README.txt |  93 +++++
 .../samples/jax_rs/basic_http2_undertow/pom.xml    |  95 +++++
 .../src/main/config/KeyREADME.txt                  |   8 +
 .../src/main/config/serviceKeystore.jks            | Bin 0 -> 3742 bytes
 .../src/main/java/http2demo/common/Customer.java   |  43 +++
 .../java/http2demo/common/CustomerService.java     |  52 +++
 .../java/http2demo/server/CustomerServiceImpl.java |  89 +++++
 .../src/main/java/http2demo/server/h2/Server.java  |  59 +++
 .../src/main/java/http2demo/server/h2c/Server.java |  59 +++
 .../src/main/resources/ServerConfig.xml            |  48 +++
 distribution/src/main/release/samples/pom.xml      |   8 +-
 parent/pom.xml                                     |  10 +
 rt/transports/http-jetty/pom.xml                   |  10 +
 .../http_jetty/JettyHTTPServerEngine.java          |  42 ++-
 rt/transports/http-netty/netty-server/pom.xml      |   6 +
 .../http/netty/server/NettyHttpServerEngine.java   |  27 +-
 .../netty/server/NettyHttpServerEngineFactory.java |   2 +-
 .../server/NettyHttpServletPipelineFactory.java    | 230 +++++++++++-
 .../NettyHttpServerEngineBeanDefinitionParser.java |  14 +-
 .../http_undertow/UndertowHTTPServerEngine.java    |  32 +-
 .../transport/http/HttpServerEngineSupport.java    |  47 +++
 .../transport/https/SSLContextInitParameters.java  |  44 +++
 .../org/apache/cxf/transport/https/SSLUtils.java   |  34 +-
 systests/pom.xml                                   |   1 +
 systests/{transports => transport-netty}/pom.xml   | 207 ++---------
 .../http2/netty/AbstractBookServerHttp2.java       |  64 ++++
 .../netty/AbstractNettyClientServerHttp2Test.java  | 118 ++++++
 .../org/apache/cxf/systest/http2/netty/Book.java   |  69 ++++
 .../cxf/systest/http2/netty/BookServerHttp2.java   |  47 +++
 .../cxf/systest/http2/netty/BookServerHttp2c.java  |  45 +++
 .../apache/cxf/systest/http2/netty/BookStore.java  |  68 ++++
 .../cxf/systest/http2/netty/Http2TestClient.java   | 401 +++++++++++++++++++++
 .../http2/netty/NettyClientServerHttp2Test.java    |  48 +++
 .../http2/netty/NettyClientServerHttp2cTest.java   |  47 +++
 .../apache/cxf/systest/http2_netty/server-tls.xml  |  41 +++
 .../org/apache/cxf/systest/http2_netty/server.xml  |  32 ++
 .../http2/AbstractBookServerHttp2.java             |  66 ++++
 .../AbstractUndertowClientServerHttp2Test.java     | 120 ++++++
 .../http_undertow/http2/BookServerHttp2.java       |  45 +++
 .../http_undertow/http2/BookServerHttp2c.java      |  45 +++
 .../http_undertow/http2/Http2TestClient.java       | 184 ++++++++++
 .../http2/UndertowClientServerHttp2Test.java       |  48 +++
 .../http2/UndertowClientServerHttp2cTest.java      |  48 +++
 .../cxf/systest/http_undertow/http2/server-tls.xml |  41 +++
 .../cxf/systest/http_undertow/http2/server.xml     |  32 ++
 systests/transports/pom.xml                        |  56 +++
 .../http2_jetty/AbstractBookServerHttp2.java       |  64 ++++
 .../AbstractJettyClientServerHttp2Test.java        | 119 ++++++
 .../org/apache/cxf/systest/http2_jetty/Book.java   |  69 ++++
 .../cxf/systest/http2_jetty/BookServerHttp2.java   |  47 +++
 .../cxf/systest/http2_jetty/BookServerHttp2c.java  |  45 +++
 .../apache/cxf/systest/http2_jetty/BookStore.java  |  68 ++++
 .../cxf/systest/http2_jetty/Http2TestClient.java   | 212 +++++++++++
 .../http2_jetty/JettyClientServerHttp2Test.java    |  48 +++
 .../http2_jetty/JettyClientServerHttp2cTest.java   |  47 +++
 .../apache/cxf/systest/http2_jetty/server-tls.xml  |  41 +++
 .../org/apache/cxf/systest/http2_jetty/server.xml  |  32 ++
 77 files changed, 4610 insertions(+), 243 deletions(-)

diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/README.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/README.txt
new file mode 100644
index 0000000..df1bc1f
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/README.txt
@@ -0,0 +1,92 @@
+JAX-RS Basic Demo With HTTPS communications
+===========================================
+
+This demo takes the JAX-RS basic demo a step further 
+by doing the communication using HTTP/2 over TLS and
+HTTP/2 over cleartext using Jetty container.
+
+Building and running the demo using Maven
+-----------------------------------------
+From the base directory of this sample (i.e., where this README file is
+located), the Maven pom.xml file can be used to build and run the demo. 
+
+Using either UNIX or Windows:
+
+  mvn install
+  mvn -Ph2-server  (HTTP/2 over TLS)
+  mvn -Ph2c-server  (HTTP/2 over cleartext)
+    
+To remove the target dir, run "mvn clean".
+
+Certificates
+------------
+See the src/main/config folder for the sample keys used (don't use
+these keys in production!) as well as scripts used for their creation.
+
+HTTP/2 over cleartext
+------------
+
+- Upgrade from HTTP/1.1 to HTTP/2 (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2 -i
+  
+    HTTP/1.1 101 Switching Protocols
+    HTTP/2 200
+    server: Jetty(9.4.44.v20210927)
+    date: Thu, 14 Oct 2021 01:35:58 GMT
+    content-type: application/xml
+    content-length: 105
+ 
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
+- Use HTTP/2 prior knowledge (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2-prior-knowledge -i
+  
+    HTTP/2 200
+    server: Jetty(9.4.44.v20210927)
+    date: Thu, 14 Oct 2021 01:36:44 GMT
+    content-type: application/xml
+    content-length: 105
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http1.1 -i
+  
+    HTTP/1.1 200 OK
+    Date: Thu, 14 Oct 2021 01:37:06 GMT
+    Content-Type: application/xml
+    Content-Length: 105
+    Server: Jetty(9.4.44.v20210927)
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+    
+HTTP/2 over TLS
+------------
+
+- Use HTTP/2
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http2 -ik
+  
+    HTTP/2 200
+    server: Jetty(9.4.44.v20210927)
+    date: Thu, 14 Oct 2021 01:25:26 GMT
+    content-type: application/xml
+    content-length: 105
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http1.1 -ik
+  
+    HTTP/1.1 200 OK
+    Date: Thu, 14 Oct 2021 01:26:06 GMT
+    Content-Type: application/xml
+    Content-Length: 105
+    Server: Jetty(9.4.44.v20210927)
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/pom.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/pom.xml
new file mode 100644
index 0000000..f93cdf2
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/pom.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jax_rs_basic_http2_jetty</artifactId>
+    <name>JAX-RS Basic Demo With HTTP/2 communications</name>
+    <description>JAX-RS Basic Demo With HTTP/2 communications</description>
+    <parent>
+        <groupId>org.apache.cxf.samples</groupId>
+        <artifactId>cxf-samples</artifactId>
+        <version>3.5.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <profiles>
+        <profile>
+            <id>h2-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>h2c-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2c.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http-jetty</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <version>${cxf.jetty9.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <version>${cxf.jetty9.version}</version>
+        </dependency>
+    </dependencies>
+    
+    <profiles>
+        <profile>
+            <id>jdk8</id>
+            <activation>
+                <jdk>1.8</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-openjdk8-server</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>jdk9+</id>
+            <activation>
+                <jdk>[9,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-java-server</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+    </profiles>
+</project>
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/KeyREADME.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/KeyREADME.txt
new file mode 100644
index 0000000..97f20fa
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/KeyREADME.txt
@@ -0,0 +1,8 @@
+# The below scripts show the commands used to generate the self-signed keys for this sample.
+# If you use the below script to create your own keys be sure to change the passwords used here
+# DO NOT USE THE SUPPLIED KEYS IN PRODUCTION--everyone has them!!
+# For production recommended to use keys signed by a third-party certificate authority (CA)
+
+# Create the combination keystore/truststore for the server.
+keytool -genkeypair -keyalg RSA -keysize 4096 -validity 730 -alias myservicekey -keystore serviceKeystore.jks -dname "cn=localhost" -keypass skpass -storepass sspass
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/serviceKeystore.jks b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/serviceKeystore.jks
new file mode 100644
index 0000000..7801717
Binary files /dev/null and b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/config/serviceKeystore.jks differ
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/Customer.java b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/Customer.java
new file mode 100644
index 0000000..81ce3c5
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/Customer.java
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Customer")
+public class Customer {
+    private long id;
+    private String name;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/CustomerService.java b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/CustomerService.java
new file mode 100644
index 0000000..890ade3
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/common/CustomerService.java
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+
+/**
+ * This interface describes a JAX-RS root resource. All the JAXRS annotations (except those overridden) will
+ * be inherited by classes implementing it.
+ */
+@Path("/customerservice/")
+public interface CustomerService {
+
+    @GET
+    @Path("/customers/{id}/")
+    Customer getCustomer(@PathParam("id") String id);
+
+    @PUT
+    @Path("/customers/")
+    Response updateCustomer(Customer customer);
+
+    @POST
+    @Path("/customers/")
+    Response addCustomer(Customer customer);
+
+    @DELETE
+    @Path("/customers/{id}/")
+    Response deleteCustomer(@PathParam("id") String id);
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/CustomerServiceImpl.java b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/CustomerServiceImpl.java
new file mode 100644
index 0000000..171d27b
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/CustomerServiceImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.
+ */
+package http2demo.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import http2demo.common.Customer;
+import http2demo.common.CustomerService;
+
+public class CustomerServiceImpl implements CustomerService {
+    long currentId = 123;
+    Map<Long, Customer> customers = new HashMap<>();
+
+    public CustomerServiceImpl() {
+        init();
+    }
+
+    public Customer getCustomer(String id) {
+        System.out.println("----invoking getCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        return customers.get(idNumber);
+    }
+
+    public Response updateCustomer(Customer customer) {
+        System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
+        Customer c = customers.get(customer.getId());
+        Response r;
+        if (c != null) {
+            customers.put(customer.getId(), customer);
+            r = Response.ok().build();
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    public Response addCustomer(Customer customer) {
+        System.out.println("----invoking addCustomer, Customer name is: " + customer.getName());
+        customer.setId(++currentId);
+
+        customers.put(customer.getId(), customer);
+
+        return Response.ok(customer).build();
+    }
+
+    public Response deleteCustomer(String id) {
+        System.out.println("----invoking deleteCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        Customer c = customers.get(idNumber);
+
+        Response r;
+        if (c != null) {
+            r = Response.ok().build();
+            customers.remove(idNumber);
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    final void init() {
+        Customer c = new Customer();
+        c.setName("John");
+        c.setId(123);
+        customers.put(c.getId(), c);
+    }
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2/Server.java
new file mode 100644
index 0000000..d821996
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus("ServerConfig.xml");
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("https://localhost:9000/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2c/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2c/Server.java
new file mode 100644
index 0000000..d86ef95
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/java/http2demo/server/h2c/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2c;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus();
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("http://localhost:9001/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/resources/ServerConfig.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/resources/ServerConfig.xml
new file mode 100644
index 0000000..6ef1e90
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_jetty/src/main/resources/ServerConfig.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!-- 
+  ** This file configures the Server which exposes the REST endpoint.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xmlns:http="http://cxf.apache.org/transports/http/configuration"
+    xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/configuration/security 
+            http://cxf.apache.org/schemas/configuration/security.xsd 
+            http://cxf.apache.org/transports/http/configuration 
+            http://cxf.apache.org/schemas/configuration/http-conf.xsd 
+            http://cxf.apache.org/transports/http-jetty/configuration 
+            http://cxf.apache.org/schemas/configuration/http-jetty.xsd 
+            http://www.springframework.org/schema/beans 
+            http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <httpj:engine-factory bus="cxf">
+        <httpj:engine port="9000">
+            <httpj:tlsServerParameters>
+                <sec:keyManagers keyPassword="skpass">
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:keyManagers>
+                <sec:trustManagers>
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:trustManagers>
+            </httpj:tlsServerParameters>
+        </httpj:engine>
+    </httpj:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/README.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/README.txt
new file mode 100644
index 0000000..cfc5b91
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/README.txt
@@ -0,0 +1,92 @@
+JAX-RS Basic Demo With HTTPS communications
+===========================================
+
+This demo takes the JAX-RS basic demo a step further 
+by doing the communication using HTTP/2 over TLS and
+HTTP/2 over cleartext using Netty container.
+
+Building and running the demo using Maven
+-----------------------------------------
+From the base directory of this sample (i.e., where this README file is
+located), the Maven pom.xml file can be used to build and run the demo. 
+
+Using either UNIX or Windows:
+
+  mvn install
+  mvn -Ph2-server  (HTTP/2 over TLS)
+  mvn -Ph2c-server  (HTTP/2 over cleartext)
+    
+To remove the target dir, run "mvn clean".
+
+Certificates
+------------
+See the src/main/config folder for the sample keys used (don't use
+these keys in production!) as well as scripts used for their creation.
+
+HTTP/2 over cleartext
+------------
+
+- Upgrade from HTTP/1.1 to HTTP/2 (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2 -i
+  
+    HTTP/1.1 101 Switching Protocols
+    connection: upgrade
+    upgrade: h2c
+
+    HTTP/2 200
+    content-type: application/xml
+    date: Thu, 14 Oct 2021 01:48:35 GMT
+    content-length: 105
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
+- Use HTTP/2 prior knowledge (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2-prior-knowledge -i
+  
+    HTTP/2 200
+    content-type: application/xml
+    date: Thu, 14 Oct 2021 01:49:08 GMT
+    content-length: 105
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http1.1 -i
+  
+    HTTP/1.1 200 OK
+    Content-Type: application/xml
+    Date: Thu, 14 Oct 2021 01:49:35 GMT
+    content-length: 105
+    connection: keep-alive
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+    
+HTTP/2 over TLS
+------------
+
+- Use HTTP/2
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http2 -ik
+  
+    HTTP/2 200
+    content-type: application/xml
+    date: Thu, 14 Oct 2021 01:46:59 GMT
+    content-length: 105
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http1.1 -ik
+  
+    HTTP/1.1 200 OK
+    Content-Type: application/xml
+    Date: Thu, 14 Oct 2021 01:47:51 GMT
+    content-length: 105
+    connection: keep-alive
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/pom.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/pom.xml
new file mode 100644
index 0000000..fd53303
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jax_rs_basic_http2_netty</artifactId>
+    <name>JAX-RS Basic Demo With HTTP/2 communications</name>
+    <description>JAX-RS Basic Demo With HTTP/2 communications</description>
+    <parent>
+        <groupId>org.apache.cxf.samples</groupId>
+        <artifactId>cxf-samples</artifactId>
+        <version>3.5.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <profiles>
+        <profile>
+            <id>h2-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>h2c-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2c.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http-netty-server</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http2</artifactId>
+            <version>${cxf.netty.version}</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/KeyREADME.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/KeyREADME.txt
new file mode 100644
index 0000000..97f20fa
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/KeyREADME.txt
@@ -0,0 +1,8 @@
+# The below scripts show the commands used to generate the self-signed keys for this sample.
+# If you use the below script to create your own keys be sure to change the passwords used here
+# DO NOT USE THE SUPPLIED KEYS IN PRODUCTION--everyone has them!!
+# For production recommended to use keys signed by a third-party certificate authority (CA)
+
+# Create the combination keystore/truststore for the server.
+keytool -genkeypair -keyalg RSA -keysize 4096 -validity 730 -alias myservicekey -keystore serviceKeystore.jks -dname "cn=localhost" -keypass skpass -storepass sspass
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/serviceKeystore.jks b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/serviceKeystore.jks
new file mode 100644
index 0000000..e3dd4b4
Binary files /dev/null and b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/config/serviceKeystore.jks differ
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/Customer.java b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/Customer.java
new file mode 100644
index 0000000..81ce3c5
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/Customer.java
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Customer")
+public class Customer {
+    private long id;
+    private String name;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/CustomerService.java b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/CustomerService.java
new file mode 100644
index 0000000..890ade3
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/common/CustomerService.java
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+
+/**
+ * This interface describes a JAX-RS root resource. All the JAXRS annotations (except those overridden) will
+ * be inherited by classes implementing it.
+ */
+@Path("/customerservice/")
+public interface CustomerService {
+
+    @GET
+    @Path("/customers/{id}/")
+    Customer getCustomer(@PathParam("id") String id);
+
+    @PUT
+    @Path("/customers/")
+    Response updateCustomer(Customer customer);
+
+    @POST
+    @Path("/customers/")
+    Response addCustomer(Customer customer);
+
+    @DELETE
+    @Path("/customers/{id}/")
+    Response deleteCustomer(@PathParam("id") String id);
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/CustomerServiceImpl.java b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/CustomerServiceImpl.java
new file mode 100644
index 0000000..171d27b
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/CustomerServiceImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.
+ */
+package http2demo.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import http2demo.common.Customer;
+import http2demo.common.CustomerService;
+
+public class CustomerServiceImpl implements CustomerService {
+    long currentId = 123;
+    Map<Long, Customer> customers = new HashMap<>();
+
+    public CustomerServiceImpl() {
+        init();
+    }
+
+    public Customer getCustomer(String id) {
+        System.out.println("----invoking getCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        return customers.get(idNumber);
+    }
+
+    public Response updateCustomer(Customer customer) {
+        System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
+        Customer c = customers.get(customer.getId());
+        Response r;
+        if (c != null) {
+            customers.put(customer.getId(), customer);
+            r = Response.ok().build();
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    public Response addCustomer(Customer customer) {
+        System.out.println("----invoking addCustomer, Customer name is: " + customer.getName());
+        customer.setId(++currentId);
+
+        customers.put(customer.getId(), customer);
+
+        return Response.ok(customer).build();
+    }
+
+    public Response deleteCustomer(String id) {
+        System.out.println("----invoking deleteCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        Customer c = customers.get(idNumber);
+
+        Response r;
+        if (c != null) {
+            r = Response.ok().build();
+            customers.remove(idNumber);
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    final void init() {
+        Customer c = new Customer();
+        c.setName("John");
+        c.setId(123);
+        customers.put(c.getId(), c);
+    }
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2/Server.java
new file mode 100644
index 0000000..d821996
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus("ServerConfig.xml");
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("https://localhost:9000/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2c/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2c/Server.java
new file mode 100644
index 0000000..d86ef95
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/java/http2demo/server/h2c/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2c;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus();
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("http://localhost:9001/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/resources/ServerConfig.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/resources/ServerConfig.xml
new file mode 100644
index 0000000..8506180
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_netty/src/main/resources/ServerConfig.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!-- 
+  ** This file configures the Server which exposes the REST endpoint.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xmlns:http="http://cxf.apache.org/transports/http/configuration"
+    xmlns:httpj="http://cxf.apache.org/transports/http-netty-server/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/configuration/security 
+        http://cxf.apache.org/schemas/configuration/security.xsd 
+        http://cxf.apache.org/transports/http/configuration 
+        http://cxf.apache.org/schemas/configuration/http-conf.xsd 
+        http://cxf.apache.org/transports/http-netty-server/configuration 
+        http://cxf.apache.org/schemas/configuration/http-netty-server.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <httpj:engine-factory bus="cxf">
+        <httpj:engine port="9000">
+            <httpj:tlsServerParameters>
+                <sec:keyManagers keyPassword="skpass">
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:keyManagers>
+                <sec:trustManagers>
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:trustManagers>
+            </httpj:tlsServerParameters>
+        </httpj:engine>
+    </httpj:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/README.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/README.txt
new file mode 100644
index 0000000..bb2cb62
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/README.txt
@@ -0,0 +1,93 @@
+JAX-RS Basic Demo With HTTPS communications
+===========================================
+
+This demo takes the JAX-RS basic demo a step further 
+by doing the communication using HTTP/2 over TLS and
+HTTP/2 over cleartext using Undertow container.
+
+Building and running the demo using Maven
+-----------------------------------------
+From the base directory of this sample (i.e., where this README file is
+located), the Maven pom.xml file can be used to build and run the demo. 
+
+Using either UNIX or Windows:
+
+  mvn install
+  mvn -Ph2-server  (HTTP/2 over TLS)
+  mvn -Ph2c-server  (HTTP/2 over cleartext)
+    
+To remove the target dir, run "mvn clean".
+
+Certificates
+------------
+See the src/main/config folder for the sample keys used (don't use
+these keys in production!) as well as scripts used for their creation.
+
+HTTP/2 over cleartext
+------------
+
+- Upgrade from HTTP/1.1 to HTTP/2 (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2 -i
+  
+    HTTP/1.1 101 Switching Protocols
+    Connection: Upgrade
+    Upgrade: h2c
+    Date: Thu, 14 Oct 2021 00:51:50 GMT
+  
+    HTTP/2 200
+    content-type: application/xml
+    content-length: 105
+    date: Thu, 14 Oct 2021 00:51:50 GMT
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
+- Use HTTP/2 prior knowledge (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http2-prior-knowledge -i
+  
+    HTTP/2 200
+    content-type: application/xml
+    content-length: 105
+    date: Thu, 14 Oct 2021 00:55:35 GMT
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage (cleartext)
+
+    $ curl http://localhost:9001/customerservice/customers/123 --http1.1 -i
+  
+    HTTP/1.1 200 OK
+    Connection: keep-alive
+    Content-Type: application/xml
+    Content-Length: 105
+    Date: Thu, 14 Oct 2021 00:50:50 GMT
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+    
+HTTP/2 over TLS
+------------
+
+- Use HTTP/2
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http2 -ik
+  
+    HTTP/2 200
+    content-type: application/xml
+    content-length: 105
+    date: Thu, 14 Oct 2021 01:04:34 GMT
+
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+  
+- Force HTTP/1.1 usage
+
+    $ curl https://localhost:9000/customerservice/customers/123 --http1.1 -ik
+  
+    HTTP/1.1 200 OK
+    Connection: keep-alive
+    Content-Type: application/xml
+    Content-Length: 105
+    Date: Thu, 14 Oct 2021 01:06:34 GMT
+  
+    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customer><id>123</id><name>John</name></Customer>
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/pom.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/pom.xml
new file mode 100644
index 0000000..ea57f3a
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jax_rs_basic_http2_undertow</artifactId>
+    <name>JAX-RS Basic Demo With HTTP/2 communications</name>
+    <description>JAX-RS Basic Demo With HTTP/2 communications</description>
+    <parent>
+        <groupId>org.apache.cxf.samples</groupId>
+        <artifactId>cxf-samples</artifactId>
+        <version>3.5.0-SNAPSHOT</version>
+        <relativePath>../..</relativePath>
+    </parent>
+    <profiles>
+        <profile>
+            <id>h2-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>h2c-server</id>
+            <build>
+                <defaultGoal>test</defaultGoal>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <phase>test</phase>
+                                <goals>
+                                    <goal>java</goal>
+                                </goals>
+                                <configuration>
+                                    <mainClass>http2demo.server.h2c.Server</mainClass>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-transports-http-undertow</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/KeyREADME.txt b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/KeyREADME.txt
new file mode 100644
index 0000000..97f20fa
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/KeyREADME.txt
@@ -0,0 +1,8 @@
+# The below scripts show the commands used to generate the self-signed keys for this sample.
+# If you use the below script to create your own keys be sure to change the passwords used here
+# DO NOT USE THE SUPPLIED KEYS IN PRODUCTION--everyone has them!!
+# For production recommended to use keys signed by a third-party certificate authority (CA)
+
+# Create the combination keystore/truststore for the server.
+keytool -genkeypair -keyalg RSA -keysize 4096 -validity 730 -alias myservicekey -keystore serviceKeystore.jks -dname "cn=localhost" -keypass skpass -storepass sspass
+
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/serviceKeystore.jks b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/serviceKeystore.jks
new file mode 100644
index 0000000..8d40c61
Binary files /dev/null and b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/config/serviceKeystore.jks differ
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/Customer.java b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/Customer.java
new file mode 100644
index 0000000..81ce3c5
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/Customer.java
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Customer")
+public class Customer {
+    private long id;
+    private String name;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/CustomerService.java b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/CustomerService.java
new file mode 100644
index 0000000..890ade3
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/common/CustomerService.java
@@ -0,0 +1,52 @@
+/**
+ * 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.
+ */
+package http2demo.common;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+
+/**
+ * This interface describes a JAX-RS root resource. All the JAXRS annotations (except those overridden) will
+ * be inherited by classes implementing it.
+ */
+@Path("/customerservice/")
+public interface CustomerService {
+
+    @GET
+    @Path("/customers/{id}/")
+    Customer getCustomer(@PathParam("id") String id);
+
+    @PUT
+    @Path("/customers/")
+    Response updateCustomer(Customer customer);
+
+    @POST
+    @Path("/customers/")
+    Response addCustomer(Customer customer);
+
+    @DELETE
+    @Path("/customers/{id}/")
+    Response deleteCustomer(@PathParam("id") String id);
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/CustomerServiceImpl.java b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/CustomerServiceImpl.java
new file mode 100644
index 0000000..171d27b
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/CustomerServiceImpl.java
@@ -0,0 +1,89 @@
+/**
+ * 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.
+ */
+package http2demo.server;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ws.rs.core.Response;
+
+import http2demo.common.Customer;
+import http2demo.common.CustomerService;
+
+public class CustomerServiceImpl implements CustomerService {
+    long currentId = 123;
+    Map<Long, Customer> customers = new HashMap<>();
+
+    public CustomerServiceImpl() {
+        init();
+    }
+
+    public Customer getCustomer(String id) {
+        System.out.println("----invoking getCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        return customers.get(idNumber);
+    }
+
+    public Response updateCustomer(Customer customer) {
+        System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName());
+        Customer c = customers.get(customer.getId());
+        Response r;
+        if (c != null) {
+            customers.put(customer.getId(), customer);
+            r = Response.ok().build();
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    public Response addCustomer(Customer customer) {
+        System.out.println("----invoking addCustomer, Customer name is: " + customer.getName());
+        customer.setId(++currentId);
+
+        customers.put(customer.getId(), customer);
+
+        return Response.ok(customer).build();
+    }
+
+    public Response deleteCustomer(String id) {
+        System.out.println("----invoking deleteCustomer, Customer id is: " + id);
+        long idNumber = Long.parseLong(id);
+        Customer c = customers.get(idNumber);
+
+        Response r;
+        if (c != null) {
+            r = Response.ok().build();
+            customers.remove(idNumber);
+        } else {
+            r = Response.notModified().build();
+        }
+
+        return r;
+    }
+
+    final void init() {
+        Customer c = new Customer();
+        c.setName("John");
+        c.setId(123);
+        customers.put(c.getId(), c);
+    }
+
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2/Server.java
new file mode 100644
index 0000000..d821996
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus("ServerConfig.xml");
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("https://localhost:9000/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2c/Server.java b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2c/Server.java
new file mode 100644
index 0000000..d86ef95
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/java/http2demo/server/h2c/Server.java
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+
+package http2demo.server.h2c;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+import http2demo.server.CustomerServiceImpl;
+
+public class Server {
+
+    static {
+        // set the configuration file
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus();
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        BusFactory.setDefaultBus(bus);
+    }
+
+    protected Server() throws Exception {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(CustomerServiceImpl.class);
+        sf.setResourceProvider(CustomerServiceImpl.class,
+            new SingletonResourceProvider(new CustomerServiceImpl()));
+        sf.setAddress("http://localhost:9001/");
+
+        sf.create();
+    }
+
+    public static void main(String[] args) throws Exception {
+        new Server();
+        System.out.println("Server ready...");
+
+        Thread.sleep(5 * 60 * 1000);
+        System.out.println("Server exiting");
+        System.exit(0);
+    }
+}
diff --git a/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/resources/ServerConfig.xml b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/resources/ServerConfig.xml
new file mode 100644
index 0000000..fff566f
--- /dev/null
+++ b/distribution/src/main/release/samples/jax_rs/basic_http2_undertow/src/main/resources/ServerConfig.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!-- 
+  ** This file configures the Server which exposes the REST endpoint.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xmlns:http="http://cxf.apache.org/transports/http/configuration"
+    xmlns:httpj="http://cxf.apache.org/transports/http-undertow/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/configuration/security 
+        http://cxf.apache.org/schemas/configuration/security.xsd 
+        http://cxf.apache.org/transports/http/configuration 
+        http://cxf.apache.org/schemas/configuration/http-conf.xsd 
+        http://cxf.apache.org/transports/http-undertow/configuration 
+        http://cxf.apache.org/schemas/configuration/http-undertow.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <httpj:engine-factory bus="cxf">
+        <httpj:engine port="9000">
+            <httpj:tlsServerParameters>
+                <sec:keyManagers keyPassword="skpass">
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:keyManagers>
+                <sec:trustManagers>
+                    <sec:keyStore file="src/main/config/serviceKeystore.jks" password="sspass" type="JKS"/>
+                </sec:trustManagers>
+            </httpj:tlsServerParameters>
+        </httpj:engine>
+    </httpj:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/distribution/src/main/release/samples/pom.xml b/distribution/src/main/release/samples/pom.xml
index 409eb38..754c6297 100644
--- a/distribution/src/main/release/samples/pom.xml
+++ b/distribution/src/main/release/samples/pom.xml
@@ -30,9 +30,10 @@
         <!-- don't deploy the samples, kind of pointless -->
         <maven.deploy.skip>true</maven.deploy.skip>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <spring.boot.version>2.5.0</spring.boot.version>
+        <spring.boot.version>2.5.5</spring.boot.version>
         <spring.cloud.eureka.version>3.0.3</spring.cloud.eureka.version>
-        <cxf.jetty9.version>9.4.43.v20210629</cxf.jetty9.version>
+        <cxf.jetty9.version>9.4.44.v20210927</cxf.jetty9.version>
+        <cxf.netty.version>4.1.69.Final</cxf.netty.version>
         <cxf.httpcomponents.client.version>4.5.13</cxf.httpcomponents.client.version>
         <cxf.swagger.ui.version>3.52.1</cxf.swagger.ui.version>
         <cxf.tika.version>2.1.0</cxf.tika.version>
@@ -147,6 +148,9 @@
         <module>jaxws_graalvm_dynamic/client</module>
         <module>jaxws_graalvm_dynamic/server</module>
         <module>jax_rs/graalvm_basic</module>
+        <module>jax_rs/basic_http2_undertow</module>
+        <module>jax_rs/basic_http2_netty</module>
+        <module>jax_rs/basic_http2_jetty</module>
     </modules>
     <dependencyManagement>
         <dependencies>
diff --git a/parent/pom.xml b/parent/pom.xml
index f2c17b7..97e5429 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1159,6 +1159,16 @@
                 <version>${cxf.jetty.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.eclipse.jetty.http2</groupId>
+                <artifactId>http2-server</artifactId>
+                <version>${cxf.jetty.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.eclipse.jetty</groupId>
+                <artifactId>jetty-alpn-server</artifactId>
+                <version>${cxf.jetty.version}</version>
+            </dependency>
+            <dependency>
                  <groupId>io.undertow</groupId>
                  <artifactId>undertow-core</artifactId>
                  <version>${cxf.undertow.version}</version>
diff --git a/rt/transports/http-jetty/pom.xml b/rt/transports/http-jetty/pom.xml
index d17d88a..a8c0ff9 100644
--- a/rt/transports/http-jetty/pom.xml
+++ b/rt/transports/http-jetty/pom.xml
@@ -128,6 +128,16 @@
             <artifactId>jetty-http</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <scope>runtime</scope>
diff --git a/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
index 45212be..ffc8819 100644
--- a/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
+++ b/rt/transports/http-jetty/src/main/java/org/apache/cxf/transport/http_jetty/JettyHTTPServerEngine.java
@@ -54,7 +54,11 @@ import org.apache.cxf.configuration.security.ClientAuthentication;
 import org.apache.cxf.helpers.JavaUtils;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.transport.HttpUriMapper;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
 import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
+import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
 import org.eclipse.jetty.security.SecurityHandler;
 import org.eclipse.jetty.server.AbstractConnector;
 import org.eclipse.jetty.server.ConnectionFactory;
@@ -84,7 +88,7 @@ import org.eclipse.jetty.util.thread.ThreadPool;
  * work off of a designated port. The port will be enabled for
  * "http" or "https" depending upon its successful configuration.
  */
-public class JettyHTTPServerEngine implements ServerEngine {
+public class JettyHTTPServerEngine implements ServerEngine, HttpServerEngineSupport {
     public static final String DO_NOT_CHECK_URL_PROP = "org.apache.cxf.transports.http_jetty.DontCheckUrl";
 
     private static final Logger LOG = LogUtils.getL7dLogger(JettyHTTPServerEngine.class);
@@ -145,15 +149,12 @@ public class JettyHTTPServerEngine implements ServerEngine {
     /**
      * This constructor is called by the JettyHTTPServerEngineFactory.
      */
-    public JettyHTTPServerEngine(
-        Container.Listener mBeanContainer,
-        String host,
-        int port) {
+    public JettyHTTPServerEngine(Container.Listener mBeanContainer, String host, int port) {
         this.host = host;
         this.port = port;
         this.mBeanContainer = mBeanContainer;
     }
-
+    
     public JettyHTTPServerEngine() {
 
     }
@@ -398,7 +399,7 @@ public class JettyHTTPServerEngine implements ServerEngine {
             addServerMBean();
 
             if (connector == null) {
-                connector = createConnector(getHost(), getPort());
+                connector = createConnector(getHost(), getPort(), handler.getBus());
                 if (LOG.isLoggable(Level.FINER)) {
                     logConnector((ServerConnector)connector);
                 }
@@ -621,7 +622,7 @@ public class JettyHTTPServerEngine implements ServerEngine {
     }
 
     
-    private Connector createConnector(String hosto, int porto) {
+    private Connector createConnector(String hosto, int porto, final Bus bus) {
         // now we just use the SelectChannelConnector as the default connector
         SslContextFactory sslcf = null;
         if (tlsServerParameters != null) {
@@ -648,7 +649,7 @@ public class JettyHTTPServerEngine implements ServerEngine {
             // unparsable version
         }
 
-        ServerConnector result = (ServerConnector)createConnectorJetty(sslcf, hosto, porto, major, minor);
+        ServerConnector result = (ServerConnector)createConnectorJetty(sslcf, hosto, porto, major, minor, bus);
 
         try {
             result.setPort(porto);
@@ -665,7 +666,8 @@ public class JettyHTTPServerEngine implements ServerEngine {
         return result;
     }
 
-    AbstractConnector createConnectorJetty(SslContextFactory sslcf, String hosto, int porto, int major, int minor) {
+    AbstractConnector createConnectorJetty(SslContextFactory sslcf, String hosto, int porto, 
+            int major, int minor, final Bus bus) {
         final AbstractConnector result;
         try {
             HttpConfiguration httpConfig = new HttpConfiguration();
@@ -678,10 +680,26 @@ public class JettyHTTPServerEngine implements ServerEngine {
 
             if (tlsServerParameters != null) {
                 httpConfig.addCustomizer(new org.eclipse.jetty.server.SecureRequestCustomizer());
-                SslConnectionFactory scf = new SslConnectionFactory(sslcf, "HTTP/1.1");
-                connectionFactories.add(scf);
+
+                if (!isHttp2Enabled(bus)) {
+                    final SslConnectionFactory scf = new SslConnectionFactory(sslcf, httpFactory.getProtocol());
+                    connectionFactories.add(scf);
+                } else {
+                    // The ALPN processors are application specific (as per Jetty docs) and are pluggable as
+                    // additional dependency.
+                    final ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory();
+                    alpn.setDefaultProtocol(httpFactory.getProtocol());
+                    
+                    final SslConnectionFactory scf = new SslConnectionFactory(sslcf, alpn.getProtocol());
+                    connectionFactories.add(scf);
+                    connectionFactories.add(alpn);
+                    connectionFactories.add(new HTTP2ServerConnectionFactory(httpConfig));
+                }
+
                 String proto = (major > 9 || (major == 9 && minor >= 3)) ? "SSL" : "SSL-HTTP/1.1";
                 result.setDefaultProtocol(proto);
+            } else if (isHttp2Enabled(bus)) {
+                connectionFactories.add(new HTTP2CServerConnectionFactory(httpConfig));
             }
             connectionFactories.add(httpFactory);
             result.setConnectionFactories(connectionFactories);
diff --git a/rt/transports/http-netty/netty-server/pom.xml b/rt/transports/http-netty/netty-server/pom.xml
index 3807fdd..9e65f55 100644
--- a/rt/transports/http-netty/netty-server/pom.xml
+++ b/rt/transports/http-netty/netty-server/pom.xml
@@ -62,6 +62,12 @@
             <version>${cxf.netty.version}</version>
         </dependency>
         <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http2</artifactId>
+            <version>${cxf.netty.version}</version>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
             <!-- we don't implement the servlet 3.0 specification here -->
             <groupId>org.apache.geronimo.specs</groupId>
             <artifactId>geronimo-servlet_2.5_spec</artifactId>
diff --git a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngine.java b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngine.java
index 182d997..c198fb2 100644
--- a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngine.java
+++ b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngine.java
@@ -29,11 +29,13 @@ import java.util.logging.Logger;
 
 import javax.annotation.PostConstruct;
 
+import org.apache.cxf.Bus;
 import org.apache.cxf.common.i18n.Message;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.configuration.jsse.TLSServerParameters;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.transport.HttpUriMapper;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
 
 import io.netty.bootstrap.ServerBootstrap;
 import io.netty.channel.Channel;
@@ -44,7 +46,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
 import io.netty.util.concurrent.DefaultEventExecutorGroup;
 import io.netty.util.concurrent.EventExecutorGroup;
 
-public class NettyHttpServerEngine implements ServerEngine {
+public class NettyHttpServerEngine implements ServerEngine, HttpServerEngineSupport {
 
     private static final Logger LOG =
             LogUtils.getL7dLogger(NettyHttpServerEngine.class);
@@ -95,22 +97,37 @@ public class NettyHttpServerEngine implements ServerEngine {
     private EventLoopGroup bossGroup;
     private EventLoopGroup workerGroup;
     private EventExecutorGroup applicationExecutor;
+    
+    private Bus bus;
 
+    
     public NettyHttpServerEngine() {
 
     }
 
-    public NettyHttpServerEngine(
-            String host,
-            int port) {
+    @Deprecated
+    public NettyHttpServerEngine(String host, int port) {
+        this(host, port, null);
+    }
+
+    public NettyHttpServerEngine(String host, int port, Bus bus) {
         this.host = host;
         this.port = port;
+        this.bus = bus;
     }
 
     @PostConstruct
     public void finalizeConfig() {
         // need to check if we need to any other thing other than Setting the TLSServerParameter
     }
+    
+    public void setBus(Bus bus) {
+        this.bus = bus;
+    }
+    
+    public Bus getBus() {
+        return bus;
+    }
 
     /**
      * This method is used to programmatically set the TLSServerParameters.
@@ -163,7 +180,7 @@ public class NettyHttpServerEngine implements ServerEngine {
             new NettyHttpServletPipelineFactory(
                  tlsServerParameters, sessionSupport,
                  maxChunkContentSize, handlerMap,
-                 this, applicationExecutor);
+                 this, applicationExecutor, isHttp2Enabled(bus));
         // Start the servletPipeline's timer
         servletPipeline.start();
         bootstrap.childHandler(servletPipeline);
diff --git a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngineFactory.java b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngineFactory.java
index 93bb2ca..7c3712f 100644
--- a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngineFactory.java
+++ b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServerEngineFactory.java
@@ -151,7 +151,7 @@ public class NettyHttpServerEngineFactory implements BusLifeCycleListener {
 
         NettyHttpServerEngine ref = portMap.get(port);
         if (ref == null) {
-            ref = new NettyHttpServerEngine(host, port);
+            ref = new NettyHttpServerEngine(host, port, factory.getBus());
             if (tlsParams != null) {
                 ref.setTlsServerParameters(tlsParams);
             }
diff --git a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServletPipelineFactory.java b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServletPipelineFactory.java
index f92a16e..cdc9350 100644
--- a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServletPipelineFactory.java
+++ b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/NettyHttpServletPipelineFactory.java
@@ -19,31 +19,64 @@
 
 package org.apache.cxf.transport.http.netty.server;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
 
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.configuration.jsse.TLSServerParameters;
+import org.apache.cxf.configuration.security.ClientAuthentication;
 import org.apache.cxf.transport.http.netty.server.interceptor.ChannelInterceptor;
 import org.apache.cxf.transport.http.netty.server.interceptor.HttpSessionInterceptor;
 import org.apache.cxf.transport.http.netty.server.session.DefaultHttpSessionStore;
 import org.apache.cxf.transport.http.netty.server.session.HttpSessionStore;
+import org.apache.cxf.transport.https.SSLContextInitParameters;
 import org.apache.cxf.transport.https.SSLUtils;
 
 import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
+import io.netty.channel.SimpleChannelInboundHandler;
 import io.netty.channel.group.ChannelGroup;
 import io.netty.channel.group.DefaultChannelGroup;
 import io.netty.handler.codec.http.HttpContentCompressor;
+import io.netty.handler.codec.http.HttpMessage;
 import io.netty.handler.codec.http.HttpObjectAggregator;
 import io.netty.handler.codec.http.HttpRequestDecoder;
 import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.codec.http.HttpServerCodec;
+import io.netty.handler.codec.http.HttpServerUpgradeHandler;
+import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodec;
+import io.netty.handler.codec.http.HttpServerUpgradeHandler.UpgradeCodecFactory;
+import io.netty.handler.codec.http2.CleartextHttp2ServerUpgradeHandler;
+import io.netty.handler.codec.http2.Http2CodecUtil;
+import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
+import io.netty.handler.codec.http2.Http2MultiplexHandler;
+import io.netty.handler.codec.http2.Http2SecurityUtil;
+import io.netty.handler.codec.http2.Http2ServerUpgradeCodec;
+import io.netty.handler.codec.http2.Http2StreamFrameToHttpObjectCodec;
+import io.netty.handler.ssl.ApplicationProtocolConfig;
+import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolNames;
+import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.ssl.SslProvider;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
 import io.netty.handler.timeout.IdleStateHandler;
+import io.netty.util.AsciiString;
+import io.netty.util.ReferenceCountUtil;
 import io.netty.util.concurrent.DefaultEventExecutorGroup;
 import io.netty.util.concurrent.EventExecutorGroup;
 import io.netty.util.concurrent.ImmediateEventExecutor;
@@ -68,6 +101,8 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
     private final EventExecutorGroup applicationExecutor;
 
     private final NettyHttpServerEngine nettyHttpServerEngine;
+    
+    private final boolean enableHttp2; /* enable HTTP2 support */
 
     /**
      * @deprecated use {@link #NettyHttpServletPipelineFactory(TLSServerParameters, boolean, int, Map,
@@ -83,9 +118,18 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
     }
 
     public NettyHttpServletPipelineFactory(TLSServerParameters tlsServerParameters,
+            boolean supportSession, int maxChunkContentSize,
+            Map<String, NettyHttpContextHandler> handlerMap,
+            NettyHttpServerEngine engine, EventExecutorGroup applicationExecutor) {
+        this(tlsServerParameters, supportSession, maxChunkContentSize, handlerMap, engine,
+            applicationExecutor, false);
+    }
+
+    public NettyHttpServletPipelineFactory(TLSServerParameters tlsServerParameters,
                                            boolean supportSession, int maxChunkContentSize,
                                            Map<String, NettyHttpContextHandler> handlerMap,
-                                           NettyHttpServerEngine engine, EventExecutorGroup applicationExecutor) {
+                                           NettyHttpServerEngine engine, EventExecutorGroup applicationExecutor,
+                                           boolean enableHttp2) {
         this.supportSession = supportSession;
         this.watchdog = new HttpSessionWatchdog();
         this.handlerMap = handlerMap;
@@ -93,6 +137,7 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
         this.maxChunkContentSize = maxChunkContentSize;
         this.nettyHttpServerEngine = engine;
         this.applicationExecutor = applicationExecutor;
+        this.enableHttp2 = enableHttp2;
     }
 
     public Map<String, NettyHttpContextHandler> getHttpContextHandlerMap() {
@@ -139,12 +184,12 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
         return handler;
     }
 
-    protected ChannelPipeline getDefaulHttpChannelPipeline(Channel channel) throws Exception {
+    protected ChannelPipeline getDefaultHttpChannelPipeline(Channel channel) throws Exception {
 
         // Create a default pipeline implementation.
         ChannelPipeline pipeline = channel.pipeline();
 
-        SslHandler sslHandler = configureServerSSLOnDemand();
+        SslHandler sslHandler = configureServerHttpSSLOnDemand();
         if (sslHandler != null) {
             LOG.log(Level.FINE,
                     "Server SSL handler configured and added as an interceptor against the ChannelPipeline: {}",
@@ -152,6 +197,18 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
             pipeline.addLast("ssl", sslHandler);
         }
 
+        configureDefaultHttpPipeline(pipeline);
+
+        return pipeline;
+    }
+    
+    protected void configureDefaultHttp2Pipeline(ChannelPipeline pipeline) {
+        pipeline
+            .addLast(Http2FrameCodecBuilder.forServer().build())
+            .addLast(new Http2MultiplexHandler(createHttp2ChannelInitializer()));
+    }
+
+    protected void configureDefaultHttpPipeline(ChannelPipeline pipeline) {
         pipeline.addLast("decoder", new HttpRequestDecoder());
         pipeline.addLast("encoder", new HttpResponseEncoder());
         pipeline.addLast("aggregator", new HttpObjectAggregator(maxChunkContentSize));
@@ -159,20 +216,74 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
         // Remove the following line if you don't want automatic content
         // compression.
         pipeline.addLast("deflater", new HttpContentCompressor());
+        
         // Set up the idle handler
         pipeline.addLast("idle", new IdleStateHandler(nettyHttpServerEngine.getReadIdleTime(),
                 nettyHttpServerEngine.getWriteIdleTime(), 0));
-
-        return pipeline;
     }
 
-    private SslHandler configureServerSSLOnDemand() throws Exception {
+    private SslHandler configureServerHttpSSLOnDemand() throws Exception {
         if (tlsServerParameters != null) {
             SSLEngine sslEngine = SSLUtils.createServerSSLEngine(tlsServerParameters);
             return new SslHandler(sslEngine);
         }
         return null;
     }
+    
+    private SslContext configureServerHttp2SSLOnDemand() throws Exception {
+        if (tlsServerParameters != null) {
+            final SSLContextInitParameters initParams = SSLUtils.getSSLContextInitParameters(tlsServerParameters);
+            // Use only JDK provider for now, leaving OpenSsl as an option
+            final SslProvider provider = SslProvider.JDK;
+    
+            final KeyManager[] keyManagers = initParams.getKeyManagers();
+            if (keyManagers == null || keyManagers.length == 0) {
+                throw new IllegalStateException("No KeyManagers are configured, unable "
+                        + "to create Netty's SslContext instance");
+            }
+            
+            final String[] cipherSuites = org.apache.cxf.configuration.jsse.SSLUtils
+                .getCiphersuitesToInclude(
+                        tlsServerParameters.getCipherSuites(), 
+                        tlsServerParameters.getCipherSuitesFilter(),
+                        SSLContext.getDefault().getDefaultSSLParameters().getCipherSuites(),
+                        Http2SecurityUtil.CIPHERS.toArray(new String[] {}),
+                        LOG);
+            
+            final SslContextBuilder builder = SslContextBuilder
+                .forServer(keyManagers[0]) /* only first is used, as with SSLContext::init*/
+                .sslProvider(provider)
+                .ciphers(Arrays.asList(cipherSuites), SupportedCipherSuiteFilter.INSTANCE)
+                .applicationProtocolConfig(
+                    new ApplicationProtocolConfig(
+                        Protocol.ALPN,
+                        // NO_ADVERTISE is currently the only mode supported by both OpenSsl and JDK providers.
+                        SelectorFailureBehavior.NO_ADVERTISE,
+                        // ACCEPT is currently the only mode supported by both OpenSsl and JDK providers.
+                        SelectedListenerFailureBehavior.ACCEPT,
+                        ApplicationProtocolNames.HTTP_2,
+                        ApplicationProtocolNames.HTTP_1_1
+                    ));
+            
+            final TrustManager[] trustManagers = initParams.getTrustManagers();
+            if (trustManagers != null && trustManagers.length > 0) {
+                builder.trustManager(trustManagers[0]);
+            }
+            
+            final ClientAuthentication clientAuth = tlsServerParameters.getClientAuthentication();
+            if (clientAuth != null) {
+                if (clientAuth.isSetRequired() && clientAuth.isRequired()) {
+                    builder.clientAuth(ClientAuth.REQUIRE);
+                } else if (clientAuth.isSetWant() && clientAuth.isWant()) {
+                    builder.clientAuth(ClientAuth.OPTIONAL);
+                }
+            }
+            
+            return builder.build();
+        }
+        
+        return null;
+    }
 
     private class HttpSessionWatchdog implements Runnable {
 
@@ -203,12 +314,115 @@ public class NettyHttpServletPipelineFactory extends ChannelInitializer<Channel>
         }
 
     }
+    
+    /**
+     * Application negotiation handler to select either HTTP 1.1 or HTTP 2 protocol, based
+     * on client/server ALPN negotiations.
+     */
+    private class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler {
+        protected Http2OrHttpHandler() {
+            super(ApplicationProtocolNames.HTTP_1_1);
+        }
+
+        @Override
+        protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
+            if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
+                configureDefaultHttp2Pipeline(ctx.pipeline());
+            } else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {
+                configureDefaultHttpPipeline(ctx.pipeline());
+                ctx.pipeline().addLast(applicationExecutor, "handler", getServletHandler());
+            } else {
+                throw new IllegalStateException("Unknown application protocol: " + protocol);
+            }
+        }
+    }
 
     @Override
     protected void initChannel(Channel ch) throws Exception {
-        ChannelPipeline pipeline = getDefaulHttpChannelPipeline(ch);
+        if (!enableHttp2) {
+            final ChannelPipeline pipeline = getDefaultHttpChannelPipeline(ch);
+            pipeline.addLast(applicationExecutor, "handler", this.getServletHandler());
+        } else {
+            getDefaultHttp2ChannelPipeline(ch);
+        }
+    }
+    
+    protected ChannelPipeline getDefaultHttp2ChannelPipeline(Channel channel) throws Exception {
+        // Create a default pipeline implementation with HTTP/2 support
+        ChannelPipeline pipeline = channel.pipeline();
+
+        SslContext sslCtx = configureServerHttp2SSLOnDemand();
+        if (sslCtx != null) {
+            final SslHandler sslHandler = sslCtx.newHandler(channel.alloc());
 
-        pipeline.addLast(applicationExecutor, "handler", this.getServletHandler());
+            LOG.log(Level.FINE,
+                    "Server SSL handler configured and added as an interceptor against the ChannelPipeline: {}",
+                    sslHandler);
+            
+            pipeline.addLast(sslHandler, new Http2OrHttpHandler());
+            return pipeline;
+        }
+        
+        final UpgradeCodecFactory upgradeCodecFactory = new UpgradeCodecFactory() {
+            @Override
+            public UpgradeCodec newUpgradeCodec(CharSequence protocol) {
+                if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {
+                    return new Http2ServerUpgradeCodec(
+                        Http2FrameCodecBuilder.forServer().build(),
+                        new Http2MultiplexHandler(createHttp2ChannelInitializer()));
+                } else {
+                    return null;
+                }
+            }
+        };
+        
+        final HttpServerCodec sourceCodec = new HttpServerCodec();
+        final HttpServerUpgradeHandler upgradeHandler = new HttpServerUpgradeHandler(sourceCodec, upgradeCodecFactory);
+        final CleartextHttp2ServerUpgradeHandler cleartextUpgradeHandler = new CleartextHttp2ServerUpgradeHandler(
+            sourceCodec, upgradeHandler, createHttp2ChannelInitializerPriorKnowledge());
+
+        pipeline.addLast(cleartextUpgradeHandler);
+        pipeline.addLast(new SimpleChannelInboundHandler<HttpMessage>() {
+            @Override
+            protected void channelRead0(ChannelHandlerContext ctx, HttpMessage msg) throws Exception {
+                // If this handler is hit then no upgrade has been attempted and the client is just talking HTTP
+                final ChannelPipeline pipeline = ctx.pipeline();
+                
+                pipeline.addAfter(applicationExecutor, ctx.name(), "handler", getServletHandler());
+                pipeline.replace(this, "aggregator", new HttpObjectAggregator(maxChunkContentSize));
+
+                // Remove the following line if you don't want automatic content compression.
+                pipeline.addLast("deflater", new HttpContentCompressor());
+
+                // Set up the idle handler
+                pipeline.addLast("idle", new IdleStateHandler(nettyHttpServerEngine.getReadIdleTime(),
+                        nettyHttpServerEngine.getWriteIdleTime(), 0));
+
+                ctx.fireChannelRead(ReferenceCountUtil.retain(msg));
+            }
+        });
+        
+        return pipeline;
     }
 
+    private ChannelInitializer<Channel> createHttp2ChannelInitializer() {
+        return new ChannelInitializer<Channel>() {
+            @Override
+            protected void initChannel(Channel childChannel) throws Exception {
+                childChannel.pipeline()
+                    .addLast(new Http2StreamFrameToHttpObjectCodec(true))
+                    .addLast("aggregator", new HttpObjectAggregator(maxChunkContentSize))
+                    .addLast(applicationExecutor, getServletHandler());
+            }
+        };
+    }
+    
+    private ChannelInitializer<Channel> createHttp2ChannelInitializerPriorKnowledge() {
+        return new ChannelInitializer<Channel>() {
+            @Override
+            protected void initChannel(Channel childChannel) throws Exception {
+                configureDefaultHttp2Pipeline(childChannel.pipeline());
+            }
+        };
+    }
 }
diff --git a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/spring/NettyHttpServerEngineBeanDefinitionParser.java b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/spring/NettyHttpServerEngineBeanDefinitionParser.java
index 2ef975e..8e8daf9 100644
--- a/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/spring/NettyHttpServerEngineBeanDefinitionParser.java
+++ b/rt/transports/http-netty/netty-server/src/main/java/org/apache/cxf/transport/http/netty/server/spring/NettyHttpServerEngineBeanDefinitionParser.java
@@ -229,7 +229,6 @@ public class NettyHttpServerEngineBeanDefinitionParser extends AbstractBeanDefin
 
         String threadingRef;
         String tlsRef;
-        Bus bus;
         NettyHttpServerEngineFactory factory;
 
         public SpringNettyHttpServerEngine(
@@ -237,8 +236,7 @@ public class NettyHttpServerEngineBeanDefinitionParser extends AbstractBeanDefin
             Bus b,
             String host,
             int port) {
-            super(host, port);
-            bus = b;
+            super(host, port, b);
             factory = fac;
         }
 
@@ -247,15 +245,15 @@ public class NettyHttpServerEngineBeanDefinitionParser extends AbstractBeanDefin
         }
 
         public void setBus(Bus b) {
-            bus = b;
-            if (null != bus && null == factory) {
-                factory = bus.getExtension(NettyHttpServerEngineFactory.class);
+            super.setBus(b);
+            if (null != getBus() && null == factory) {
+                factory = getBus().getExtension(NettyHttpServerEngineFactory.class);
             }
         }
 
         public void setApplicationContext(ApplicationContext ctx) throws BeansException {
-            if (bus == null) {
-                bus = BusWiringBeanFactoryPostProcessor.addDefaultBus(ctx);
+            if (getBus() == null) {
+                setBus(BusWiringBeanFactoryPostProcessor.addDefaultBus(ctx));
             }
         }
 
diff --git a/rt/transports/http-undertow/src/main/java/org/apache/cxf/transport/http_undertow/UndertowHTTPServerEngine.java b/rt/transports/http-undertow/src/main/java/org/apache/cxf/transport/http_undertow/UndertowHTTPServerEngine.java
index e684f6f..b8971ba 100644
--- a/rt/transports/http-undertow/src/main/java/org/apache/cxf/transport/http_undertow/UndertowHTTPServerEngine.java
+++ b/rt/transports/http-undertow/src/main/java/org/apache/cxf/transport/http_undertow/UndertowHTTPServerEngine.java
@@ -43,6 +43,7 @@ import org.apache.cxf.common.util.SystemPropertyAction;
 import org.apache.cxf.configuration.jsse.TLSServerParameters;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.transport.HttpUriMapper;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
 import org.apache.cxf.transport.https.AliasedX509ExtendedKeyManager;
 import org.xnio.Options;
 import org.xnio.Sequence;
@@ -64,10 +65,14 @@ import io.undertow.servlet.handlers.ServletPathMatches;
 import io.undertow.util.CopyOnWriteMap;
 
 
-public class UndertowHTTPServerEngine implements ServerEngine {
+public class UndertowHTTPServerEngine implements ServerEngine, HttpServerEngineSupport {
 
     public static final String DO_NOT_CHECK_URL_PROP = "org.apache.cxf.transports.http_undertow.DontCheckUrl";
     
+    /**
+     * Please use {@link HttpServerEngineSupport#ENABLE_HTTP2} instead.
+     */
+    @Deprecated
     public static final String ENABLE_HTTP2_PROP = "org.apache.cxf.transports.http_undertow.EnableHttp2";
     
     public static final String ENABLE_RECORD_REQUEST_START_TIME_PROP = 
@@ -183,6 +188,17 @@ public class UndertowHTTPServerEngine implements ServerEngine {
         servantCount = servantCount + 1;
     }
 
+    @Override
+    public boolean isHttp2Enabled(Bus bus) {
+        Object prop = null;
+        if (bus != null) {
+            prop = bus.getProperty(ENABLE_HTTP2_PROP);
+        }
+        if (prop == null) {
+            prop = SystemPropertyAction.getPropertyOrNull(ENABLE_HTTP2_PROP);
+        }
+        return PropertyUtils.isTrue(prop) || HttpServerEngineSupport.super.isHttp2Enabled(bus);
+    }
 
     private ServletContext buildServletContext(String contextName)
         throws ServletException {
@@ -203,7 +219,7 @@ public class UndertowHTTPServerEngine implements ServerEngine {
     private Undertow createServer(URL url, UndertowHTTPHandler undertowHTTPHandler) throws Exception {
         Undertow.Builder result = Undertow.builder();
         result.setServerOption(UndertowOptions.IDLE_TIMEOUT, getMaxIdleTime());
-        if (this.shouldEnableHttp2(undertowHTTPHandler.getBus())) {
+        if (this.isHttp2Enabled(undertowHTTPHandler.getBus())) {
             result.setServerOption(UndertowOptions.ENABLE_HTTP2, Boolean.TRUE);
         }
         if (this.shouldEnableRecordRequestStartTime(undertowHTTPHandler.getBus())) {
@@ -313,18 +329,6 @@ public class UndertowHTTPServerEngine implements ServerEngine {
         return !PropertyUtils.isTrue(prop);
     }
     
-    private boolean shouldEnableHttp2(Bus bus) {
-
-        Object prop = null;
-        if (bus != null) {
-            prop = bus.getProperty(ENABLE_HTTP2_PROP);
-        }
-        if (prop == null) {
-            prop = SystemPropertyAction.getPropertyOrNull(ENABLE_HTTP2_PROP);
-        }
-        return PropertyUtils.isTrue(prop);
-    }
-    
     private boolean shouldEnableRecordRequestStartTime(Bus bus) {
 
         Object prop = null;
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpServerEngineSupport.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpServerEngineSupport.java
new file mode 100644
index 0000000..fd4762e
--- /dev/null
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/http/HttpServerEngineSupport.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.transport.http;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.PropertyUtils;
+import org.apache.cxf.common.util.SystemPropertyAction;
+
+/**
+ * Support class for HTTP server engines: holds common properties and commonly
+ * used methods, shared across all HTTP server engine implementations (Tomcat, Jetty,
+ * Undertow, Netty, ...).
+ */
+public interface HttpServerEngineSupport {
+    String ENABLE_HTTP2 = "org.apache.cxf.transports.http2.enabled";
+    
+    default boolean isHttp2Enabled(Bus bus) {
+        Object value = null;
+        
+        if (bus != null) {
+            value = bus.getProperty(ENABLE_HTTP2);
+        }
+        
+        if (value == null) {
+            value = SystemPropertyAction.getPropertyOrNull(ENABLE_HTTP2);
+        }
+        
+        return PropertyUtils.isTrue(value);
+    }
+}
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLContextInitParameters.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLContextInitParameters.java
new file mode 100644
index 0000000..2182962
--- /dev/null
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLContextInitParameters.java
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.transport.https;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.TrustManager;
+
+public final class SSLContextInitParameters {
+    private KeyManager[] keyManagers;
+    private TrustManager[] trustManagers;
+
+    public void setKeyManagers(KeyManager[] keyManagers) {
+        this.keyManagers = keyManagers; 
+    }
+    
+    public KeyManager[] getKeyManagers() {
+        return keyManagers;
+    }
+
+    public void setTrustManagers(TrustManager[] trustManagers) {
+        this.trustManagers = trustManagers;
+    }
+    
+    public TrustManager[] getTrustManagers() {
+        return trustManagers;
+    }
+}
diff --git a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
index 49242ac..f43253f 100644
--- a/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
+++ b/rt/transports/http/src/main/java/org/apache/cxf/transport/https/SSLUtils.java
@@ -59,16 +59,11 @@ public final class SSLUtils {
         }
         return verifier;
     }
-
-    public static SSLContext getSSLContext(TLSParameterBase parameters) throws GeneralSecurityException {
-        // TODO do we need to cache the context
-        String provider = parameters.getJsseProvider();
-
-        String protocol = parameters.getSecureSocketProtocol() != null ? parameters
-            .getSecureSocketProtocol() : "TLS";
-
-        SSLContext ctx = provider == null ? SSLContext.getInstance(protocol) : SSLContext
-            .getInstance(protocol, provider);
+    
+    public static SSLContextInitParameters getSSLContextInitParameters(TLSParameterBase parameters) 
+            throws GeneralSecurityException {
+        
+        final SSLContextInitParameters contextParameters = new SSLContextInitParameters();
 
         KeyManager[] keyManagers = parameters.getKeyManagers();
         if (keyManagers == null && parameters instanceof TLSClientParameters) {
@@ -80,8 +75,25 @@ public final class SSLUtils {
         if (trustManagers == null && parameters instanceof TLSClientParameters) {
             trustManagers = org.apache.cxf.configuration.jsse.SSLUtils.getDefaultTrustStoreManagers(LOG);
         }
+        
+        contextParameters.setKeyManagers(configuredKeyManagers);
+        contextParameters.setTrustManagers(trustManagers);
+        
+        return contextParameters;
+    }
+
+    public static SSLContext getSSLContext(TLSParameterBase parameters) throws GeneralSecurityException {
+        // TODO do we need to cache the context
+        String provider = parameters.getJsseProvider();
+
+        String protocol = parameters.getSecureSocketProtocol() != null ? parameters
+            .getSecureSocketProtocol() : "TLS";
+
+        SSLContext ctx = provider == null ? SSLContext.getInstance(protocol) : SSLContext
+            .getInstance(protocol, provider);
 
-        ctx.init(configuredKeyManagers, trustManagers, parameters.getSecureRandom());
+        final SSLContextInitParameters initParams = getSSLContextInitParameters(parameters);
+        ctx.init(initParams.getKeyManagers(), initParams.getTrustManagers(), parameters.getSecureRandom());
 
         if (parameters instanceof TLSClientParameters && ctx.getClientSessionContext() != null) {
             ctx.getClientSessionContext().setSessionTimeout(((TLSClientParameters)parameters).getSslCacheTimeout());
diff --git a/systests/pom.xml b/systests/pom.xml
index 5ab0ee1..eb29fa8 100644
--- a/systests/pom.xml
+++ b/systests/pom.xml
@@ -55,5 +55,6 @@
         <module>rs-sse</module>
         <module>microprofile</module>
         <module>spring-boot</module>
+        <module>transport-netty</module>
     </modules>
 </project>
diff --git a/systests/transports/pom.xml b/systests/transport-netty/pom.xml
similarity index 51%
copy from systests/transports/pom.xml
copy to systests/transport-netty/pom.xml
index a7f4ec6..f5aa5f5 100644
--- a/systests/transports/pom.xml
+++ b/systests/transport-netty/pom.xml
@@ -26,14 +26,15 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.cxf.systests</groupId>
-    <artifactId>cxf-systests-transports</artifactId>
-    <name>Apache CXF Transport System Tests</name>
-    <description>Apache CXF Transport System Tests</description>
+    <artifactId>cxf-systests-transport-netty</artifactId>
+    <name>Apache CXF Netty Transport System Tests</name>
+    <description>Apache CXF Netty Transport System Tests</description>
     <url>https://cxf.apache.org</url>
+    
     <properties>
-        <cxf.surefire.fork.vmargs>-Djdk.http.auth.tunneling.disabledSchemes=""</cxf.surefire.fork.vmargs>
-        <cxf.module.name>org.apache.cxf.systests.transport</cxf.module.name>
+        <cxf.module.name>org.apache.cxf.systests.transport.netty</cxf.module.name>
     </properties>
+    
     <build>
         <testSourceDirectory>${basedir}/src/test/java</testSourceDirectory>
         <testResources>
@@ -103,63 +104,38 @@
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-frontend-jaxws</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-frontend-js</artifactId>
+            <artifactId>cxf-rt-transports-http</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-bindings-soap</artifactId>
+            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-databinding-aegis</artifactId>
+            <artifactId>cxf-rt-rs-client</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-transports-http</artifactId>
-            <version>${project.version}</version>
+            <groupId>com.fasterxml.jackson.jaxrs</groupId>
+            <artifactId>jackson-jaxrs-json-provider</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-transports-http-hc</artifactId>
-            <version>${project.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>jcl-over-slf4j</artifactId>
-                </exclusion>
-            </exclusions>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-transports-udp</artifactId>
+            <artifactId>cxf-rt-rs-extension-providers</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-servlet</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-webapp</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-transports-http-jetty</artifactId>
+            <artifactId>cxf-rt-transports-http-netty-server</artifactId>
             <version>${project.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>javax.servlet-api</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
@@ -173,188 +149,55 @@
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-transports-local</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-ws-policy</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-features-logging</artifactId>
+            <artifactId>cxf-testutils</artifactId>
             <version>${project.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
             <artifactId>cxf-testutils</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
+            <classifier>keys</classifier>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-testutils</artifactId>
+            <artifactId>cxf-rt-features-logging</artifactId>
             <version>${project.version}</version>
             <scope>test</scope>
-            <classifier>keys</classifier>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-web</artifactId>
-            <scope>test</scope>
             <version>${cxf.spring.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-webmvc</artifactId>
             <scope>test</scope>
-            <version>${cxf.spring.version}</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-beans</artifactId>
-            <scope>test</scope>
             <version>${cxf.spring.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-context</artifactId>
-            <scope>test</scope>
             <version>${cxf.spring.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>httpunit</groupId>
-            <artifactId>httpunit</artifactId>
-            <version>1.7</version>
             <scope>test</scope>
-            <exclusions>
-                <exclusion>
-                    <groupId>javax.servlet</groupId>
-                    <artifactId>servlet-api</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>xerces</groupId>
-                    <artifactId>xercesImpl</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>xerces</groupId>
-                    <artifactId>xmlParserAPIs</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>${cxf.spring.mock}</artifactId>
-            <version>${cxf.spring.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-config</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-web</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <version>${cxf.spring.boot.version}</version>
-            <scope>test</scope>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter-logging</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <version>${cxf.spring.boot.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-rs-client</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.geronimo.specs</groupId>
-            <artifactId>geronimo-j2ee-connector_1.5_spec</artifactId>
-        </dependency>
-        <!-- make http://java.sun.com/dtd/web-app_2_3.dtd et al locally available during the tests -->
-        <dependency>
-            <groupId>${cxf.servlet-api.group}</groupId>
-            <artifactId>${cxf.servlet-api.artifact}</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.mozilla</groupId>
-            <artifactId>rhino</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <!-- This needs to be here as httpunit requires some classes that are only in 1.7R2 or lower -->
-            <groupId>rhino</groupId>
-            <artifactId>js</artifactId>
-            <version>1.7R2</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.codehaus.jettison</groupId>
-            <artifactId>jettison</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.littleshoot</groupId>
-            <artifactId>littleproxy</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jaxb</groupId>
-            <artifactId>jaxb-xjc</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.bouncycastle</groupId>
-            <artifactId>bctls-jdk15on</artifactId>
-            <version>${cxf.bcprov.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.junit.vintage</groupId>
-            <artifactId>junit-vintage-engine</artifactId>
-            <version>${cxf.junit5.version}</version>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-codec-http2</artifactId>
+            <version>${cxf.netty.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
-
-    <profiles>
-        <profile>
-            <id>jdk16</id>
-            <activation>
-                <jdk>[16,)</jdk>
-            </activation>
-            <properties>
-                <cxf.surefire.fork.vmargs>--add-opens java.xml/com.sun.org.apache.xerces.internal.dom=ALL-UNNAMED -Djdk.http.auth.tunneling.disabledSchemes=""</cxf.surefire.fork.vmargs>
-            </properties>
-        </profile>
-    </profiles>
 </project>
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractBookServerHttp2.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractBookServerHttp2.java
new file mode 100644
index 0000000..1a07c9d
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractBookServerHttp2.java
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.customer.book.Book;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.provider.StreamingResponseProvider;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+abstract class AbstractBookServerHttp2 extends AbstractBusTestServerBase {
+    org.apache.cxf.endpoint.Server server;
+
+    private final String port;
+    private final String context;
+    private final String scheme;
+
+    AbstractBookServerHttp2(String port, String context, String scheme) {
+        this.port = port;
+        this.context = context;
+        this.scheme = scheme;
+    }
+
+    protected void run() {
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus(context);
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        setBus(bus);
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setBus(bus);
+        sf.setResourceClasses(BookStore.class);
+        sf.setProvider(new StreamingResponseProvider<Book>());
+        sf.setResourceProvider(BookStore.class,
+            new SingletonResourceProvider(new BookStore(), true));
+        sf.setAddress(scheme + "://localhost:" + port + "/http2");
+        server = sf.create();
+    }
+
+    public void tearDown() throws Exception {
+        server.stop();
+        server.destroy();
+        server = null;
+    }
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
new file mode 100644
index 0000000..1263377
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/AbstractNettyClientServerHttp2Test.java
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.systest.http2.netty.Http2TestClient.ClientResponse;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.https.InsecureTrustManager;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+abstract class AbstractNettyClientServerHttp2Test extends AbstractBusClientServerTestBase {
+    @Test
+    public void testBookNotFoundWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/notFound")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(404));
+        assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+    }
+    
+    @Test
+    public void testBookWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/booknames")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+        assertEquals("CXF in Action", response.getBody());
+    }
+
+    @Test
+    public void testGetBookStreamHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("application/xml")
+            .path(getContext() + "/web/bookstore/bookstream")
+            .http2()
+            .get();
+
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo("HTTP/2.0"));
+        assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+            + "<Book><id>1</id><name>Book1</name></Book>", response.getBody());
+    }
+
+    @Test
+    public void testBookWithHttp() throws Exception {
+        final WebClient wc = WebClient
+            .create(getAddress() + getContext() + "/web/bookstore/booknames")
+            .accept("text/plain");
+        
+        if (isSecure()) {
+            final HTTPConduit conduit = WebClient.getConfig(wc).getHttpConduit();
+            TLSClientParameters params = conduit.getTlsClientParameters();
+
+            if (params == null)  {
+                params = new TLSClientParameters();
+                conduit.setTlsClientParameters(params);
+            }
+
+            // Create TrustManager instance which trusts all clients and servers
+            params.setTrustManagers(InsecureTrustManager.getNoOpX509TrustManagers()); 
+            params.setDisableCNCheck(true);
+        }
+        
+        try (Response resp = wc.get()) {
+            assertThat(resp.getStatus(), equalTo(200));
+            assertEquals("CXF in Action", resp.readEntity(String.class));
+        }
+    }
+
+    protected abstract String getAddress();
+    protected abstract String getContext();
+
+    protected boolean isSecure() {
+        return getAddress().startsWith("https");
+    }
+}
\ No newline at end of file
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Book.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Book.java
new file mode 100644
index 0000000..9d95c5d
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Book.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "class")
+@XmlRootElement(name = "Book")
+public class Book {
+    private String name;
+    private long id;
+
+    public Book() {
+    }
+
+    public Book(String name, long id) {
+        this.name = name;
+        this.id = id;
+    }
+
+    public void setName(String n) {
+        name = n;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setId(long i) {
+        id = i;
+    }
+    public long getId() {
+        return id;
+    }
+
+    @PUT
+    public void cloneState(Book book) {
+        id = book.getId();
+        name = book.getName();
+    }
+
+    @GET
+    public Book retrieveState() {
+        return this;
+    }
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2.java
new file mode 100644
index 0000000..51be2c2
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+public class BookServerHttp2 extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2.class);
+
+    org.apache.cxf.endpoint.Server server;
+
+    public BookServerHttp2() {
+        this(PORT);
+    }
+
+    public BookServerHttp2(String port) {
+        super(port, "org/apache/cxf/systest/http2_netty/server-tls.xml", "https");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2 s = new BookServerHttp2();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2c.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2c.java
new file mode 100644
index 0000000..73ca51c
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookServerHttp2c.java
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+public class BookServerHttp2c extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2c.class);
+
+    public BookServerHttp2c() {
+        this(PORT);
+    }
+
+    public BookServerHttp2c(String port) {
+        super(port, "org/apache/cxf/systest/http2_netty/server.xml", "http");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2c s = new BookServerHttp2c();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookStore.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookStore.java
new file mode 100644
index 0000000..4b4e1ca
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/BookStore.java
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import org.apache.cxf.jaxrs.ext.StreamingResponse;
+
+@Path("/web/bookstore")
+public class BookStore {
+    private static ExecutorService executor = Executors.newSingleThreadExecutor();
+
+    @GET
+    @Path("/booknames")
+    @Produces("text/plain")
+    public byte[] getBookName() {
+        return "CXF in Action".getBytes();
+    }
+
+    @GET
+    @Path("/bookstream")
+    @Produces("application/xml")
+    public StreamingResponse<Book> getBookStream() {
+        return new StreamingResponse<Book>() {
+            public void writeTo(final StreamingResponse.Writer<Book> out) throws IOException {
+                out.write(new Book("Book1", 1));
+                executor.execute(new Runnable() {
+                    public void run() {
+                        try {
+                            for (int i = 2; i <= 5; i++) {
+                                Thread.sleep(500);
+                                out.write(new Book("Book" + i, i));
+                                out.getEntityStream().flush();
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        };
+    }
+}
+
+
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
new file mode 100644
index 0000000..32e4e64
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/Http2TestClient.java
@@ -0,0 +1,401 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.core.MediaType;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.DefaultFullHttpRequest;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpClientUpgradeHandler;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.HttpVersion;
+import io.netty.handler.codec.http2.DefaultHttp2Connection;
+import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
+import io.netty.handler.codec.http2.Http2ClientUpgradeCodec;
+import io.netty.handler.codec.http2.Http2Connection;
+import io.netty.handler.codec.http2.Http2ConnectionHandler;
+import io.netty.handler.codec.http2.Http2SecurityUtil;
+import io.netty.handler.codec.http2.Http2Settings;
+import io.netty.handler.codec.http2.HttpConversionUtil;
+import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
+import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
+import io.netty.handler.ssl.ApplicationProtocolConfig;
+import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
+import io.netty.handler.ssl.ApplicationProtocolNames;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
+import io.netty.handler.ssl.SupportedCipherSuiteFilter;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import io.netty.util.internal.PlatformDependent;
+
+/**
+ * TODO: Use CXF client once https://issues.apache.org/jira/browse/CXF-8606 is dones
+ */
+public class Http2TestClient implements AutoCloseable {
+    private final SslContext ssl;
+    
+    public Http2TestClient(boolean secure) throws Exception {
+        if (secure) {
+            ssl = SslContext.newClientContext(
+                SslProvider.JDK,
+                null, 
+                InsecureTrustManagerFactory.INSTANCE,
+                Http2SecurityUtil.CIPHERS,
+                SupportedCipherSuiteFilter.INSTANCE,
+                new ApplicationProtocolConfig(
+                        Protocol.ALPN,
+                        SelectorFailureBehavior.FATAL_ALERT,
+                        SelectedListenerFailureBehavior.FATAL_ALERT,
+                        ApplicationProtocolNames.HTTP_2,
+                        ApplicationProtocolNames.HTTP_1_1),
+                0, 0);
+        } else {
+            ssl = null;
+        }
+    }
+    
+    public static class ClientResponse {
+        private String body;
+        private String protocol;
+        private int responseCode;
+        
+        public ClientResponse(int responseCode, String protocol) {
+            this.responseCode = responseCode;
+            this.protocol = protocol;
+        }
+
+        public void setBody(String body) {
+            this.body = body;
+        }
+        
+        public String getBody() {
+            return body;
+        }
+        
+        public void setResponseCode(int rc) {
+            this.responseCode = rc;
+        }
+
+        public int getResponseCode() {
+            return responseCode;
+        }
+
+        public String getProtocol() {
+            return protocol;
+        }
+        
+        public void setProtocol(String protocol) {
+            this.protocol = protocol;
+        }
+    }
+    
+    public class RequestBuilder {
+        private final String address;
+        private String path = "";
+        private String accept = MediaType.WILDCARD;
+        private HttpVersion version = HttpVersion.HTTP_1_1;
+
+        public RequestBuilder(final String address) {
+            this.address = address;
+        }
+        
+        public RequestBuilder path(final String p) {
+            this.path = p;
+            return this;
+        }
+        
+        
+        public RequestBuilder accept(final String a) {
+            this.accept = a;
+            return this;
+        }
+        
+        public RequestBuilder http2() {
+            version = null;
+            return this;
+        }
+        
+        public ClientResponse get() throws Exception {
+            return request(address, path, version, HttpMethod.GET, accept);
+        }
+    }
+    
+    public RequestBuilder request(final String address) throws IOException {
+        return new RequestBuilder(address);
+    }
+
+    public ClientResponse request(final String address, final String path, 
+            final HttpVersion version, final HttpMethod method, final String accept) 
+                throws Exception {
+
+        final URI uri = URI.create(address);
+                
+        final Http2ClientInitializer initializer = new Http2ClientInitializer(Integer.MAX_VALUE);
+        final NioEventLoopGroup worker = new NioEventLoopGroup();
+        
+        final Bootstrap bootstrap = new Bootstrap();
+        bootstrap.group(worker);
+        bootstrap.channel(NioSocketChannel.class);
+        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
+        bootstrap.remoteAddress(uri.getHost(), uri.getPort());
+        bootstrap.handler(initializer);
+
+        final Channel channel = bootstrap.connect().syncUninterruptibly().channel();
+        final HttpResponseHandler responseHandler = initializer.getResponseHandler();
+        final Http2SettingsHandler http2SettingsHandler = initializer.getSettingsHandler();
+
+        try {
+            final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, path);
+            request.headers().add(HttpHeaderNames.HOST, uri.getHost());
+            request.headers().add(HttpHeaderNames.ACCEPT, accept);
+            request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), uri.getScheme());
+
+            http2SettingsHandler.awaitSettings(5, TimeUnit.SECONDS);
+            responseHandler.put(3, channel.write(request), channel.newPromise());
+            
+            channel.flush();
+            responseHandler.awaitResponses(15, TimeUnit.SECONDS);
+        } finally {
+            channel.close().awaitUninterruptibly();
+            worker.shutdownGracefully();
+        }
+        
+        
+        final List<ClientResponse> responses = responseHandler.responses();
+        if (responses.size() != 1) {
+            throw new IllegalStateException("Expected exactly one response, but got 0 or more");
+        }
+        
+        return responses.get(0);
+    }
+    
+    @Override
+    public void close() throws Exception {
+    }
+    
+    private class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
+        private ChannelPromise promise;
+
+        Http2SettingsHandler(ChannelPromise promise) {
+            this.promise = promise;
+        }
+
+        /**
+         * Wait for this handler to be added after the upgrade to HTTP/2, and for initial preface
+         * handshake to complete.
+         */
+        void awaitSettings(long timeout, TimeUnit unit) throws Exception {
+            if (!promise.awaitUninterruptibly(timeout, unit)) {
+                throw new IllegalStateException("Timed out waiting for settings");
+            }
+            if (!promise.isSuccess()) {
+                throw new RuntimeException(promise.cause());
+            }
+        }
+        
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception {
+            promise.setSuccess();
+            ctx.pipeline().remove(this);
+        }
+    }
+    
+    private class HttpResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
+        private final Map<Integer, Entry<ChannelFuture, ChannelPromise>> streamidPromiseMap;
+        private final List<ClientResponse> responses = new CopyOnWriteArrayList<>(); 
+        
+        HttpResponseHandler() {
+            streamidPromiseMap = PlatformDependent.newConcurrentHashMap();
+        }
+
+        Entry<ChannelFuture, ChannelPromise> put(int streamId, ChannelFuture writeFuture, ChannelPromise promise) {
+            return streamidPromiseMap.put(streamId, new SimpleEntry<>(writeFuture, promise));
+        }
+
+        void awaitResponses(long timeout, TimeUnit unit) {
+            final Iterator<Entry<Integer, Entry<ChannelFuture, ChannelPromise>>> itr = streamidPromiseMap
+                .entrySet()
+                .iterator();
+            
+            while (itr.hasNext()) {
+                final Entry<Integer, Entry<ChannelFuture, ChannelPromise>> entry = itr.next();
+
+                final ChannelFuture writeFuture = entry.getValue().getKey();
+                if (!writeFuture.awaitUninterruptibly(timeout, unit)) {
+                    throw new IllegalStateException("Timed out waiting to write for stream id " + entry.getKey());
+                }
+                
+                if (!writeFuture.isSuccess()) {
+                    throw new RuntimeException(writeFuture.cause());
+                }
+                
+                final ChannelPromise promise = entry.getValue().getValue();
+                if (!promise.awaitUninterruptibly(timeout, unit)) {
+                    throw new IllegalStateException("Timed out waiting for response on stream id " + entry.getKey());
+                }
+                
+                if (!promise.isSuccess()) {
+                    throw new RuntimeException(promise.cause());
+                }
+
+                itr.remove();
+            }
+        }
+        
+        List<ClientResponse> responses() {
+            return responses;
+        }
+
+        @Override
+        protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
+            Integer streamId = msg.headers().getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
+            if (streamId == null) {
+                System.err.println("HttpResponseHandler unexpected message received: " + msg);
+                return;
+            }
+
+            final Entry<ChannelFuture, ChannelPromise> entry = streamidPromiseMap.get(streamId);
+            if (entry == null) {
+                System.err.println("Message received for unknown stream id " + streamId);
+            } else {
+                final ByteBuf content = msg.content();
+                final ClientResponse response = new ClientResponse(msg.status().code(), "HTTP/2.0");
+                
+                if (content.isReadable()) {
+                    int contentLength = content.readableBytes();
+                    byte[] arr = new byte[contentLength];
+                    content.readBytes(arr);
+                    response.setBody(new String(arr));
+                }
+
+                responses.add(response);
+                entry.getValue().setSuccess();
+            }
+        }
+    }
+    
+    private class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
+        private final int maxContentLength;
+        private HttpResponseHandler responseHandler;
+        private Http2SettingsHandler settingsHandler;
+        private Http2ConnectionHandler connectionHandler;
+
+        Http2ClientInitializer(int maxContentLength) {
+            this.maxContentLength = maxContentLength;
+        }
+
+        @Override
+        public void initChannel(SocketChannel ch) throws Exception {
+            final Http2Connection connection = new DefaultHttp2Connection(false);
+
+            responseHandler = new HttpResponseHandler();
+            settingsHandler = new Http2SettingsHandler(ch.newPromise());
+            
+            connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
+                .connection(connection)
+                .frameListener(new DelegatingDecompressorFrameListener(connection,
+                    new InboundHttp2ToHttpAdapterBuilder(connection)
+                        .maxContentLength(maxContentLength)
+                        .propagateSettings(true)
+                        .build()))
+                .build();
+
+            if (ssl != null) {
+                ch.pipeline().addLast(ssl.newHandler(ch.alloc()));
+                ch.pipeline().addLast(connectionHandler);
+                ch.pipeline().addLast(settingsHandler);
+                ch.pipeline().addLast(responseHandler);
+            } else {
+                final HttpClientCodec sourceCodec = new HttpClientCodec();
+                final Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(connectionHandler);
+                final HttpClientUpgradeHandler upgradeHandler = new HttpClientUpgradeHandler(sourceCodec, 
+                    upgradeCodec, 65536);
+
+                ch.pipeline().addLast(sourceCodec);
+                ch.pipeline().addLast(upgradeHandler);
+                ch.pipeline().addLast(new UpgradeRequestHandler(settingsHandler, responseHandler));
+            }
+        }
+        
+        HttpResponseHandler getResponseHandler() {
+            return responseHandler;
+        }
+        
+        Http2SettingsHandler getSettingsHandler() {
+            return settingsHandler;
+        }
+    }
+    
+    /**
+     * A handler that triggers the cleartext upgrade to HTTP/2 by sending an 
+     * initial HTTP request.
+     */
+    private class UpgradeRequestHandler extends ChannelInboundHandlerAdapter {
+        private final Http2SettingsHandler settingsHandler;
+        private final HttpResponseHandler responseHandler;
+
+        UpgradeRequestHandler(final Http2SettingsHandler settingsHandler, final HttpResponseHandler responseHandler) {
+            this.settingsHandler = settingsHandler;
+            this.responseHandler = responseHandler;
+        }
+        
+        @Override
+        public void channelActive(ChannelHandlerContext ctx) throws Exception {
+            final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");
+            request.headers().add(HttpHeaderNames.HOST, "localhost");
+            request.headers().add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), "http");
+
+            ctx.writeAndFlush(request);
+            ctx.fireChannelActive();
+            
+            ctx.pipeline().remove(this);
+            ctx.pipeline().addLast(settingsHandler);
+            ctx.pipeline().addLast(responseHandler);
+        }
+    }
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2Test.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2Test.java
new file mode 100644
index 0000000..d29fe7a
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2Test.java
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class NettyClientServerHttp2Test extends AbstractNettyClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2()));
+        createStaticBus();
+    }
+
+    
+    @Override
+    protected String getAddress() {
+        return "https://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2cTest.java b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2cTest.java
new file mode 100644
index 0000000..b7d7f5a
--- /dev/null
+++ b/systests/transport-netty/src/test/java/org/apache/cxf/systest/http2/netty/NettyClientServerHttp2cTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2.netty;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class NettyClientServerHttp2cTest extends AbstractNettyClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2c.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2c()));
+        createStaticBus();
+    }
+
+    @Override
+    protected String getAddress() {
+        return "http://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server-tls.xml b/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server-tls.xml
new file mode 100644
index 0000000..dd9ebf7
--- /dev/null
+++ b/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server-tls.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-netty="http://cxf.apache.org/transports/http-netty-server/configuration"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-netty-server/configuration 
+        http://cxf.apache.org/schemas/configuration/http-netty-server.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://cxf.apache.org/configuration/security 
+        http://cxf.apache.org/schemas/configuration/security.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-netty:engine-factory bus="cxf">
+        <http-netty:engine port="${testutil.ports.org.apache.cxf.systest.http2.netty.BookServerHttp2}">
+            <http-netty:tlsServerParameters>
+                <sec:keyManagers keyPassword="password">
+                    <sec:keyStore type="jks" password="password" resource="keys/Bethal.jks"/>
+                </sec:keyManagers>
+                <sec:clientAuthentication want="false" required="false"/>
+            </http-netty:tlsServerParameters>
+        </http-netty:engine>
+    </http-netty:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server.xml b/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server.xml
new file mode 100644
index 0000000..5ff63d1
--- /dev/null
+++ b/systests/transport-netty/src/test/resources/org/apache/cxf/systest/http2_netty/server.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-netty="http://cxf.apache.org/transports/http-netty-server/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-netty-server/configuration 
+        http://cxf.apache.org/schemas/configuration/http-netty-server.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-netty:engine-factory bus="cxf">
+        <http-netty:engine port="${testutil.ports.org.apache.cxf.systest.http2.netty.BookServerHttp2c}">
+        </http-netty:engine>
+    </http-netty:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractBookServerHttp2.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractBookServerHttp2.java
new file mode 100644
index 0000000..e6601db
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractBookServerHttp2.java
@@ -0,0 +1,66 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.customer.book.Book;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.provider.StreamingResponseProvider;
+import org.apache.cxf.systest.http_undertow.websocket.BookStorePerRequest;
+import org.apache.cxf.systest.http_undertow.websocket.BookStoreWebSocket;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+abstract class AbstractBookServerHttp2 extends AbstractBusTestServerBase {
+    org.apache.cxf.endpoint.Server server;
+
+    private final String port;
+    private final String scheme;
+    private final String context;
+
+    AbstractBookServerHttp2(String port, String context, String scheme) {
+        this.port = port;
+        this.context = context;
+        this.scheme = scheme;
+    }
+
+    protected void run() {
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus(context);
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        setBus(bus);
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setBus(bus);
+        sf.setResourceClasses(BookStoreWebSocket.class, BookStorePerRequest.class);
+        sf.setProvider(new StreamingResponseProvider<Book>());
+        sf.setResourceProvider(BookStoreWebSocket.class,
+            new SingletonResourceProvider(new BookStoreWebSocket(), true));
+        sf.setAddress(scheme + "://localhost:" + port + "/http2");
+        server = sf.create();
+    }
+
+    public void tearDown() throws Exception {
+        server.stop();
+        server.destroy();
+        server = null;
+    }
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractUndertowClientServerHttp2Test.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractUndertowClientServerHttp2Test.java
new file mode 100644
index 0000000..c3b3470
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/AbstractUndertowClientServerHttp2Test.java
@@ -0,0 +1,120 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.https.InsecureTrustManager;
+
+import io.undertow.client.ClientResponse;
+import io.undertow.util.Protocols;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+abstract class AbstractUndertowClientServerHttp2Test extends AbstractBusClientServerTestBase {
+    @Test
+    public void testBookNotFoundWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/notFound")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(404));
+        assertThat(response.getProtocol(), equalTo(Protocols.HTTP_2_0));
+    }
+    
+    @Test
+    public void testBookWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/booknames")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo(Protocols.HTTP_2_0));
+        assertEquals("CXF in Action", client.getBody(response));
+    }
+
+    @Test
+    public void testGetBookStreamHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("application/json")
+            .path(getContext() + "/web/bookstore/bookstream")
+            .http2()
+            .get();
+
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo(Protocols.HTTP_2_0));
+        assertEquals("{\"Book\":{\"id\":1,\"name\":\"WebSocket1\"}}", 
+            client.getBody(response));
+    }
+
+    @Test
+    public void testBookWithHttp() throws Exception {
+        final WebClient wc = WebClient
+            .create(getAddress() + getContext() + "/web/bookstore/booknames")
+            .accept("text/plain");
+        
+        if (isSecure()) {
+            final HTTPConduit conduit = WebClient.getConfig(wc).getHttpConduit();
+            TLSClientParameters params = conduit.getTlsClientParameters();
+
+            if (params == null)  {
+                params = new TLSClientParameters();
+                conduit.setTlsClientParameters(params);
+            }
+
+            // Create TrustManager instance which trusts all clients and servers
+            params.setTrustManagers(InsecureTrustManager.getNoOpX509TrustManagers()); 
+            params.setDisableCNCheck(true);
+        }
+        
+        try (Response resp = wc.get()) {
+            assertThat(resp.getStatus(), equalTo(200));
+            assertEquals("CXF in Action", resp.readEntity(String.class));
+        }
+    }
+
+    protected abstract String getAddress();
+    protected abstract String getContext();
+
+    protected boolean isSecure() {
+        return getAddress().startsWith("https");
+    }
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2.java
new file mode 100644
index 0000000..a1f7872c
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2.java
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+public class BookServerHttp2 extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2.class);
+
+    public BookServerHttp2() {
+        this(PORT);
+    }
+
+    public BookServerHttp2(String port) {
+        super(port, "org/apache/cxf/systest/http_undertow/http2/server-tls.xml", "https");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2 s = new BookServerHttp2();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2c.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2c.java
new file mode 100644
index 0000000..d3e02b4
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/BookServerHttp2c.java
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+public class BookServerHttp2c extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2c.class);
+
+    public BookServerHttp2c() {
+        this(PORT);
+    }
+
+    public BookServerHttp2c(String port) {
+        super(port, "org/apache/cxf/systest/http_undertow/http2/server.xml", "http");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2c s = new BookServerHttp2c();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/Http2TestClient.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/Http2TestClient.java
new file mode 100644
index 0000000..6d8ed7d
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/Http2TestClient.java
@@ -0,0 +1,184 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.cxf.transport.https.InsecureTrustManager;
+import org.xnio.IoUtils;
+import org.xnio.OptionMap;
+import org.xnio.Options;
+import org.xnio.Xnio;
+import org.xnio.XnioWorker;
+
+import io.undertow.UndertowOptions;
+import io.undertow.client.ClientCallback;
+import io.undertow.client.ClientConnection;
+import io.undertow.client.ClientExchange;
+import io.undertow.client.ClientRequest;
+import io.undertow.client.ClientResponse;
+import io.undertow.client.UndertowClient;
+import io.undertow.connector.ByteBufferPool;
+import io.undertow.protocols.ssl.UndertowXnioSsl;
+import io.undertow.server.DefaultByteBufferPool;
+import io.undertow.util.AttachmentKey;
+import io.undertow.util.Headers;
+import io.undertow.util.HttpString;
+import io.undertow.util.Methods;
+import io.undertow.util.StringReadChannelListener;
+
+/**
+ * TODO: Use CXF client once https://issues.apache.org/jira/browse/CXF-8606 is dones
+ */
+public class Http2TestClient {
+    private static final int BUFFER_SIZE = Integer.getInteger("test.bufferSize", 1024 * 16 - 20);
+    private static final AttachmentKey<String> RESPONSE_BODY = AttachmentKey.create(String.class);
+    
+    private final UndertowClient client;
+    private final UndertowXnioSsl ssl;
+    private final XnioWorker worker;
+    private final ByteBufferPool pool;
+    
+    public Http2TestClient(boolean secure) throws Exception {
+        client = UndertowClient.getInstance();
+        
+        final Xnio xnio = Xnio.getInstance();
+        worker = xnio.createWorker(null,  
+            OptionMap.builder()
+                .set(Options.WORKER_IO_THREADS, 8)
+                .set(Options.TCP_NODELAY, true)
+                .set(Options.KEEP_ALIVE, true)
+                .set(Options.WORKER_NAME, "TestClient")
+                .getMap());
+        
+        pool = new DefaultByteBufferPool(true, BUFFER_SIZE, 1000, 10, 100);
+        if (secure) {
+            final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
+            sslContext.init(new KeyManager[] {}, InsecureTrustManager.getNoOpX509TrustManagers(), null);
+            ssl = new UndertowXnioSsl(xnio, OptionMap.EMPTY, sslContext);
+        } else {
+            ssl = null;
+        }
+    }
+    
+    public class RequestBuilder {
+        private final String address;
+        private String path = "";
+        private String accept = MediaType.WILDCARD;
+        private OptionMap options = OptionMap.EMPTY;
+
+        public RequestBuilder(final String address) {
+            this.address = address;
+        }
+        
+        public RequestBuilder path(final String p) {
+            this.path = p;
+            return this;
+        }
+        
+        
+        public RequestBuilder accept(final String a) {
+            this.accept = a;
+            return this;
+        }
+        
+        public RequestBuilder http2() {
+            options = OptionMap.create(UndertowOptions.ENABLE_HTTP2, true);
+            return this;
+        }
+        
+        public ClientResponse get() throws IOException {
+            return request(address, path, options, Methods.GET, accept);
+        }
+    }
+    
+    public RequestBuilder request(final String address) throws IOException {
+        return new RequestBuilder(address);
+    }
+
+    public ClientResponse request(final String address, final String path, final OptionMap options,
+            final HttpString method, final String accept) throws IOException {
+
+        final ClientConnection connection = client
+            .connect(URI.create(address), worker, ssl, pool, options)
+            .get();
+        
+        try {
+            final ClientRequest request = new ClientRequest()
+                .setMethod(method)
+                .setPath(path);
+
+            request.getRequestHeaders().put(Headers.ACCEPT, accept);
+            request.getRequestHeaders().put(Headers.HOST, "localhost");
+            
+            final CompletableFuture<ClientResponse> future = new CompletableFuture<ClientResponse>();
+            connection.sendRequest(request, createClientCallback(future));
+            return future.join();
+        } finally {
+            IoUtils.safeClose(connection);
+        }
+    }
+
+    private ClientCallback<ClientExchange> createClientCallback(final CompletableFuture<ClientResponse> future) {
+        return new ClientCallback<ClientExchange>() {
+            @Override
+            public void completed(ClientExchange result) {
+                result.setResponseListener(new ClientCallback<ClientExchange>() {
+                    @Override
+                    public void completed(final ClientExchange result) {
+                        new StringReadChannelListener(result.getConnection().getBufferPool()) {
+                            @Override
+                            protected void stringDone(String string) {
+                                result.getResponse().putAttachment(RESPONSE_BODY, string);
+                                future.complete(result.getResponse());
+                            }
+
+                            @Override
+                            protected void error(IOException e) {
+                                future.completeExceptionally(e);
+                            }
+                        }.setup(result.getResponseChannel());
+                    }
+
+                    @Override
+                    public void failed(IOException e) {
+                        future.completeExceptionally(e);
+                    }
+                });
+            }
+
+            @Override
+            public void failed(IOException e) {
+                future.completeExceptionally(e);
+            }
+        };
+    }
+
+    public String getBody(ClientResponse response) {
+        return response.getAttachment(RESPONSE_BODY);
+    }
+
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2Test.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2Test.java
new file mode 100644
index 0000000..1babfdc
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2Test.java
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class UndertowClientServerHttp2Test extends AbstractUndertowClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2()));
+        createStaticBus();
+    }
+
+    @Override
+    protected String getAddress() {
+        return "https://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2cTest.java b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2cTest.java
new file mode 100644
index 0000000..b5b752d
--- /dev/null
+++ b/systests/transport-undertow/src/test/java/org/apache/cxf/systest/http_undertow/http2/UndertowClientServerHttp2cTest.java
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http_undertow.http2;
+
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class UndertowClientServerHttp2cTest extends AbstractUndertowClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2c.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2c()));
+        createStaticBus();
+    }
+
+    @Override
+    protected String getAddress() {
+        return "http://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server-tls.xml b/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server-tls.xml
new file mode 100644
index 0000000..cbd3a67
--- /dev/null
+++ b/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server-tls.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-undertow="http://cxf.apache.org/transports/http-undertow/configuration"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-undertow/configuration 
+        http://cxf.apache.org/schemas/configuration/http-undertow.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://cxf.apache.org/configuration/security 
+        http://cxf.apache.org/schemas/configuration/security.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-undertow:engine-factory bus="cxf">
+        <http-undertow:engine port="${testutil.ports.org.apache.cxf.systest.http_undertow.http2.BookServerHttp2}">
+            <http-undertow:tlsServerParameters>
+                <sec:keyManagers keyPassword="password">
+                    <sec:keyStore type="jks" password="password" resource="keys/Bethal.jks"/>
+                </sec:keyManagers>
+                <sec:clientAuthentication want="false" required="false"/>
+            </http-undertow:tlsServerParameters>
+        </http-undertow:engine>
+    </http-undertow:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server.xml b/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server.xml
new file mode 100644
index 0000000..a35af1a
--- /dev/null
+++ b/systests/transport-undertow/src/test/resources/org/apache/cxf/systest/http_undertow/http2/server.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-undertow="http://cxf.apache.org/transports/http-undertow/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-undertow/configuration 
+        http://cxf.apache.org/schemas/configuration/http-undertow.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-undertow:engine-factory bus="cxf">
+        <http-undertow:engine port="${testutil.ports.org.apache.cxf.systest.http_undertow.http2.BookServerHttp2c}">
+        </http-undertow:engine>
+    </http-undertow:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transports/pom.xml b/systests/transports/pom.xml
index a7f4ec6..62c617f 100644
--- a/systests/transports/pom.xml
+++ b/systests/transports/pom.xml
@@ -344,10 +344,66 @@
             <version>${cxf.junit5.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-server</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-alpn-server</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty.http2</groupId>
+            <artifactId>http2-client</artifactId>
+            <version>${cxf.jetty9.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <profiles>
         <profile>
+            <id>jdk8</id>
+            <activation>
+                <jdk>1.8</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-openjdk8-server</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-openjdk8-client</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>jdk9+</id>
+            <activation>
+                <jdk>[9,)</jdk>
+            </activation>
+            <dependencies>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-java-server</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+                <dependency>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-alpn-java-client</artifactId>
+                    <version>${cxf.jetty9.version}</version>
+                    <scope>test</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
             <id>jdk16</id>
             <activation>
                 <jdk>[16,)</jdk>
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractBookServerHttp2.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractBookServerHttp2.java
new file mode 100644
index 0000000..83d999b
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractBookServerHttp2.java
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.customer.book.Book;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.provider.StreamingResponseProvider;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.transport.http.HttpServerEngineSupport;
+
+abstract class AbstractBookServerHttp2 extends AbstractBusTestServerBase {
+    org.apache.cxf.endpoint.Server server;
+
+    private final String port;
+    private final String context;
+    private final String scheme;
+
+    AbstractBookServerHttp2(String port, String context, String scheme) {
+        this.port = port;
+        this.context = context;
+        this.scheme = scheme;
+    }
+
+    protected void run() {
+        SpringBusFactory factory = new SpringBusFactory();
+        Bus bus = factory.createBus(context);
+        bus.setProperty(HttpServerEngineSupport.ENABLE_HTTP2, true);
+        setBus(bus);
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setBus(bus);
+        sf.setResourceClasses(BookStore.class);
+        sf.setProvider(new StreamingResponseProvider<Book>());
+        sf.setResourceProvider(BookStore.class,
+            new SingletonResourceProvider(new BookStore(), true));
+        sf.setAddress(scheme + "://localhost:" + port + "/http2");
+        server = sf.create();
+    }
+
+    public void tearDown() throws Exception {
+        server.stop();
+        server.destroy();
+        server = null;
+    }
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractJettyClientServerHttp2Test.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractJettyClientServerHttp2Test.java
new file mode 100644
index 0000000..08eba61
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/AbstractJettyClientServerHttp2Test.java
@@ -0,0 +1,119 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.configuration.jsse.TLSClientParameters;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.systest.http2_jetty.Http2TestClient.ClientResponse;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.transport.http.HTTPConduit;
+import org.apache.cxf.transport.https.InsecureTrustManager;
+import org.eclipse.jetty.http.HttpVersion;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+abstract class AbstractJettyClientServerHttp2Test extends AbstractBusClientServerTestBase {
+    @Test
+    public void testBookNotFoundWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/notFound")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(404));
+        assertThat(response.getProtocol(), equalTo(HttpVersion.HTTP_2));
+    }
+
+    @Test
+    public void testBookWithHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("text/plain")
+            .path(getContext() + "/web/bookstore/booknames")
+            .http2()
+            .get();
+        
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo(HttpVersion.HTTP_2));
+        assertEquals("CXF in Action", response.getBody());
+    }
+
+    @Test
+    public void testGetBookStreamHttp2() throws Exception {
+        final Http2TestClient client = new Http2TestClient(isSecure());
+        
+        final ClientResponse response = client
+            .request(getAddress())
+            .accept("application/xml")
+            .path(getContext() + "/web/bookstore/bookstream")
+            .http2()
+            .get();
+
+        assertThat(response.getResponseCode(), equalTo(200));
+        assertThat(response.getProtocol(), equalTo(HttpVersion.HTTP_2));
+        assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+            + "<Book><id>1</id><name>Book1</name></Book>", response.getBody());
+    }
+
+    @Test
+    public void testBookWithHttp() throws Exception {
+        final WebClient wc = WebClient
+            .create(getAddress() + getContext() + "/web/bookstore/booknames")
+            .accept("text/plain");
+        
+        if (isSecure()) {
+            final HTTPConduit conduit = WebClient.getConfig(wc).getHttpConduit();
+            TLSClientParameters params = conduit.getTlsClientParameters();
+
+            if (params == null)  {
+                params = new TLSClientParameters();
+                conduit.setTlsClientParameters(params);
+            }
+
+            // Create TrustManager instance which trusts all clients and servers
+            params.setTrustManagers(InsecureTrustManager.getNoOpX509TrustManagers()); 
+            params.setDisableCNCheck(true);
+        }
+        
+        try (Response resp = wc.get()) {
+            assertThat(resp.getStatus(), equalTo(200));
+            assertEquals("CXF in Action", resp.readEntity(String.class));
+        }
+    }
+
+    protected abstract String getAddress();
+    protected abstract String getContext();
+
+    protected boolean isSecure() {
+        return getAddress().startsWith("https");
+    }
+}
\ No newline at end of file
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Book.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Book.java
new file mode 100644
index 0000000..fd80aac
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Book.java
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
+
+@JsonTypeInfo(use = Id.CLASS, include = As.PROPERTY, property = "class")
+@XmlRootElement(name = "Book")
+public class Book {
+    private String name;
+    private long id;
+
+    public Book() {
+    }
+
+    public Book(String name, long id) {
+        this.name = name;
+        this.id = id;
+    }
+
+    public void setName(String n) {
+        name = n;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setId(long i) {
+        id = i;
+    }
+    public long getId() {
+        return id;
+    }
+
+    @PUT
+    public void cloneState(Book book) {
+        id = book.getId();
+        name = book.getName();
+    }
+
+    @GET
+    public Book retrieveState() {
+        return this;
+    }
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2.java
new file mode 100644
index 0000000..1980e96
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+public class BookServerHttp2 extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2.class);
+
+    org.apache.cxf.endpoint.Server server;
+
+    public BookServerHttp2() {
+        this(PORT);
+    }
+
+    public BookServerHttp2(String port) {
+        super(port, "org/apache/cxf/systest/http2_jetty/server-tls.xml", "https");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2 s = new BookServerHttp2();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2c.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2c.java
new file mode 100644
index 0000000..74d7303
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookServerHttp2c.java
@@ -0,0 +1,45 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+public class BookServerHttp2c extends AbstractBookServerHttp2 {
+    public static final String PORT = allocatePort(BookServerHttp2c.class);
+
+    public BookServerHttp2c() {
+        this(PORT);
+    }
+
+    public BookServerHttp2c(String port) {
+        super(port, "org/apache/cxf/systest/http2_jetty/server.xml", "http");
+    }
+
+    public static void main(String[] args) {
+        try {
+            BookServerHttp2c s = new BookServerHttp2c();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookStore.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookStore.java
new file mode 100644
index 0000000..5aa5bdd
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/BookStore.java
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import org.apache.cxf.jaxrs.ext.StreamingResponse;
+
+@Path("/web/bookstore")
+public class BookStore {
+    private static ExecutorService executor = Executors.newSingleThreadExecutor();
+
+    @GET
+    @Path("/booknames")
+    @Produces("text/plain")
+    public byte[] getBookName() {
+        return "CXF in Action".getBytes();
+    }
+
+    @GET
+    @Path("/bookstream")
+    @Produces("application/xml")
+    public StreamingResponse<Book> getBookStream() {
+        return new StreamingResponse<Book>() {
+            public void writeTo(final StreamingResponse.Writer<Book> out) throws IOException {
+                out.write(new Book("Book1", 1));
+                executor.execute(new Runnable() {
+                    public void run() {
+                        try {
+                            for (int i = 2; i <= 5; i++) {
+                                Thread.sleep(500);
+                                out.write(new Book("Book" + i, i));
+                                out.getEntityStream().flush();
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            }
+        };
+    }
+}
+
+
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Http2TestClient.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Http2TestClient.java
new file mode 100644
index 0000000..70a388a
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/Http2TestClient.java
@@ -0,0 +1,212 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import javax.ws.rs.ClientErrorException;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.http.HttpURI;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.http.MetaData;
+import org.eclipse.jetty.http2.api.Session;
+import org.eclipse.jetty.http2.api.Stream;
+import org.eclipse.jetty.http2.api.server.ServerSessionListener;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.frames.DataFrame;
+import org.eclipse.jetty.http2.frames.HeadersFrame;
+import org.eclipse.jetty.util.Callback;
+import org.eclipse.jetty.util.FuturePromise;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+/**
+ * TODO: Use CXF client once https://issues.apache.org/jira/browse/CXF-8606 is dones
+ */
+public class Http2TestClient implements AutoCloseable {
+    private final HTTP2Client client;
+    private final SslContextFactory sslContextFactory;
+    
+    public Http2TestClient(boolean secure) throws Exception {
+        client = new HTTP2Client();
+        if (secure) {
+            sslContextFactory = new SslContextFactory.Client(true);
+            client.addBean(sslContextFactory);
+        } else {
+            sslContextFactory = null;
+        }
+        client.start();
+    }
+    
+    public static class ClientResponse {
+        private String body;
+        private HttpVersion protocol;
+        private int responseCode;
+
+        public void setBody(String body) {
+            this.body = body;
+        }
+        
+        public String getBody() {
+            return body;
+        }
+        
+        public void setResponseCode(int rc) {
+            this.responseCode = rc;
+        }
+
+        public int getResponseCode() {
+            return responseCode;
+        }
+
+        public HttpVersion getProtocol() {
+            return protocol;
+        }
+        
+        public void setProtocol(HttpVersion protocol) {
+            this.protocol = protocol;
+        }
+    }
+    
+    public class RequestBuilder {
+        private final String address;
+        private String path = "";
+        private String accept = MediaType.WILDCARD;
+        private HttpVersion version = HttpVersion.HTTP_1_1;
+
+        public RequestBuilder(final String address) {
+            this.address = address;
+        }
+        
+        public RequestBuilder path(final String p) {
+            this.path = p;
+            return this;
+        }
+        
+        
+        public RequestBuilder accept(final String a) {
+            this.accept = a;
+            return this;
+        }
+        
+        public RequestBuilder http2() {
+            version = HttpVersion.HTTP_2;
+            return this;
+        }
+        
+        public ClientResponse get() throws InterruptedException, ExecutionException, TimeoutException {
+            return request(address, path, version, "GET", accept);
+        }
+    }
+    
+    public RequestBuilder request(final String address) throws IOException {
+        return new RequestBuilder(address);
+    }
+
+    public ClientResponse request(final String address, final String path, 
+            final HttpVersion version, final String method, final String accept) 
+                throws InterruptedException, ExecutionException, TimeoutException {
+
+        final URI uri = URI.create(address);
+        final FuturePromise<Session> sessionPromise = new FuturePromise<>();
+
+        client.connect(sslContextFactory, new InetSocketAddress(uri.getHost(), uri.getPort()), 
+            new ServerSessionListener.Adapter(), sessionPromise);
+        final Session session = sessionPromise.get();
+
+        final HttpFields requestFields = new HttpFields();
+        requestFields.add(HttpHeader.ACCEPT, accept);
+        requestFields.add(HttpHeader.HOST, "localhost");
+
+        final MetaData.Request request = new MetaData.Request(method, new HttpURI(address + path), 
+            version, requestFields);
+
+        final CompletableFuture<ClientResponse> future = new CompletableFuture<>();
+        final Stream.Listener responseListener = new ResponseListener(future);
+        
+        final HeadersFrame headersFrame = new HeadersFrame(request, null, true);
+        session.newStream(headersFrame, new FuturePromise<>(), responseListener);
+        return future.get(5, TimeUnit.SECONDS);
+    }
+    
+    @Override
+    public void close() throws Exception {
+        client.stop();
+    }
+    
+    private final class ResponseListener extends Stream.Listener.Adapter {
+        private final ClientResponse response = new ClientResponse();
+        private final CompletableFuture<ClientResponse> future;
+        
+        ResponseListener(final CompletableFuture<ClientResponse> f) {
+            this.future = f;
+        }
+        
+        @Override
+        public void onHeaders(Stream stream, HeadersFrame frame) {
+            final MetaData metaData = frame.getMetaData();
+            response.setProtocol(metaData.getHttpVersion());
+            if (metaData.isResponse()) {
+                final int status = ((MetaData.Response)metaData).getStatus();
+                response.setResponseCode(status);
+                // Unsuccessful response
+                if (status >= 400) {
+                    future.complete(response);
+                }
+            }
+            super.onHeaders(stream, frame);
+        }
+        
+        @Override
+        public void onData(Stream stream, DataFrame frame, Callback callback) {
+            byte[] bytes = new byte[frame.getData().remaining()];
+            frame.getData().get(bytes);
+            response.setBody(new String(bytes));
+            future.complete(response);
+            super.onData(stream, frame, callback);
+        }
+        
+        @Override
+        public void onTimeout(Stream stream, Throwable x) {
+            future.completeExceptionally(x);
+            super.onTimeout(stream, x);
+        }
+        
+        @Override
+        public void onFailure(Stream stream, int error, String reason, Throwable failure, Callback callback) {
+            future.completeExceptionally(failure);
+            super.onFailure(stream, error, reason, failure, callback);
+        }
+        
+        @Override
+        public void onFailure(Stream stream, int error, String reason, Callback callback) {
+            future.completeExceptionally(new ClientErrorException(reason, error));
+            super.onFailure(stream, error, reason, callback);
+        }
+    }
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2Test.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2Test.java
new file mode 100644
index 0000000..a707024
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2Test.java
@@ -0,0 +1,48 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class JettyClientServerHttp2Test extends AbstractJettyClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2()));
+        createStaticBus();
+    }
+
+    
+    @Override
+    protected String getAddress() {
+        return "https://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2cTest.java b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2cTest.java
new file mode 100644
index 0000000..805367c
--- /dev/null
+++ b/systests/transports/src/test/java/org/apache/cxf/systest/http2_jetty/JettyClientServerHttp2cTest.java
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ */
+
+package org.apache.cxf.systest.http2_jetty;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+
+import org.junit.BeforeClass;
+
+import static org.junit.Assert.assertTrue;
+
+public class JettyClientServerHttp2cTest extends AbstractJettyClientServerHttp2Test {
+    private static final String PORT = BookServerHttp2c.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        assertTrue("server did not launch correctly", launchServer(new BookServerHttp2c()));
+        createStaticBus();
+    }
+
+    @Override
+    protected String getAddress() {
+        return "http://localhost:" + PORT;
+    }
+    
+    @Override
+    protected String getContext() {
+        return "/http2";
+    }
+}
diff --git a/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server-tls.xml b/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server-tls.xml
new file mode 100644
index 0000000..5a0cba8
--- /dev/null
+++ b/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server-tls.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-jetty="http://cxf.apache.org/transports/http-jetty/configuration"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-jetty/configuration 
+        http://cxf.apache.org/schemas/configuration/http-jetty.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://cxf.apache.org/configuration/security 
+        http://cxf.apache.org/schemas/configuration/security.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-jetty:engine-factory bus="cxf">
+        <http-jetty:engine port="${testutil.ports.org.apache.cxf.systest.http2_jetty.BookServerHttp2}">
+            <http-jetty:tlsServerParameters>
+                <sec:keyManagers keyPassword="password">
+                    <sec:keyStore type="jks" password="password" resource="keys/Bethal.jks"/>
+                </sec:keyManagers>
+                <sec:clientAuthentication want="false" required="false"/>
+            </http-jetty:tlsServerParameters>
+        </http-jetty:engine>
+    </http-jetty:engine-factory>
+</beans>
\ No newline at end of file
diff --git a/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server.xml b/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server.xml
new file mode 100644
index 0000000..c44bf1e
--- /dev/null
+++ b/systests/transports/src/test/resources/org/apache/cxf/systest/http2_jetty/server.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:http-jetty="http://cxf.apache.org/transports/http-jetty/configuration"
+    xsi:schemaLocation="http://cxf.apache.org/transports/http-jetty/configuration 
+        http://cxf.apache.org/schemas/configuration/http-jetty.xsd 
+        http://www.springframework.org/schema/beans 
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"/>
+    <http-jetty:engine-factory bus="cxf">
+        <http-jetty:engine port="${testutil.ports.org.apache.cxf.systest.http2_jetty.BookServerHttp2c}">
+        </http-jetty:engine>
+    </http-jetty:engine-factory>
+</beans>
\ No newline at end of file