From ca5c3361b7ace2d6027c43fbe44dc8e81cb35588 Mon Sep 17 00:00:00 2001 From: Laurent Garnier Date: Sun, 5 Feb 2023 20:34:48 +0100 Subject: [PATCH 1/2] Add param sslContextFactory when creating a HTTP or web socket client Signed-off-by: Laurent Garnier --- .../core/io/net/http/HttpClientFactory.java | 18 ++++++++++ .../core/io/net/http/WebSocketFactory.java | 18 ++++++++++ .../http/internal/WebClientFactoryImpl.java | 35 +++++++++++++------ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/HttpClientFactory.java b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/HttpClientFactory.java index 2ad0d995373..689c95865e4 100644 --- a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/HttpClientFactory.java +++ b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/HttpClientFactory.java @@ -13,7 +13,9 @@ 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.util.ssl.SslContextFactory; /** * Factory class to create Jetty http clients @@ -39,6 +41,22 @@ public interface HttpClientFactory { */ HttpClient createHttpClient(String consumerName); + /** + * Creates a new Jetty http 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 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-_] + * @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); + /** * Returns the shared Jetty http client. You must not call any setter methods or {@code stop()} on it. * The returned client is already started. diff --git a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/WebSocketFactory.java b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/WebSocketFactory.java index 77519db9793..bd9dc197ec4 100644 --- a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/WebSocketFactory.java +++ b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/WebSocketFactory.java @@ -13,6 +13,8 @@ package org.openhab.core.io.net.http; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.websocket.client.WebSocketClient; /** @@ -38,6 +40,22 @@ public interface WebSocketFactory { */ WebSocketClient createWebSocketClient(String consumerName); + /** + * Creates a new Jetty web socket 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 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-_] + * @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 + */ + WebSocketClient createWebSocketClient(String consumerName, @Nullable SslContextFactory sslContextFactory); + /** * Returns a shared Jetty web socket client. You must not call any setter methods or {@code stop()} on it. * The returned client is already started. diff --git a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java index 63b4242400d..fdfba40d63e 100644 --- a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java +++ b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java @@ -21,6 +21,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; @@ -124,16 +125,28 @@ protected void deactivate() { @Override public HttpClient createHttpClient(String consumerName) { + return createHttpClient(consumerName, null); + } + + @Override + public @NonNull HttpClient createHttpClient(@NonNull String consumerName, + @Nullable SslContextFactory sslContextFactory) { logger.debug("http client for consumer {} requested", consumerName); checkConsumerName(consumerName); - return createHttpClientInternal(consumerName, false, null); + return createHttpClientInternal(consumerName, sslContextFactory, false, null); } @Override public WebSocketClient createWebSocketClient(String consumerName) { + return createWebSocketClient(consumerName, null); + } + + @Override + public @NonNull WebSocketClient createWebSocketClient(@NonNull String consumerName, + @Nullable SslContextFactory sslContextFactory) { logger.debug("web socket client for consumer {} requested", consumerName); checkConsumerName(consumerName); - return createWebSocketClientInternal(consumerName, false, null); + return createWebSocketClientInternal(consumerName, sslContextFactory, false, null); } @Override @@ -191,7 +204,7 @@ private synchronized void initialize() { } if (commonHttpClient == null) { - commonHttpClient = createHttpClientInternal("common", true, threadPool); + commonHttpClient = createHttpClientInternal("common", null, true, threadPool); // we need to set the stop timeout AFTER the client has been started, because // otherwise the Jetty client sets it back to the default value. // We need the stop timeout in order to prevent blocking the deactivation of this @@ -201,7 +214,7 @@ private synchronized void initialize() { } if (commonWebSocketClient == null) { - commonWebSocketClient = createWebSocketClientInternal("common", true, threadPool); + commonWebSocketClient = createWebSocketClientInternal("common", null, true, threadPool); logger.debug("Jetty shared web socket client created"); } } catch (RuntimeException e) { @@ -212,12 +225,13 @@ private synchronized void initialize() { } } - private HttpClient createHttpClientInternal(String consumerName, boolean startClient, - @Nullable QueuedThreadPool threadPool) { + private HttpClient createHttpClientInternal(String consumerName, @Nullable SslContextFactory sslContextFactory, + boolean startClient, @Nullable QueuedThreadPool threadPool) { try { logger.debug("creating http client for consumer {}", consumerName); - HttpClient httpClient = new HttpClient(createSslContextFactory()); + HttpClient httpClient = new HttpClient( + sslContextFactory != null ? sslContextFactory : createSslContextFactory()); // If proxy is set as property (standard Java property), provide the proxy information to Jetty HTTP // Client @@ -276,12 +290,13 @@ private HttpClient createHttpClientInternal(String consumerName, boolean startCl } } - private WebSocketClient createWebSocketClientInternal(String consumerName, boolean startClient, - @Nullable QueuedThreadPool threadPool) { + private WebSocketClient createWebSocketClientInternal(String consumerName, + @Nullable SslContextFactory sslContextFactory, boolean startClient, @Nullable QueuedThreadPool threadPool) { try { logger.debug("creating web socket client for consumer {}", consumerName); - HttpClient httpClient = new HttpClient(createSslContextFactory()); + HttpClient httpClient = new HttpClient( + sslContextFactory != null ? sslContextFactory : createSslContextFactory()); if (threadPool != null) { httpClient.setExecutor(threadPool); } else { From 002aa668d006f441149a484741ae97082fd498ae Mon Sep 17 00:00:00 2001 From: Laurent Garnier Date: Thu, 9 Feb 2023 08:04:25 +0100 Subject: [PATCH 2/2] Review comment: @NonNull annotation removed Signed-off-by: Laurent Garnier --- .../core/io/net/http/internal/WebClientFactoryImpl.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java index fdfba40d63e..8d211b7b796 100644 --- a/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java +++ b/bundles/org.openhab.core.io.net/src/main/java/org/openhab/core/io/net/http/internal/WebClientFactoryImpl.java @@ -21,7 +21,6 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; -import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; @@ -129,8 +128,7 @@ public HttpClient createHttpClient(String consumerName) { } @Override - public @NonNull HttpClient createHttpClient(@NonNull String consumerName, - @Nullable SslContextFactory sslContextFactory) { + public HttpClient createHttpClient(String consumerName, @Nullable SslContextFactory sslContextFactory) { logger.debug("http client for consumer {} requested", consumerName); checkConsumerName(consumerName); return createHttpClientInternal(consumerName, sslContextFactory, false, null); @@ -142,8 +140,7 @@ public WebSocketClient createWebSocketClient(String consumerName) { } @Override - public @NonNull WebSocketClient createWebSocketClient(@NonNull String consumerName, - @Nullable SslContextFactory sslContextFactory) { + public WebSocketClient createWebSocketClient(String consumerName, @Nullable SslContextFactory sslContextFactory) { logger.debug("web socket client for consumer {} requested", consumerName); checkConsumerName(consumerName); return createWebSocketClientInternal(consumerName, sslContextFactory, false, null);