javeme commented on code in PR #133:
URL: 
https://github.com/apache/incubator-hugegraph-commons/pull/133#discussion_r1365685318


##########
hugegraph-common/pom.xml:
##########
@@ -196,76 +198,17 @@
             <version>${jackson.version}</version>
         </dependency>
 
-        <!-- jersey -->
-        <dependency>
-            <groupId>org.glassfish.jersey.core</groupId>
-            <artifactId>jersey-client</artifactId>
-            <version>${jersey.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jersey.media</groupId>
-            <artifactId>jersey-media-json-jackson</artifactId>
-            <version>${jersey.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.fasterxml.jackson.jaxrs</groupId>
-                    <artifactId>jackson-jaxrs-base</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>com.fasterxml.jackson.jaxrs</groupId>
-                    <artifactId>jackson-jaxrs-json-provider</artifactId>
-                </exclusion>
-                <exclusion>
-                    <artifactId>jackson-annotations</artifactId>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                </exclusion>
-                <exclusion>
-                    <artifactId>jackson-databind</artifactId>
-                    <groupId>com.fasterxml.jackson.core</groupId>
-                </exclusion>
-                <exclusion>
-                    <artifactId>jackson-module-jaxb-annotations</artifactId>
-                    <groupId>com.fasterxml.jackson.module</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jersey.connectors</groupId>
-            <artifactId>jersey-apache-connector</artifactId>
-            <version>${jersey.version}</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>commons-codec</artifactId>
-                    <groupId>commons-codec</groupId>
-                </exclusion>
-                <exclusion>
-                    <artifactId>commons-logging</artifactId>
-                    <groupId>commons-logging</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>org.glassfish.jersey.inject</groupId>
-            <artifactId>jersey-hk2</artifactId>
-            <version>${jersey.hk2.version}</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>javassist</artifactId>
-                    <groupId>org.javassist</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>jakarta.xml.bind</groupId>
-            <artifactId>jakarta.xml.bind-api</artifactId>
-            <version>${jakarta.xml.version}</version>
-            <exclusions>
-                <exclusion>
-                    <artifactId>jakarta.activation-api</artifactId>
-                    <groupId>jakarta.activation</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>jakarta.xml.bind</groupId>-->
+<!--            <artifactId>jakarta.xml.bind-api</artifactId>-->
+<!--            <version>${jakarta.xml.version}</version>-->
+<!--            <exclusions>-->
+<!--                <exclusion>-->
+<!--                    <artifactId>jakarta.activation-api</artifactId>-->
+<!--                    <groupId>jakarta.activation</groupId>-->
+<!--                </exclusion>-->
+<!--            </exclusions>-->
+<!--        </dependency>-->

Review Comment:
   expect to be removed



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -207,31 +265,64 @@ public RestResult post(String path, Object object) {
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           MultivaluedMap<String, Object> headers) {
+    public RestResult post(String path, Object object, RestHeaders headers) {
         return this.post(path, object, headers, null);
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           Map<String, Object> params) {
+    public RestResult post(String path, Object object, Map<String, Object> 
params) {
         return this.post(path, object, null, params);
     }
 
+    private Request.Builder getRequestBuilder(String path, String id, 
RestHeaders headers,
+                                              Map<String, Object> params) {
+        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder()
+                                            .addPathSegments(path);
+        if (id != null) {
+            urlBuilder.addPathSegment(id);
+        }
+
+        if (params != null) {
+            params.forEach((name, value) -> {
+                if (value == null) {
+                    return;
+                }
+
+                if (value instanceof Collection) {
+                    for (Object i : (Collection<?>) value) {
+                        urlBuilder.addQueryParameter(name, String.valueOf(i));
+                    }
+                } else {
+                    urlBuilder.addQueryParameter(name, String.valueOf(value));
+                }
+            });
+        }
+
+        Request.Builder builder = requestBuilder
+                .url(urlBuilder.build());
+
+        if (headers != null) {
+            builder.headers(headers.toOkhttpHeader());
+        }
+
+        this.attachAuthToRequest(builder);
+
+        return builder;
+    }
+
+    @SneakyThrows
     @Override
     public RestResult post(String path, Object object,
-                           MultivaluedMap<String, Object> headers,
+                           RestHeaders headers,

Review Comment:
   we can move params to line 316



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -241,7 +332,7 @@ public RestResult put(String path, String id, Object 
object) {
 
     @Override
     public RestResult put(String path, String id, Object object,
-                          MultivaluedMap<String, Object> headers) {
+                          RestHeaders headers) {

Review Comment:
   ditto



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -360,136 +436,42 @@ public String getAuthContext() {
         return this.authContext.get();
     }
 
-    private void attachAuthToRequest(Builder builder) {
+    public void setAuthContext(String auth) {
+        this.authContext.set(auth);
+    }
+
+    private void attachAuthToRequest(Request.Builder builder) {
         // Add auth header
         String auth = this.getAuthContext();
         if (StringUtils.isNotEmpty(auth)) {
-            builder.header(HttpHeaders.AUTHORIZATION, auth);
+            builder.addHeader("Authorization", auth);
         }
     }
 
-    private Pair<Builder, Entity<?>> buildRequest(
-                                     String path, String id, Object object,
-                                     MultivaluedMap<String, Object> headers,
-                                     Map<String, Object> params) {
-        WebTarget target = this.target;
-        if (params != null && !params.isEmpty()) {
-            for (Map.Entry<String, Object> param : params.entrySet()) {
-                target = target.queryParam(param.getKey(), param.getValue());
-            }
-        }
-
-        Builder builder = id == null ? target.path(path).request() :
-                          target.path(path).path(encode(id)).request();
+    @SneakyThrows
+    private X509TrustManager trustManagerForCertificates(String trustStoreFile,
+                                                         String 
trustStorePass) {
+        char[] password = trustStorePass.toCharArray();
 
-        String encoding = null;
-        if (headers != null && !headers.isEmpty()) {
-            // Add headers
-            builder = builder.headers(headers);
-            encoding = (String) headers.getFirst("Content-Encoding");
+        //load keyStore
+        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+        try (FileInputStream in = new FileInputStream(trustStoreFile)) {
+            keyStore.load(in, password);
         }
-        // Add auth header
-        this.attachAuthToRequest(builder);
 
-        /*
-         * We should specify the encoding of the entity object manually,
-         * because Entity.json() method will reset "content encoding =
-         * null" that has been set up by headers before.
-         */
-        MediaType customContentType = parseCustomContentType(headers);
-        Entity<?> entity;
-        if (encoding == null) {
-            entity = Entity.entity(object, customContentType);
-        } else {
-            Variant variant = new Variant(customContentType,
-                                          (String) null, encoding);
-            entity = Entity.entity(object, variant);
-        }
-        return Pair.of(builder, entity);
-    }
-
-    /**
-     * parse user custom content-type, returns MediaType.APPLICATION_JSON_TYPE 
default.
-     * @param headers custom http header
-     */
-    private static MediaType parseCustomContentType(MultivaluedMap<String, 
Object> headers) {
-        String customContentType = null;
-        if (MapUtils.isNotEmpty(headers) && headers.get("Content-Type") != 
null) {
-            List<?> contentTypeObj = headers.get("Content-Type");
-            if (contentTypeObj != null && !contentTypeObj.isEmpty()) {
-                customContentType = contentTypeObj.get(0).toString();
-            }
-            return MediaType.valueOf(customContentType);
-        }
-        return MediaType.APPLICATION_JSON_TYPE;
-    }
-
-    private static void configConnectionManager(String url, ClientConfig conf) 
{
-        /*
-         * Using httpclient with connection pooling, and configuring the
-         * jersey connector. But the jersey that has been released in the 
maven central
-         * repository seems to have a bug: 
https://github.com/jersey/jersey/pull/3752
-         */
-        PoolingHttpClientConnectionManager pool = connectionManager(url, conf);
-        Object maxTotal = conf.getProperty("maxTotal");
-        Object maxPerRoute = conf.getProperty("maxPerRoute");
-        if (maxTotal != null) {
-            pool.setMaxTotal((int) maxTotal);
-        }
-        if (maxPerRoute != null) {
-            pool.setDefaultMaxPerRoute((int) maxPerRoute);
-        }
-        conf.property(ApacheClientProperties.CONNECTION_MANAGER, pool);
-        conf.connectorProvider(new ApacheConnectorProvider());
-    }
+        TrustManagerFactory trustManagerFactory =
+                
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        trustManagerFactory.init(keyStore);
 
-    private static PoolingHttpClientConnectionManager connectionManager(
-                                                      String url,
-                                                      ClientConfig conf) {
-        String protocol = (String) conf.getProperty("protocol");
-        if (protocol == null || "http".equals(protocol)) {
-            return new PoolingHttpClientConnectionManager(TTL, TimeUnit.HOURS);
+        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+        if (trustManagers.length != 1 || !(trustManagers[0] instanceof 
X509TrustManager)) {
+            throw new IllegalStateException("Unexpected default trust 
managers:"
+                                            + Arrays.toString(trustManagers));
         }
-
-        assert "https".equals(protocol);
-        String trustStoreFile = (String) conf.getProperty("trustStoreFile");
-        E.checkArgument(trustStoreFile != null && !trustStoreFile.isEmpty(),
-                        "The trust store file must be set when use https");
-        String trustStorePass = (String) 
conf.getProperty("trustStorePassword");
-        E.checkArgument(trustStorePass != null,
-                        "The trust store password must be set when use https");
-        SSLContext context = SslConfigurator.newInstance()
-                                            .trustStoreFile(trustStoreFile)
-                                            .trustStorePassword(trustStorePass)
-                                            .securityProtocol("SSL")
-                                            .createSSLContext();
-        TrustManager[] trustAllManager = NoCheckTrustManager.create();
-        try {
-            context.init(null, trustAllManager, new SecureRandom());
-        } catch (KeyManagementException e) {
-            throw new ClientException("Failed to init security management", e);
-        }
-
-        HostnameVerifier verifier = new HostNameVerifier(url);
-        ConnectionSocketFactory httpSocketFactory, httpsSocketFactory;
-        httpSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
-        httpsSocketFactory = new SSLConnectionSocketFactory(context, verifier);
-        Registry<ConnectionSocketFactory> registry =
-                RegistryBuilder.<ConnectionSocketFactory>create()
-                .register("http", httpSocketFactory)
-                .register("https", httpsSocketFactory)
-                .build();
-        return new PoolingHttpClientConnectionManager(registry, null,
-                                                      null, null, TTL,
-                                                      TimeUnit.HOURS);
-    }
-
-    public static String encode(String raw) {
-        return UriComponent.encode(raw, UriComponent.Type.PATH_SEGMENT);
+        return (X509TrustManager) trustManagers[0];
     }
 
     public static class HostNameVerifier implements HostnameVerifier {
-

Review Comment:
   expect a blank line after the class define



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);
+            }
+        } else {
+            bodyContent = String.valueOf(object);
+        }
+        RequestBody requestBody = 
RequestBody.create(MediaType.parse(contentType), bodyContent);
 
-    public AbstractRestClient(String url, String token, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .build());
+        if (headers != null && "gzip".equals(headers.get("Content-Encoding"))) 
{
+            requestBody = gzip(requestBody);
+        }
+        return requestBody;
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+    private static RequestBody gzip(final RequestBody body) {
+        return new RequestBody() {
+            @Override
+            public MediaType contentType() {
+                return body.contentType();
+            }
+
+            @Override
+            public long contentLength() {
+                return -1; // We don't know the compressed length in advance!
+            }
+
+            @Override
+            public void writeTo(BufferedSink sink) throws IOException {
+                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+                body.writeTo(gzipSink);
+                gzipSink.close();
+            }
+        };
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute,
-                              String trustStoreFile,
-                              String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
-
-    public AbstractRestClient(String url, ClientConfig config) {
-        configConnectionManager(url, config);
-
-        this.client = JerseyClientBuilder.newClient(config);
-        this.client.register(GZipEncoder.class);
-        this.target = this.client.target(url);
-        this.pool = (PoolingHttpClientConnectionManager) config.getProperty(
-                    ApacheClientProperties.CONNECTION_MANAGER);
-        if (this.pool != null) {
-            this.cleanExecutor = ExecutorUtil.newScheduledThreadPool(
-                                              "conn-clean-worker-%d");
-            Number idleTimeProp = (Number) config.getProperty("idleTime");
-            final long idleTime = idleTimeProp == null ?
-                                  IDLE_TIME : idleTimeProp.longValue();
-            final long checkPeriod = idleTime / 2L;
-            this.cleanExecutor.scheduleWithFixedDelay(() -> {
-                PoolStats stats = this.pool.getTotalStats();
-                int using = stats.getLeased() + stats.getPending();
-                if (using > 0) {
-                    // Do clean only when all connections are idle
-                    return;
-                }
-                // Release connections when all clients are inactive
-                this.pool.closeIdleConnections(idleTime, 
TimeUnit.MILLISECONDS);
-                this.pool.closeExpiredConnections();
-            }, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+    private static String parseContentType(RestHeaders headers) {
+        if (headers != null) {
+            String contentType = headers.get("Content-Type");
+            if (contentType != null) {
+                return contentType;
+            }
         }
+        return "application/json";
     }
 
-    protected abstract void checkStatus(Response response,
-                                        Response.Status... statuses);
+    private OkHttpClient getOkhttpClient(OkhttpConfig okhttpConfig) {

Review Comment:
   also mark static?



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -251,19 +342,19 @@ public RestResult put(String path, String id, Object 
object,
         return this.put(path, id, object, null, params);
     }
 
+    @SneakyThrows
     @Override
     public RestResult put(String path, String id, Object object,
-                          MultivaluedMap<String, Object> headers,
+                          RestHeaders headers,

Review Comment:
   ditto



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -360,136 +436,42 @@ public String getAuthContext() {
         return this.authContext.get();
     }
 
-    private void attachAuthToRequest(Builder builder) {
+    public void setAuthContext(String auth) {
+        this.authContext.set(auth);
+    }
+
+    private void attachAuthToRequest(Request.Builder builder) {
         // Add auth header
         String auth = this.getAuthContext();
         if (StringUtils.isNotEmpty(auth)) {
-            builder.header(HttpHeaders.AUTHORIZATION, auth);
+            builder.addHeader("Authorization", auth);
         }
     }
 
-    private Pair<Builder, Entity<?>> buildRequest(
-                                     String path, String id, Object object,
-                                     MultivaluedMap<String, Object> headers,
-                                     Map<String, Object> params) {
-        WebTarget target = this.target;
-        if (params != null && !params.isEmpty()) {
-            for (Map.Entry<String, Object> param : params.entrySet()) {
-                target = target.queryParam(param.getKey(), param.getValue());
-            }
-        }
-
-        Builder builder = id == null ? target.path(path).request() :
-                          target.path(path).path(encode(id)).request();
+    @SneakyThrows
+    private X509TrustManager trustManagerForCertificates(String trustStoreFile,
+                                                         String 
trustStorePass) {
+        char[] password = trustStorePass.toCharArray();
 
-        String encoding = null;
-        if (headers != null && !headers.isEmpty()) {
-            // Add headers
-            builder = builder.headers(headers);
-            encoding = (String) headers.getFirst("Content-Encoding");
+        //load keyStore

Review Comment:
   expect a space "// "



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestHeaders.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.hugegraph.rest;
+
+import java.util.Date;
+
+public class RestHeaders {

Review Comment:
   expect a blank line after the class define



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestHeaders.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.hugegraph.rest;
+
+import java.util.Date;
+
+public class RestHeaders {
+    private final okhttp3.Headers.Builder headersBuilder = new 
okhttp3.Headers.Builder();
+
+    public String get(String key) {
+        return headersBuilder.get(key);
+    }
+
+    public Date getDate(String key) {
+        return headersBuilder.build().getDate(key);
+    }
+
+    public RestHeaders add(String key, String value) {
+        headersBuilder.add(key, value);
+        return this;
+    }
+
+    public RestHeaders add(String key, Date value) {
+        headersBuilder.add(key, value);
+        return this;
+    }
+
+    public okhttp3.Headers toOkhttpHeader() {
+        return headersBuilder.build();
+    }
+

Review Comment:
   unexpected blank line



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/OkhttpConfig.java:
##########
@@ -0,0 +1,37 @@
+/*
+ * 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.hugegraph.rest;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Builder
+@Getter
+@Setter
+public class OkhttpConfig {

Review Comment:
   expect a blank line after the class define



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestHeaders.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.hugegraph.rest;
+
+import java.util.Date;
+
+public class RestHeaders {
+    private final okhttp3.Headers.Builder headersBuilder = new 
okhttp3.Headers.Builder();

Review Comment:
   can we move into the constructor



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestResult.java:
##########
@@ -21,39 +21,48 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import lombok.SneakyThrows;
+import okhttp3.Headers;
+import okhttp3.Response;
+
 public class RestResult {
 
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     private final int status;
-    private final MultivaluedMap<String, Object> headers;
+    private final Headers headers;
     private final String content;
 
     public RestResult(Response response) {
-        this(response.getStatus(), response.readEntity(String.class),
-             response.getHeaders());
+        this(response.code(), getResponseContent(response), 
response.headers());
     }
 
     public RestResult(int status, String content,
-                      MultivaluedMap<String, Object> headers) {
+                      Headers headers) {

Review Comment:
   keep them in one line



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestClientTest.java:
##########
@@ -370,10 +272,10 @@ public void testPut() {
     @Test
     public void testPutWithHeaders() {
         RestClient client = new RestClientImpl("/test", 1000, 200);
-        MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
-        headers.add("key1", "value1-1");
-        headers.add("key1", "value1-2");
-        headers.add("Content-Encoding", "gzip");
+        RestHeaders headers =
+                new RestHeaders().add("key1", "value1-1").add("key2",
+                                                              "value1-2")

Review Comment:
   seems one line is ok



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestResult.java:
##########
@@ -21,39 +21,48 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.Module;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import lombok.SneakyThrows;
+import okhttp3.Headers;
+import okhttp3.Response;
+
 public class RestResult {
 
     private static final ObjectMapper MAPPER = new ObjectMapper();
 
     private final int status;
-    private final MultivaluedMap<String, Object> headers;
+    private final Headers headers;
     private final String content;
 
     public RestResult(Response response) {
-        this(response.getStatus(), response.readEntity(String.class),
-             response.getHeaders());
+        this(response.code(), getResponseContent(response), 
response.headers());
     }
 
     public RestResult(int status, String content,
-                      MultivaluedMap<String, Object> headers) {
+                      Headers headers) {
         this.status = status;
         this.headers = headers;
         this.content = content;
     }
 
+    @SneakyThrows
+    private static String getResponseContent(Response response) {
+        return response.body().string();
+    }
+
+    public static void registerModule(Module module) {
+        MAPPER.registerModule(module);
+    }
+
     public int status() {
         return this.status;
     }
 
-    public MultivaluedMap<String, Object> headers() {
+    public Headers headers() {

Review Comment:
   also return RestHeaders



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestClientTest.java:
##########
@@ -327,16 +228,16 @@ public void testHostNameVerifier() {
 
     @Test
     public void testPostWithHeaderAndContent() {
-        MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
-        headers.add("key1", "value1-1");
-        headers.add("key1", "value1-2");
-        headers.add("Content-Encoding", "gzip");
+        RestHeaders headers = new RestHeaders()
+                .add("key1", "value1-1")

Review Comment:
   prefer to align with new



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestClientTest.java:
##########
@@ -192,52 +91,54 @@ public void testPostWithMaxTotalAndPerRoute() {
         Assert.assertEquals(200, restResult.status());
     }
 
-    @Test
-    public void testCleanExecutor() throws Exception {
-        // Modify IDLE_TIME 100ms to speed test
-        int newIdleTime = 100;
-        int newCheckPeriod = newIdleTime + 20;
-
-        RestClient client = new RestClientImpl("/test", 1000, newIdleTime,
-                                               10, 5, 200);
-
-        PoolingHttpClientConnectionManager pool;
-        pool = Whitebox.getInternalState(client, "pool");
-        pool = Mockito.spy(pool);
-        Whitebox.setInternalState(client, "pool", pool);
-        HttpRoute route = new HttpRoute(HttpHost.create(
-                                        "http://127.0.0.1:8080";));
-        // Create a connection manually, it will be put into leased list
-        HttpClientConnection conn = pool.requestConnection(route, null)
-                                        .get(1L, TimeUnit.SECONDS);
-        PoolStats stats = pool.getTotalStats();
-        int usingConns = stats.getLeased() + stats.getPending();
-        Assert.assertGte(1, usingConns);
-
-        // Sleep more than two check periods for busy connection
-        Thread.sleep(newCheckPeriod);
-        Mockito.verify(pool, Mockito.never()).closeExpiredConnections();
-        stats = pool.getTotalStats();
-        usingConns = stats.getLeased() + stats.getPending();
-        Assert.assertGte(1, usingConns);
-
-        // The connection will be put into available list
-        pool.releaseConnection(conn, null, 0, TimeUnit.SECONDS);
-
-        stats = pool.getTotalStats();
-        usingConns = stats.getLeased() + stats.getPending();
-        Assert.assertEquals(0, usingConns);
-        /*
-         * Sleep more than two check periods for free connection,
-         * ensure connection has been closed
-         */
-        Thread.sleep(newCheckPeriod);
-        Mockito.verify(pool, Mockito.atLeastOnce())
-               .closeExpiredConnections();
-        Mockito.verify(pool, Mockito.atLeastOnce())
-               .closeIdleConnections(newIdleTime, TimeUnit.MILLISECONDS);
-    }
-
+    /**
+     * okhttp does not need to manually clean Executor
+     */
+//    @Test
+//    public void testCleanExecutor() throws Exception {
+//        // Modify IDLE_TIME 100ms to speed test
+//        int newIdleTime = 100;
+//        int newCheckPeriod = newIdleTime + 20;
+//
+//        RestClient client = new RestClientImpl("/test", 1000, newIdleTime,
+//                                               10, 5, 200);
+//
+//        PoolingHttpClientConnectionManager pool;
+//        pool = Whitebox.getInternalState(client, "pool");
+//        pool = Mockito.spy(pool);
+//        Whitebox.setInternalState(client, "pool", pool);
+//        HttpRoute route = new HttpRoute(HttpHost.create(
+//                                        "http://127.0.0.1:8080";));
+//        // Create a connection manually, it will be put into leased list
+//        HttpClientConnection conn = pool.requestConnection(route, null)
+//                                        .get(1L, TimeUnit.SECONDS);
+//        PoolStats stats = pool.getTotalStats();
+//        int usingConns = stats.getLeased() + stats.getPending();
+//        Assert.assertGte(1, usingConns);
+//
+//        // Sleep more than two check periods for busy connection
+//        Thread.sleep(newCheckPeriod);
+//        Mockito.verify(pool, Mockito.never()).closeExpiredConnections();
+//        stats = pool.getTotalStats();
+//        usingConns = stats.getLeased() + stats.getPending();
+//        Assert.assertGte(1, usingConns);
+//
+//        // The connection will be put into available list
+//        pool.releaseConnection(conn, null, 0, TimeUnit.SECONDS);
+//
+//        stats = pool.getTotalStats();
+//        usingConns = stats.getLeased() + stats.getPending();
+//        Assert.assertEquals(0, usingConns);
+//        /*
+//         * Sleep more than two check periods for free connection,
+//         * ensure connection has been closed
+//         */
+//        Thread.sleep(newCheckPeriod);
+//        Mockito.verify(pool, Mockito.atLeastOnce())
+//               .closeExpiredConnections();
+//        Mockito.verify(pool, Mockito.atLeastOnce())
+//               .closeIdleConnections(newIdleTime, TimeUnit.MILLISECONDS);
+//    }

Review Comment:
   unused code is expected to be removed



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();

Review Comment:
   also move into the constructor?



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestClientTest.java:
##########
@@ -449,29 +351,31 @@ public void testDeleteWithException() {
         });
     }
 
-    @Test
-    public void testClose() {
-        RestClient client = new RestClientImpl("/test", 1000, 10, 5, 200);
-        RestResult restResult = client.post("path", "body");
-        Assert.assertEquals(200, restResult.status());
-
-        client.close();
-        Assert.assertThrows(IllegalStateException.class, () -> {
-            client.post("path", "body");
-        });
-
-        PoolingHttpClientConnectionManager pool;
-        pool = Whitebox.getInternalState(client, "pool");
-        Assert.assertNotNull(pool);
-        AtomicBoolean isShutDown = Whitebox.getInternalState(pool, 
"isShutDown");
-        Assert.assertTrue(isShutDown.get());
-
-        ScheduledExecutorService cleanExecutor;
-        cleanExecutor = Whitebox.getInternalState(client, "cleanExecutor");
-        Assert.assertNotNull(cleanExecutor);
-        Assert.assertTrue(cleanExecutor.isShutdown());
-    }
-
+    /**
+     * okhttp does not need to manually close connection pool
+     */
+//    @Test
+//    public void testClose() {
+//        RestClient client = new RestClientImpl("/test", 1000, 10, 5, 200);
+//        RestResult restResult = client.post("path", "body");
+//        Assert.assertEquals(200, restResult.status());
+//
+//        client.close();
+//        Assert.assertThrows(IllegalStateException.class, () -> {
+//            client.post("path", "body");
+//        });
+//
+//        PoolingHttpClientConnectionManager pool;
+//        pool = Whitebox.getInternalState(client, "pool");
+//        Assert.assertNotNull(pool);
+//        AtomicBoolean isShutDown = Whitebox.getInternalState(pool, 
"isShutDown");
+//        Assert.assertTrue(isShutDown.get());
+//
+//        ScheduledExecutorService cleanExecutor;
+//        cleanExecutor = Whitebox.getInternalState(client, "cleanExecutor");
+//        Assert.assertNotNull(cleanExecutor);
+//        Assert.assertTrue(cleanExecutor.isShutdown());
+//    }

Review Comment:
   ditto



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestResultTest.java:
##########
@@ -19,22 +19,45 @@
 
 import java.util.Map;
 
-import jakarta.ws.rs.core.MultivaluedHashMap;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
+import org.apache.hugegraph.rest.RestResult;
+import org.apache.hugegraph.rest.SerializeException;
+import org.apache.hugegraph.testutil.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
-import org.apache.hugegraph.rest.RestResult;
-import org.apache.hugegraph.rest.SerializeException;
-import org.apache.hugegraph.testutil.Assert;
+import lombok.SneakyThrows;
+import okhttp3.Headers;
+import okhttp3.Response;
 
 public class RestResultTest {
 
+    private static RestResult newRestResult(int status) {
+        return newRestResult(status, "", new Headers.Builder().build());
+    }
+
+    private static RestResult newRestResult(int status, String content) {
+        return newRestResult(status, content, new Headers.Builder().build());
+    }
+
+    private static RestResult newRestResult(int status,
+                                            Headers h) {

Review Comment:
   rename to `Headers headers` and move to line 45?



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();

Review Comment:
   keep in one line?



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {

Review Comment:
   prefer buildRequestBody



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/OkhttpTokenInterceptor.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.hugegraph.rest;
+
+import java.io.IOException;
+
+import okhttp3.Interceptor;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class OkhttpTokenInterceptor implements Interceptor {
+
+    private final String token;
+
+    public OkhttpTokenInterceptor(String token) {
+        this.token = token;
+    }
+
+    @Override
+    public Response intercept(Chain chain) throws IOException {
+        Request request = chain.request();
+        if (request.header("Authorization") == null) {
+            Request authenticatedRequest = request.newBuilder()
+                                                  .header("Authorization", 
"Bearer " + token)

Review Comment:
   keep `this.token` style for member access



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -207,31 +265,64 @@ public RestResult post(String path, Object object) {
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           MultivaluedMap<String, Object> headers) {
+    public RestResult post(String path, Object object, RestHeaders headers) {
         return this.post(path, object, headers, null);
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           Map<String, Object> params) {
+    public RestResult post(String path, Object object, Map<String, Object> 
params) {
         return this.post(path, object, null, params);
     }
 
+    private Request.Builder getRequestBuilder(String path, String id, 
RestHeaders headers,
+                                              Map<String, Object> params) {
+        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder()

Review Comment:
   this.baseUrl



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -207,31 +265,64 @@ public RestResult post(String path, Object object) {
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           MultivaluedMap<String, Object> headers) {
+    public RestResult post(String path, Object object, RestHeaders headers) {
         return this.post(path, object, headers, null);
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           Map<String, Object> params) {
+    public RestResult post(String path, Object object, Map<String, Object> 
params) {
         return this.post(path, object, null, params);
     }
 
+    private Request.Builder getRequestBuilder(String path, String id, 
RestHeaders headers,
+                                              Map<String, Object> params) {
+        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder()
+                                            .addPathSegments(path);
+        if (id != null) {
+            urlBuilder.addPathSegment(id);
+        }
+
+        if (params != null) {
+            params.forEach((name, value) -> {

Review Comment:
   use for loop instead



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -207,31 +265,64 @@ public RestResult post(String path, Object object) {
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           MultivaluedMap<String, Object> headers) {
+    public RestResult post(String path, Object object, RestHeaders headers) {
         return this.post(path, object, headers, null);
     }
 
     @Override
-    public RestResult post(String path, Object object,
-                           Map<String, Object> params) {
+    public RestResult post(String path, Object object, Map<String, Object> 
params) {
         return this.post(path, object, null, params);
     }
 
+    private Request.Builder getRequestBuilder(String path, String id, 
RestHeaders headers,
+                                              Map<String, Object> params) {
+        HttpUrl.Builder urlBuilder = HttpUrl.parse(baseUrl).newBuilder()
+                                            .addPathSegments(path);
+        if (id != null) {
+            urlBuilder.addPathSegment(id);
+        }
+
+        if (params != null) {
+            params.forEach((name, value) -> {
+                if (value == null) {
+                    return;
+                }
+
+                if (value instanceof Collection) {
+                    for (Object i : (Collection<?>) value) {
+                        urlBuilder.addQueryParameter(name, String.valueOf(i));
+                    }
+                } else {
+                    urlBuilder.addQueryParameter(name, String.valueOf(value));
+                }
+            });
+        }
+
+        Request.Builder builder = requestBuilder
+                .url(urlBuilder.build());

Review Comment:
   seems one line is ok



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);
+            }
+        } else {
+            bodyContent = String.valueOf(object);
+        }
+        RequestBody requestBody = 
RequestBody.create(MediaType.parse(contentType), bodyContent);
 
-    public AbstractRestClient(String url, String token, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .build());
+        if (headers != null && "gzip".equals(headers.get("Content-Encoding"))) 
{
+            requestBody = gzip(requestBody);
+        }
+        return requestBody;
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+    private static RequestBody gzip(final RequestBody body) {
+        return new RequestBody() {
+            @Override
+            public MediaType contentType() {
+                return body.contentType();
+            }
+
+            @Override
+            public long contentLength() {
+                return -1; // We don't know the compressed length in advance!
+            }
+
+            @Override
+            public void writeTo(BufferedSink sink) throws IOException {
+                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+                body.writeTo(gzipSink);
+                gzipSink.close();
+            }
+        };
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute,
-                              String trustStoreFile,
-                              String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
-
-    public AbstractRestClient(String url, ClientConfig config) {
-        configConnectionManager(url, config);
-
-        this.client = JerseyClientBuilder.newClient(config);
-        this.client.register(GZipEncoder.class);
-        this.target = this.client.target(url);
-        this.pool = (PoolingHttpClientConnectionManager) config.getProperty(
-                    ApacheClientProperties.CONNECTION_MANAGER);
-        if (this.pool != null) {
-            this.cleanExecutor = ExecutorUtil.newScheduledThreadPool(
-                                              "conn-clean-worker-%d");
-            Number idleTimeProp = (Number) config.getProperty("idleTime");
-            final long idleTime = idleTimeProp == null ?
-                                  IDLE_TIME : idleTimeProp.longValue();
-            final long checkPeriod = idleTime / 2L;
-            this.cleanExecutor.scheduleWithFixedDelay(() -> {
-                PoolStats stats = this.pool.getTotalStats();
-                int using = stats.getLeased() + stats.getPending();
-                if (using > 0) {
-                    // Do clean only when all connections are idle
-                    return;
-                }
-                // Release connections when all clients are inactive
-                this.pool.closeIdleConnections(idleTime, 
TimeUnit.MILLISECONDS);
-                this.pool.closeExpiredConnections();
-            }, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+    private static String parseContentType(RestHeaders headers) {
+        if (headers != null) {
+            String contentType = headers.get("Content-Type");
+            if (contentType != null) {
+                return contentType;
+            }
         }
+        return "application/json";
     }
 
-    protected abstract void checkStatus(Response response,
-                                        Response.Status... statuses);
+    private OkHttpClient getOkhttpClient(OkhttpConfig okhttpConfig) {

Review Comment:
   prefer buildOkHttpClient



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);
+            }
+        } else {
+            bodyContent = String.valueOf(object);
+        }
+        RequestBody requestBody = 
RequestBody.create(MediaType.parse(contentType), bodyContent);
 
-    public AbstractRestClient(String url, String token, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .build());
+        if (headers != null && "gzip".equals(headers.get("Content-Encoding"))) 
{
+            requestBody = gzip(requestBody);
+        }
+        return requestBody;
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+    private static RequestBody gzip(final RequestBody body) {
+        return new RequestBody() {
+            @Override
+            public MediaType contentType() {
+                return body.contentType();
+            }
+
+            @Override
+            public long contentLength() {
+                return -1; // We don't know the compressed length in advance!
+            }
+
+            @Override
+            public void writeTo(BufferedSink sink) throws IOException {
+                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+                body.writeTo(gzipSink);
+                gzipSink.close();
+            }
+        };
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute,
-                              String trustStoreFile,
-                              String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
-
-    public AbstractRestClient(String url, ClientConfig config) {
-        configConnectionManager(url, config);
-
-        this.client = JerseyClientBuilder.newClient(config);
-        this.client.register(GZipEncoder.class);
-        this.target = this.client.target(url);
-        this.pool = (PoolingHttpClientConnectionManager) config.getProperty(
-                    ApacheClientProperties.CONNECTION_MANAGER);
-        if (this.pool != null) {
-            this.cleanExecutor = ExecutorUtil.newScheduledThreadPool(
-                                              "conn-clean-worker-%d");
-            Number idleTimeProp = (Number) config.getProperty("idleTime");
-            final long idleTime = idleTimeProp == null ?
-                                  IDLE_TIME : idleTimeProp.longValue();
-            final long checkPeriod = idleTime / 2L;
-            this.cleanExecutor.scheduleWithFixedDelay(() -> {
-                PoolStats stats = this.pool.getTotalStats();
-                int using = stats.getLeased() + stats.getPending();
-                if (using > 0) {
-                    // Do clean only when all connections are idle
-                    return;
-                }
-                // Release connections when all clients are inactive
-                this.pool.closeIdleConnections(idleTime, 
TimeUnit.MILLISECONDS);
-                this.pool.closeExpiredConnections();
-            }, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+    private static String parseContentType(RestHeaders headers) {
+        if (headers != null) {
+            String contentType = headers.get("Content-Type");
+            if (contentType != null) {
+                return contentType;
+            }
         }
+        return "application/json";
     }
 
-    protected abstract void checkStatus(Response response,
-                                        Response.Status... statuses);
+    private OkHttpClient getOkhttpClient(OkhttpConfig okhttpConfig) {
+        OkHttpClient.Builder builder = new OkHttpClient.Builder();
 
-    protected Response request(Callable<Response> method) {
-        try {
-            return method.call();
-        } catch (Exception e) {
-            throw new ClientException("Failed to do request", e);
+        if (okhttpConfig.getTimeout() != null) {
+            builder.connectTimeout(okhttpConfig.getTimeout(), 
TimeUnit.MILLISECONDS)
+                   .readTimeout(okhttpConfig.getTimeout(), 
TimeUnit.MILLISECONDS);
+        }
+
+        if (okhttpConfig.getIdleTime() != null) {
+            ConnectionPool connectionPool =
+                    new ConnectionPool(5, okhttpConfig.getIdleTime(), 
TimeUnit.MILLISECONDS);
+            builder.connectionPool(connectionPool);
+        }
+
+
+        // auth header interceptor
+        if (StringUtils.isNotBlank(okhttpConfig.getUser()) &&
+            StringUtils.isNotBlank(okhttpConfig.getPassword())) {
+            builder.addInterceptor(new 
OkhttpBasicAuthInterceptor(okhttpConfig.getUser(),
+                                                                  
okhttpConfig.getPassword()));
+        }
+        if (StringUtils.isNotBlank(okhttpConfig.getToken())) {
+            builder.addInterceptor(new 
OkhttpTokenInterceptor(okhttpConfig.getToken()));
+        }
+
+        // ssl
+        configSsl(builder, baseUrl, okhttpConfig.getTrustStoreFile(),

Review Comment:
   this.baseUrl



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);

Review Comment:
   rename object to body?



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);
+            }
+        } else {
+            bodyContent = String.valueOf(object);
+        }
+        RequestBody requestBody = 
RequestBody.create(MediaType.parse(contentType), bodyContent);
 
-    public AbstractRestClient(String url, String token, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .build());
+        if (headers != null && "gzip".equals(headers.get("Content-Encoding"))) 
{
+            requestBody = gzip(requestBody);
+        }
+        return requestBody;
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+    private static RequestBody gzip(final RequestBody body) {
+        return new RequestBody() {
+            @Override
+            public MediaType contentType() {
+                return body.contentType();
+            }
+
+            @Override
+            public long contentLength() {
+                return -1; // We don't know the compressed length in advance!
+            }
+
+            @Override
+            public void writeTo(BufferedSink sink) throws IOException {
+                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+                body.writeTo(gzipSink);
+                gzipSink.close();
+            }
+        };
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute,
-                              String trustStoreFile,
-                              String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
-
-    public AbstractRestClient(String url, ClientConfig config) {
-        configConnectionManager(url, config);
-
-        this.client = JerseyClientBuilder.newClient(config);
-        this.client.register(GZipEncoder.class);
-        this.target = this.client.target(url);
-        this.pool = (PoolingHttpClientConnectionManager) config.getProperty(
-                    ApacheClientProperties.CONNECTION_MANAGER);
-        if (this.pool != null) {
-            this.cleanExecutor = ExecutorUtil.newScheduledThreadPool(
-                                              "conn-clean-worker-%d");
-            Number idleTimeProp = (Number) config.getProperty("idleTime");
-            final long idleTime = idleTimeProp == null ?
-                                  IDLE_TIME : idleTimeProp.longValue();
-            final long checkPeriod = idleTime / 2L;
-            this.cleanExecutor.scheduleWithFixedDelay(() -> {
-                PoolStats stats = this.pool.getTotalStats();
-                int using = stats.getLeased() + stats.getPending();
-                if (using > 0) {
-                    // Do clean only when all connections are idle
-                    return;
-                }
-                // Release connections when all clients are inactive
-                this.pool.closeIdleConnections(idleTime, 
TimeUnit.MILLISECONDS);
-                this.pool.closeExpiredConnections();
-            }, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+    private static String parseContentType(RestHeaders headers) {
+        if (headers != null) {
+            String contentType = headers.get("Content-Type");
+            if (contentType != null) {
+                return contentType;
+            }
         }
+        return "application/json";
     }
 
-    protected abstract void checkStatus(Response response,
-                                        Response.Status... statuses);
+    private OkHttpClient getOkhttpClient(OkhttpConfig okhttpConfig) {
+        OkHttpClient.Builder builder = new OkHttpClient.Builder();
 
-    protected Response request(Callable<Response> method) {
-        try {
-            return method.call();
-        } catch (Exception e) {
-            throw new ClientException("Failed to do request", e);
+        if (okhttpConfig.getTimeout() != null) {
+            builder.connectTimeout(okhttpConfig.getTimeout(), 
TimeUnit.MILLISECONDS)
+                   .readTimeout(okhttpConfig.getTimeout(), 
TimeUnit.MILLISECONDS);
+        }
+
+        if (okhttpConfig.getIdleTime() != null) {
+            ConnectionPool connectionPool =
+                    new ConnectionPool(5, okhttpConfig.getIdleTime(), 
TimeUnit.MILLISECONDS);
+            builder.connectionPool(connectionPool);
+        }
+
+
+        // auth header interceptor
+        if (StringUtils.isNotBlank(okhttpConfig.getUser()) &&
+            StringUtils.isNotBlank(okhttpConfig.getPassword())) {
+            builder.addInterceptor(new 
OkhttpBasicAuthInterceptor(okhttpConfig.getUser(),
+                                                                  
okhttpConfig.getPassword()));
+        }
+        if (StringUtils.isNotBlank(okhttpConfig.getToken())) {
+            builder.addInterceptor(new 
OkhttpTokenInterceptor(okhttpConfig.getToken()));
+        }
+
+        // ssl
+        configSsl(builder, baseUrl, okhttpConfig.getTrustStoreFile(),
+                  okhttpConfig.getTrustStorePassword());

Review Comment:
   okhttpConfig => okHttpConfig



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();
 
     public AbstractRestClient(String url, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout).build());
+        this(url, OkhttpConfig.builder()
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
-                              int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .build());
+                              Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .build());
     }
 
     public AbstractRestClient(String url, int timeout,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, null, null, timeout, maxTotal, maxPerRoute);
     }
 
     public AbstractRestClient(String url, int timeout, int idleTime,
                               int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configIdleTime(idleTime)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .idleTime(idleTime)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
     }
 
     public AbstractRestClient(String url, String user, String password,
                               int timeout, int maxTotal, int maxPerRoute,
                               String trustStoreFile,
                               String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configUser(user, password)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
+        this(url, OkhttpConfig.builder()
+                              .user(user).password(password)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, String token, Integer timeout,
+                              Integer maxTotal, Integer maxPerRoute,
+                              String trustStoreFile,
+                              String trustStorePassword) {
+        this(url, OkhttpConfig.builder()
+                              .token(token)
+                              .timeout(timeout)
+                              .maxTotal(maxTotal)
+                              .maxPerRoute(maxPerRoute)
+                              .trustStoreFile(trustStoreFile)
+                              .trustStorePassword(trustStorePassword)
+                              .build());
+    }
+
+    public AbstractRestClient(String url, OkhttpConfig okhttpConfig) {
+        this.baseUrl = url;
+        this.client = getOkhttpClient(okhttpConfig);
+    }
+
+    private static RequestBody getRequestBody(Object object, RestHeaders 
headers) {
+        String contentType = parseContentType(headers);
+        String bodyContent;
+        if ("application/json".equals(contentType)) {
+            if (object == null) {
+                bodyContent = "{}";
+            } else {
+                bodyContent = JsonUtil.toJson(object);
+            }
+        } else {
+            bodyContent = String.valueOf(object);
+        }
+        RequestBody requestBody = 
RequestBody.create(MediaType.parse(contentType), bodyContent);
 
-    public AbstractRestClient(String url, String token, int timeout) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .build());
+        if (headers != null && "gzip".equals(headers.get("Content-Encoding"))) 
{
+            requestBody = gzip(requestBody);
+        }
+        return requestBody;
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .build());
+    private static RequestBody gzip(final RequestBody body) {
+        return new RequestBody() {
+            @Override
+            public MediaType contentType() {
+                return body.contentType();
+            }
+
+            @Override
+            public long contentLength() {
+                return -1; // We don't know the compressed length in advance!
+            }
+
+            @Override
+            public void writeTo(BufferedSink sink) throws IOException {
+                BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
+                body.writeTo(gzipSink);
+                gzipSink.close();
+            }
+        };
     }
 
-    public AbstractRestClient(String url, String token, int timeout,
-                              int maxTotal, int maxPerRoute,
-                              String trustStoreFile,
-                              String trustStorePassword) {
-        this(url, new ConfigBuilder().configTimeout(timeout)
-                                     .configToken(token)
-                                     .configPool(maxTotal, maxPerRoute)
-                                     .configSSL(trustStoreFile,
-                                                trustStorePassword)
-                                     .build());
-    }
-
-    public AbstractRestClient(String url, ClientConfig config) {
-        configConnectionManager(url, config);
-
-        this.client = JerseyClientBuilder.newClient(config);
-        this.client.register(GZipEncoder.class);
-        this.target = this.client.target(url);
-        this.pool = (PoolingHttpClientConnectionManager) config.getProperty(
-                    ApacheClientProperties.CONNECTION_MANAGER);
-        if (this.pool != null) {
-            this.cleanExecutor = ExecutorUtil.newScheduledThreadPool(
-                                              "conn-clean-worker-%d");
-            Number idleTimeProp = (Number) config.getProperty("idleTime");
-            final long idleTime = idleTimeProp == null ?
-                                  IDLE_TIME : idleTimeProp.longValue();
-            final long checkPeriod = idleTime / 2L;
-            this.cleanExecutor.scheduleWithFixedDelay(() -> {
-                PoolStats stats = this.pool.getTotalStats();
-                int using = stats.getLeased() + stats.getPending();
-                if (using > 0) {
-                    // Do clean only when all connections are idle
-                    return;
-                }
-                // Release connections when all clients are inactive
-                this.pool.closeIdleConnections(idleTime, 
TimeUnit.MILLISECONDS);
-                this.pool.closeExpiredConnections();
-            }, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+    private static String parseContentType(RestHeaders headers) {
+        if (headers != null) {
+            String contentType = headers.get("Content-Type");

Review Comment:
   add a const var to RestHeaders?



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestHeaders.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.hugegraph.rest;
+
+import java.util.Date;
+
+public class RestHeaders {
+    private final okhttp3.Headers.Builder headersBuilder = new 
okhttp3.Headers.Builder();
+
+    public String get(String key) {
+        return headersBuilder.get(key);
+    }
+
+    public Date getDate(String key) {
+        return headersBuilder.build().getDate(key);
+    }
+
+    public RestHeaders add(String key, String value) {
+        headersBuilder.add(key, value);
+        return this;
+    }
+
+    public RestHeaders add(String key, Date value) {
+        headersBuilder.add(key, value);
+        return this;
+    }
+
+    public okhttp3.Headers toOkhttpHeader() {

Review Comment:
   prefer to mark protected



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestHeaders.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.hugegraph.rest;
+
+import java.util.Date;
+
+public class RestHeaders {
+    private final okhttp3.Headers.Builder headersBuilder = new 
okhttp3.Headers.Builder();
+
+    public String get(String key) {
+        return headersBuilder.get(key);

Review Comment:
   this.xx



##########
hugegraph-common/src/test/java/org/apache/hugegraph/unit/rest/RestResultTest.java:
##########
@@ -19,22 +19,45 @@
 
 import java.util.Map;
 
-import jakarta.ws.rs.core.MultivaluedHashMap;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
+import org.apache.hugegraph.rest.RestResult;
+import org.apache.hugegraph.rest.SerializeException;
+import org.apache.hugegraph.testutil.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
-import org.apache.hugegraph.rest.RestResult;
-import org.apache.hugegraph.rest.SerializeException;
-import org.apache.hugegraph.testutil.Assert;
+import lombok.SneakyThrows;
+import okhttp3.Headers;
+import okhttp3.Response;
 
 public class RestResultTest {
 
+    private static RestResult newRestResult(int status) {
+        return newRestResult(status, "", new Headers.Builder().build());
+    }
+
+    private static RestResult newRestResult(int status, String content) {
+        return newRestResult(status, content, new Headers.Builder().build());
+    }
+
+    private static RestResult newRestResult(int status,
+                                            Headers h) {
+        return newRestResult(status, "", h);
+    }
+
+    @SneakyThrows
+    private static RestResult newRestResult(int status, String content,
+                                            Headers h) {

Review Comment:
   ditto



##########
hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java:
##########
@@ -17,188 +17,246 @@
 
 package org.apache.hugegraph.rest;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.SecureRandom;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import org.apache.commons.collections.MapUtils;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.apache.http.HttpHeaders;
-import org.apache.http.config.Registry;
-import org.apache.http.config.RegistryBuilder;
-import org.apache.http.conn.socket.ConnectionSocketFactory;
-import org.apache.http.conn.socket.PlainConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.pool.PoolStats;
-import org.apache.hugegraph.util.E;
-import org.apache.hugegraph.util.ExecutorUtil;
-import org.glassfish.jersey.SslConfigurator;
-import org.glassfish.jersey.apache.connector.ApacheClientProperties;
-import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.JerseyClientBuilder;
-import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
-import org.glassfish.jersey.internal.util.collection.Ref;
-import org.glassfish.jersey.internal.util.collection.Refs;
-import org.glassfish.jersey.message.GZipEncoder;
-import org.glassfish.jersey.uri.UriComponent;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hugegraph.util.JsonUtil;
 
 import com.google.common.collect.ImmutableMap;
 
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientRequestContext;
-import jakarta.ws.rs.client.ClientRequestFilter;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation.Builder;
-import jakarta.ws.rs.client.WebTarget;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.core.Variant;
+import lombok.SneakyThrows;
+import okhttp3.ConnectionPool;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okio.BufferedSink;
+import okio.GzipSink;
+import okio.Okio;
 
 public abstract class AbstractRestClient implements RestClient {
 
-    // Time unit: hours
-    private static final long TTL = 24L;
-    // Time unit: ms
-    private static final long IDLE_TIME = 40L * 1000L;
-
-    private static final String TOKEN_KEY = "tokenKey";
-
-    private final Client client;
-    private final WebTarget target;
-
-    private PoolingHttpClientConnectionManager pool;
-    private ScheduledExecutorService cleanExecutor;
+    private final ThreadLocal<String> authContext =
+            new InheritableThreadLocal<>();
+    private final OkHttpClient client;
+    private final String baseUrl;
+    private final Request.Builder requestBuilder = new Request.Builder();

Review Comment:
   also move into the constructor?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscr...@hugegraph.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to