This is an automated email from the ASF dual-hosted git repository. lzljs3620320 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push: new df67c115d4 [core] Introduce HttpClientUtils to reuse methods df67c115d4 is described below commit df67c115d497f27ea45e64d2c1319abc313f04b4 Author: JingsongLi <jingsongl...@gmail.com> AuthorDate: Thu Jul 24 16:06:57 2025 +0800 [core] Introduce HttpClientUtils to reuse methods --- .../java/org/apache/paimon/rest/HttpClient.java | 32 ++------- .../org/apache/paimon/rest/HttpClientUtils.java | 77 ++++++++++++++++++++++ .../main/java/org/apache/paimon/rest/RESTUtil.java | 24 ------- .../org/apache/paimon/rest/SimpleHttpClient.java | 28 ++------ .../apache/paimon/rest/auth/DLFECSTokenLoader.java | 10 +-- .../actions/HttpReportMarkDoneAction.java | 9 +-- 6 files changed, 92 insertions(+), 88 deletions(-) diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java index b8928786d9..a8a18a4155 100644 --- a/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java +++ b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClient.java @@ -23,7 +23,6 @@ import org.apache.paimon.rest.auth.RESTAuthFunction; import org.apache.paimon.rest.auth.RESTAuthParameter; import org.apache.paimon.rest.exceptions.RESTException; import org.apache.paimon.rest.interceptor.LoggingInterceptor; -import org.apache.paimon.rest.interceptor.TimingInterceptor; import org.apache.paimon.rest.responses.ErrorResponse; import org.apache.paimon.utils.StringUtils; @@ -33,30 +32,24 @@ import org.apache.hc.client5.http.classic.methods.HttpDelete; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; -import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicHeader; -import org.apache.hc.core5.util.Timeout; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.function.Function; +import static org.apache.paimon.rest.HttpClientUtils.createLoggingBuilder; + /** Apache HTTP client for REST catalog. */ public class HttpClient implements RESTClient { - private static final CloseableHttpClient httpClient; - - static { - httpClient = buildHttpClient(); - } + private static final CloseableHttpClient HTTP_CLIENT = createLoggingBuilder().build(); private final String uri; @@ -67,23 +60,6 @@ public class HttpClient implements RESTClient { this.errorHandler = DefaultErrorHandler.getInstance(); } - public static CloseableHttpClient buildHttpClient() { - HttpClientBuilder clientBuilder = HttpClients.custom(); - RequestConfig requestConfig = - RequestConfig.custom() - .setConnectionRequestTimeout(Timeout.ofMinutes(3)) - .setResponseTimeout(Timeout.ofMinutes(3)) - .build(); - clientBuilder.setDefaultRequestConfig(requestConfig); - - clientBuilder.setConnectionManager(RESTUtil.configureConnectionManager()); - clientBuilder.setRetryStrategy(new ExponentialHttpRequestRetryStrategy(5)); - clientBuilder - .addRequestInterceptorFirst(new TimingInterceptor()) - .addResponseInterceptorLast(new LoggingInterceptor()); - return clientBuilder.build(); - } - @Override public <T extends RESTResponse> T get( String path, Class<T> responseType, RESTAuthFunction restAuthFunction) { @@ -161,7 +137,7 @@ public class HttpClient implements RESTClient { } private <T extends RESTResponse> T exec(HttpUriRequestBase request, Class<T> responseType) { - try (CloseableHttpResponse response = httpClient.execute(request)) { + try (CloseableHttpResponse response = HTTP_CLIENT.execute(request)) { String responseBodyStr = RESTUtil.extractResponseBodyAsString(response); if (!RESTUtil.isSuccessful(response)) { ErrorResponse error; diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/HttpClientUtils.java b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClientUtils.java new file mode 100644 index 0000000000..28402eeadd --- /dev/null +++ b/paimon-api/src/main/java/org/apache/paimon/rest/HttpClientUtils.java @@ -0,0 +1,77 @@ +/* + * 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.paimon.rest; + +import org.apache.paimon.rest.interceptor.LoggingInterceptor; +import org.apache.paimon.rest.interceptor.TimingInterceptor; + +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.http.ssl.HttpsSupport; +import org.apache.hc.core5.reactor.ssl.SSLBufferMode; +import org.apache.hc.core5.ssl.SSLContexts; +import org.apache.hc.core5.util.Timeout; + +/** Utils for {@link HttpClientBuilder}. */ +public class HttpClientUtils { + + public static HttpClientBuilder createLoggingBuilder() { + HttpClientBuilder clientBuilder = createBuilder(); + clientBuilder + .addRequestInterceptorFirst(new TimingInterceptor()) + .addResponseInterceptorLast(new LoggingInterceptor()); + return clientBuilder; + } + + public static HttpClientBuilder createBuilder() { + HttpClientBuilder clientBuilder = HttpClients.custom(); + RequestConfig requestConfig = + RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofMinutes(3)) + .setResponseTimeout(Timeout.ofMinutes(3)) + .build(); + clientBuilder.setDefaultRequestConfig(requestConfig); + + clientBuilder.setConnectionManager(configureConnectionManager()); + clientBuilder.setRetryStrategy(new ExponentialHttpRequestRetryStrategy(5)); + return clientBuilder; + } + + private static HttpClientConnectionManager configureConnectionManager() { + PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = + PoolingHttpClientConnectionManagerBuilder.create(); + connectionManagerBuilder.useSystemProperties().setMaxConnTotal(100).setMaxConnPerRoute(100); + + // support TLS + String[] tlsProtocols = {"TLSv1.2", "TLSv1.3"}; + connectionManagerBuilder.setTlsSocketStrategy( + new DefaultClientTlsStrategy( + SSLContexts.createDefault(), + tlsProtocols, + null, + SSLBufferMode.STATIC, + HttpsSupport.getDefaultHostnameVerifier())); + + return connectionManagerBuilder.build(); + } +} diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/RESTUtil.java b/paimon-api/src/main/java/org/apache/paimon/rest/RESTUtil.java index 651a134c8d..52a633b62a 100644 --- a/paimon-api/src/main/java/org/apache/paimon/rest/RESTUtil.java +++ b/paimon-api/src/main/java/org/apache/paimon/rest/RESTUtil.java @@ -28,16 +28,10 @@ import org.apache.paimon.shade.guava30.com.google.common.collect.Maps; import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonProcessingException; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.io.HttpClientConnectionManager; -import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; -import org.apache.hc.client5.http.ssl.HttpsSupport; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.net.URIBuilder; -import org.apache.hc.core5.reactor.ssl.SSLBufferMode; -import org.apache.hc.core5.ssl.SSLContexts; import java.io.IOException; import java.io.UncheckedIOException; @@ -183,24 +177,6 @@ public class RESTUtil { || code == HttpStatus.SC_NO_CONTENT; } - public static HttpClientConnectionManager configureConnectionManager() { - PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = - PoolingHttpClientConnectionManagerBuilder.create(); - connectionManagerBuilder.useSystemProperties().setMaxConnTotal(100).setMaxConnPerRoute(100); - - // support TLS - String[] tlsProtocols = {"TLSv1.2", "TLSv1.3"}; - connectionManagerBuilder.setTlsSocketStrategy( - new DefaultClientTlsStrategy( - SSLContexts.createDefault(), - tlsProtocols, - null, - SSLBufferMode.STATIC, - HttpsSupport.getDefaultHostnameVerifier())); - - return connectionManagerBuilder.build(); - } - public static String buildRequestUrl(String url, Map<String, String> queryParams) { try { if (queryParams != null && !queryParams.isEmpty()) { diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/SimpleHttpClient.java b/paimon-api/src/main/java/org/apache/paimon/rest/SimpleHttpClient.java index 800bb83aef..e0e043fc1e 100644 --- a/paimon-api/src/main/java/org/apache/paimon/rest/SimpleHttpClient.java +++ b/paimon-api/src/main/java/org/apache/paimon/rest/SimpleHttpClient.java @@ -23,28 +23,28 @@ import org.apache.paimon.utils.StringUtils; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; -import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.ParseException; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicHeader; -import org.apache.hc.core5.util.Timeout; import java.io.Closeable; import java.io.IOException; import java.util.Map; -/** A simple client to wrap apache httpcompents client. */ +import static org.apache.paimon.rest.HttpClientUtils.createBuilder; + +/** A simple client to wrap {@link CloseableHttpClient}. */ public class SimpleHttpClient implements Closeable { + public static final SimpleHttpClient INSTANCE = new SimpleHttpClient(); + private final CloseableHttpClient client; - public SimpleHttpClient() { - this.client = buildHttpClient(); + private SimpleHttpClient() { + this.client = createBuilder().build(); } public String post(String url, Object body, Map<String, String> headers) throws IOException { @@ -106,18 +106,4 @@ public class SimpleHttpClient implements Closeable { throw new RuntimeException(e); } } - - private static CloseableHttpClient buildHttpClient() { - HttpClientBuilder clientBuilder = HttpClients.custom(); - RequestConfig requestConfig = - RequestConfig.custom() - .setConnectionRequestTimeout(Timeout.ofMinutes(3)) - .setResponseTimeout(Timeout.ofMinutes(3)) - .build(); - clientBuilder.setDefaultRequestConfig(requestConfig); - - clientBuilder.setConnectionManager(RESTUtil.configureConnectionManager()); - clientBuilder.setRetryStrategy(new ExponentialHttpRequestRetryStrategy(5)); - return clientBuilder.build(); - } } diff --git a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFECSTokenLoader.java b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFECSTokenLoader.java index 96a7815354..404cb49b8d 100644 --- a/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFECSTokenLoader.java +++ b/paimon-api/src/main/java/org/apache/paimon/rest/auth/DLFECSTokenLoader.java @@ -35,12 +35,6 @@ public class DLFECSTokenLoader implements DLFTokenLoader { private static final Logger LOG = LoggerFactory.getLogger(DLFECSTokenLoader.class); - private static final SimpleHttpClient client; - - static { - client = new SimpleHttpClient(); - } - private final String ecsMetadataURL; private String roleName; @@ -73,7 +67,7 @@ public class DLFECSTokenLoader implements DLFTokenLoader { private static DLFToken getToken(String url) { try { - String token = client.get(url); + String token = SimpleHttpClient.INSTANCE.get(url); return RESTApi.fromJson(token, DLFToken.class); } catch (IOException e) { throw new UncheckedIOException(e); @@ -86,7 +80,7 @@ public class DLFECSTokenLoader implements DLFTokenLoader { protected static String getResponseBody(String url) { long startTime = System.currentTimeMillis(); try { - String responseBodyStr = client.get(url); + String responseBodyStr = SimpleHttpClient.INSTANCE.get(url); if (LOG.isDebugEnabled()) { LOG.debug( "get response success, url : {}, cost : {} ms", diff --git a/paimon-core/src/main/java/org/apache/paimon/partition/actions/HttpReportMarkDoneAction.java b/paimon-core/src/main/java/org/apache/paimon/partition/actions/HttpReportMarkDoneAction.java index bbe4a8001d..43fcf7c998 100644 --- a/paimon-core/src/main/java/org/apache/paimon/partition/actions/HttpReportMarkDoneAction.java +++ b/paimon-core/src/main/java/org/apache/paimon/partition/actions/HttpReportMarkDoneAction.java @@ -42,7 +42,6 @@ import static org.apache.paimon.CoreOptions.PARTITION_MARK_DONE_ACTION_URL; /** Report partition submission information to remote http server. */ public class HttpReportMarkDoneAction implements PartitionMarkDoneAction { - private SimpleHttpClient client; private String url; private ObjectMapper mapper; @@ -72,8 +71,6 @@ public class HttpReportMarkDoneAction implements PartitionMarkDoneAction { this.mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); - - this.client = new SimpleHttpClient(); } @Override @@ -95,9 +92,7 @@ public class HttpReportMarkDoneAction implements PartitionMarkDoneAction { } @Override - public void close() throws IOException { - client.close(); - } + public void close() throws IOException {} /** RestRequest only for HttpReportMarkDoneAction. */ @JsonIgnoreProperties(ignoreUnknown = true) @@ -175,7 +170,7 @@ public class HttpReportMarkDoneAction implements PartitionMarkDoneAction { public HttpReportMarkDoneResponse post( HttpReportMarkDoneRequest body, Map<String, String> headers) throws IOException { - String responseBodyStr = this.client.post(url, body, headers); + String responseBodyStr = SimpleHttpClient.INSTANCE.post(url, body, headers); return mapper.readValue(responseBodyStr, HttpReportMarkDoneResponse.class); } }