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);
     }
 }

Reply via email to