Add support for Jetty HTTP/2 clients (#3433)
Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>pull/3446/head
parent
a3a95b5bb9
commit
a5d65ce2ad
|
@ -176,6 +176,14 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jetty HTTP2 -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-client</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JmDNS -->
|
||||
<dependency>
|
||||
<groupId>org.jmdns</groupId>
|
||||
|
|
|
@ -750,6 +750,20 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Jetty HTTP2 -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-client</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-alpn-java-client</artifactId>
|
||||
<version>${jetty.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Xbean -->
|
||||
<dependency>
|
||||
<groupId>org.apache.xbean</groupId>
|
||||
|
|
|
@ -15,6 +15,7 @@ package org.openhab.core.io.net.http;
|
|||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
/**
|
||||
|
@ -22,6 +23,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory;
|
|||
*
|
||||
* @author Michael Bock - Initial contribution
|
||||
* @author Martin van Wingerden - add createHttpClient without endpoint
|
||||
* @author Andrew Fiddian-Green - Added support for HTTP2 client creation
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface HttpClientFactory {
|
||||
|
@ -36,7 +38,6 @@ public interface HttpClientFactory {
|
|||
* @param consumerName the for identifying the consumer in the Jetty thread pool.
|
||||
* Must be between 4 and 20 characters long and must contain only the following characters [a-zA-Z0-9-_]
|
||||
* @return the Jetty client
|
||||
* @throws NullPointerException if {@code consumerName} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code consumerName} is invalid
|
||||
*/
|
||||
HttpClient createHttpClient(String consumerName);
|
||||
|
@ -52,7 +53,6 @@ public interface HttpClientFactory {
|
|||
* Must be between 4 and 20 characters long and must contain only the following characters [a-zA-Z0-9-_]
|
||||
* @param sslContextFactory the SSL factory managing TLS encryption
|
||||
* @return the Jetty client
|
||||
* @throws NullPointerException if {@code consumerName} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code consumerName} is invalid
|
||||
*/
|
||||
HttpClient createHttpClient(String consumerName, @Nullable SslContextFactory sslContextFactory);
|
||||
|
@ -64,4 +64,33 @@ public interface HttpClientFactory {
|
|||
* @return the shared Jetty http client
|
||||
*/
|
||||
HttpClient getCommonHttpClient();
|
||||
|
||||
/**
|
||||
* Creates a new Jetty HTTP/2 client.
|
||||
* The returned client is not started yet. You have to start it yourself before using.
|
||||
* Don't forget to stop a started client again after its usage.
|
||||
* The client lifecycle should be the same as for your service.
|
||||
* DO NOT CREATE NEW CLIENTS FOR EACH REQUEST!
|
||||
*
|
||||
* @param consumerName for identifying the consumer in the Jetty thread pool.
|
||||
* Must be between 4 and 20 characters long and must contain only the following characters [a-zA-Z0-9-_]
|
||||
* @return the Jetty HTTP/2 client
|
||||
* @throws IllegalArgumentException if {@code consumerName} is invalid
|
||||
*/
|
||||
HTTP2Client createHttp2Client(String consumerName);
|
||||
|
||||
/**
|
||||
* Creates a new Jetty HTTP/2 client.
|
||||
* The returned client is not started yet. You have to start it yourself before using.
|
||||
* Don't forget to stop a started client again after its usage.
|
||||
* The client lifecycle should be the same as for your service.
|
||||
* DO NOT CREATE NEW CLIENTS FOR EACH REQUEST!
|
||||
*
|
||||
* @param consumerName for identifying the consumer in the Jetty thread pool.
|
||||
* Must be between 4 and 20 characters long and must contain only the following characters [a-zA-Z0-9-_]
|
||||
* @param sslContextFactory the SSL factory managing TLS encryption
|
||||
* @return the Jetty HTTP/2 client
|
||||
* @throws IllegalArgumentException if {@code consumerName} is invalid
|
||||
*/
|
||||
HTTP2Client createHttp2Client(String consumerName, @Nullable SslContextFactory sslContextFactory);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
*/
|
||||
package org.openhab.core.io.net.http.internal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
@ -25,6 +25,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpProxy;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.PreEncodedHttpField;
|
||||
import org.eclipse.jetty.http2.client.HTTP2Client;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
|
@ -46,6 +50,7 @@ import org.slf4j.LoggerFactory;
|
|||
* @author Michael Bock - Initial contribution
|
||||
* @author Kai Kreuzer - added web socket support
|
||||
* @author Martin van Wingerden - Add support for ESHTrustManager
|
||||
* @author Andrew Fiddian-Green - Added support for HTTP2 client creation
|
||||
*/
|
||||
@Component(immediate = true, configurationPid = "org.openhab.webclient")
|
||||
@NonNullByDefault
|
||||
|
@ -77,6 +82,9 @@ public class WebClientFactoryImpl implements HttpClientFactory, WebSocketFactory
|
|||
private int maxThreadsCustom;
|
||||
private int keepAliveTimeoutCustom; // in s
|
||||
|
||||
private boolean hpackLoadTestDone = false;
|
||||
private @Nullable HttpClientInitializationException hpackException = null;
|
||||
|
||||
@Activate
|
||||
public WebClientFactoryImpl(final @Reference ExtensibleTrustManager extensibleTrustManager) {
|
||||
this.extensibleTrustManager = extensibleTrustManager;
|
||||
|
@ -332,7 +340,6 @@ public class WebClientFactoryImpl implements HttpClientFactory, WebSocketFactory
|
|||
}
|
||||
|
||||
private void checkConsumerName(String consumerName) {
|
||||
Objects.requireNonNull(consumerName, "consumerName must not be null");
|
||||
if (consumerName.length() < MIN_CONSUMER_NAME_LENGTH) {
|
||||
throw new IllegalArgumentException(
|
||||
"consumerName " + consumerName + " too short, minimum " + MIN_CONSUMER_NAME_LENGTH);
|
||||
|
@ -362,4 +369,49 @@ public class WebClientFactoryImpl implements HttpClientFactory, WebSocketFactory
|
|||
|
||||
return sslContextFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HTTP2Client createHttp2Client(String consumerName) {
|
||||
return createHttp2Client(consumerName, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HTTP2Client createHttp2Client(String consumerName, @Nullable SslContextFactory sslContextFactory) {
|
||||
logger.debug("http client for consumer {} requested", consumerName);
|
||||
checkConsumerName(consumerName);
|
||||
return createHttp2ClientInternal(consumerName, sslContextFactory);
|
||||
}
|
||||
|
||||
private HTTP2Client createHttp2ClientInternal(String consumerName, @Nullable SslContextFactory sslContextFactory) {
|
||||
try {
|
||||
logger.debug("creating HTTP/2 client for consumer {}", consumerName);
|
||||
|
||||
if (!hpackLoadTestDone) {
|
||||
try {
|
||||
PreEncodedHttpField field = new PreEncodedHttpField(HttpHeader.C_METHOD, "PUT");
|
||||
ByteBuffer bytes = ByteBuffer.allocate(32);
|
||||
field.putTo(bytes, HttpVersion.HTTP_2);
|
||||
hpackException = null;
|
||||
} catch (Exception e) {
|
||||
hpackException = new HttpClientInitializationException("Jetty HTTP/2 hpack module not loaded", e);
|
||||
}
|
||||
hpackLoadTestDone = true;
|
||||
}
|
||||
if (hpackException != null) {
|
||||
throw hpackException;
|
||||
}
|
||||
|
||||
HTTP2Client http2Client = new HTTP2Client();
|
||||
http2Client.addBean(sslContextFactory != null ? sslContextFactory : createSslContextFactory());
|
||||
http2Client.setExecutor(
|
||||
createThreadPool(consumerName, minThreadsCustom, maxThreadsCustom, keepAliveTimeoutCustom));
|
||||
|
||||
return http2Client;
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new HttpClientInitializationException(
|
||||
"unexpected checked exception during initialization of the Jetty HTTP/2 client", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,12 +71,16 @@
|
|||
|
||||
<feature name="openhab.tp-httpclient" version="${project.version}">
|
||||
<capability>openhab.tp;feature=httpclient;version=${jetty.version}</capability>
|
||||
<feature dependency="true">pax-web-jetty-http2</feature>
|
||||
<feature dependency="true">pax-web-jetty-http2-jdk9</feature>
|
||||
<bundle dependency="true">mvn:javax.servlet/javax.servlet-api/3.1.0</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-alpn-client/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-client/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-http/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-util/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-io/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty/jetty-proxy/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty.http2/http2-client/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty.websocket/websocket-api/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty.websocket/websocket-common/${jetty.version}</bundle>
|
||||
<bundle dependency="true">mvn:org.eclipse.jetty.websocket/websocket-client/${jetty.version}</bundle>
|
||||
|
|
|
@ -65,4 +65,8 @@ Fragment-Host: org.openhab.core.auth.oauth2client
|
|||
org.eclipse.jetty.websocket.common;version='[9.4.50,9.4.51)',\
|
||||
org.ops4j.pax.logging.pax-logging-api;version='[2.2.0,2.2.1)',\
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)'
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
org.eclipse.jetty.alpn.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.common;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.hpack;version='[9.4.50,9.4.51)'
|
||||
|
|
|
@ -88,7 +88,6 @@ Fragment-Host: org.openhab.core.model.item
|
|||
com.sun.jna;version='[5.12.1,5.12.2)',\
|
||||
xstream;version='[1.4.19,1.4.20)',\
|
||||
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
|
||||
org.apache.felix.http.servlet-api;version='[1.2.0,1.2.1)',\
|
||||
org.apache.felix.scr;version='[2.2.4,2.2.5)',\
|
||||
org.eclipse.jetty.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http;version='[9.4.50,9.4.51)',\
|
||||
|
@ -110,4 +109,9 @@ Fragment-Host: org.openhab.core.model.item
|
|||
org.ops4j.pax.web.pax-web-spi;version='[8.0.15,8.0.16)',\
|
||||
org.ops4j.pax.web.pax-web-tomcat-common;version='[8.0.15,8.0.16)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)'
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)',\
|
||||
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
|
||||
org.eclipse.jetty.alpn.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.common;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.hpack;version='[9.4.50,9.4.51)'
|
||||
|
|
|
@ -114,4 +114,8 @@ Fragment-Host: org.openhab.core.model.rule.runtime
|
|||
org.ops4j.pax.web.pax-web-spi;version='[8.0.15,8.0.16)',\
|
||||
org.ops4j.pax.web.pax-web-tomcat-common;version='[8.0.15,8.0.16)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)'
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)',\
|
||||
org.eclipse.jetty.alpn.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.common;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.hpack;version='[9.4.50,9.4.51)'
|
||||
|
|
|
@ -111,4 +111,8 @@ Fragment-Host: org.openhab.core.model.script
|
|||
org.ops4j.pax.web.pax-web-runtime;version='[8.0.15,8.0.16)',\
|
||||
org.ops4j.pax.web.pax-web-spi;version='[8.0.15,8.0.16)',\
|
||||
org.ops4j.pax.web.pax-web-tomcat-common;version='[8.0.15,8.0.16)',\
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)'
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)',\
|
||||
org.eclipse.jetty.alpn.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.common;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.hpack;version='[9.4.50,9.4.51)'
|
||||
|
|
|
@ -97,7 +97,6 @@ Fragment-Host: org.openhab.core.model.thing
|
|||
io.methvin.directory-watcher;version='[0.17.1,0.17.2)',\
|
||||
com.sun.jna;version='[5.12.1,5.12.2)',\
|
||||
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
|
||||
org.apache.felix.http.servlet-api;version='[1.2.0,1.2.1)',\
|
||||
org.apache.felix.scr;version='[2.2.4,2.2.5)',\
|
||||
org.eclipse.jetty.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http;version='[9.4.50,9.4.51)',\
|
||||
|
@ -119,4 +118,9 @@ Fragment-Host: org.openhab.core.model.thing
|
|||
org.ops4j.pax.web.pax-web-spi;version='[8.0.15,8.0.16)',\
|
||||
org.ops4j.pax.web.pax-web-tomcat-common;version='[8.0.15,8.0.16)',\
|
||||
org.osgi.service.cm;version='[1.6.0,1.6.1)',\
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)'
|
||||
org.osgi.service.component;version='[1.5.0,1.5.1)',\
|
||||
org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\
|
||||
org.eclipse.jetty.alpn.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.client;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.common;version='[9.4.50,9.4.51)',\
|
||||
org.eclipse.jetty.http2.hpack;version='[9.4.50,9.4.51)'
|
||||
|
|
Loading…
Reference in New Issue