javeme commented on code in PR #133: URL: https://github.com/apache/incubator-hugegraph-commons/pull/133#discussion_r1382325111
########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java: ########## @@ -316,40 +385,35 @@ public RestResult delete(String path, String id) { return this.delete(path, id, ImmutableMap.of()); } + @SneakyThrows private RestResult delete(String path, String id, Map<String, Object> params) { - Ref<WebTarget> target = Refs.of(this.target); - for (String key : params.keySet()) { - target.set(target.get().queryParam(key, params.get(key))); + Request.Builder requestBuilder = getRequestBuilder(path, id, null, params); + requestBuilder.delete(); + + try (Response response = request(requestBuilder)) { + checkStatus(response, 204, 202); + return new RestResult(response); } + } - Response response = this.request(() -> { - WebTarget webTarget = target.get(); - Builder builder = id == null ? webTarget.path(path).request() : - webTarget.path(path).path(encode(id)).request(); - this.attachAuthToRequest(builder); - return builder.delete(); - }); + protected abstract void checkStatus(Response response, int... statuses); - checkStatus(response, Response.Status.NO_CONTENT, - Response.Status.ACCEPTED); - return new RestResult(response); + @SneakyThrows + protected Response request(Request.Builder requestBuilder) { + return client.newCall(requestBuilder.build()).execute(); } + @SneakyThrows @Override public void close() { - if (this.pool != null) { - this.pool.close(); - this.cleanExecutor.shutdownNow(); + if (client != null) { Review Comment: this.client ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestResult.java: ########## @@ -66,7 +74,7 @@ public <T> T readObject(Class<T> clazz) { return MAPPER.readValue(this.content, clazz); } catch (Exception e) { throw new SerializeException( - "Failed to deserialize: %s", e, this.content); + "Failed to deserialize: %s", e, this.content); Review Comment: can we keep the origin style? ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/RequestHeaders.java: ########## @@ -0,0 +1,26 @@ +/* + * 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; + +public class RequestHeaders { Review Comment: I think the RestHeaders class is ok, so just move into RestHeaders? ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/RequestHeaders.java: ########## @@ -0,0 +1,26 @@ +/* + * 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; + +public class RequestHeaders { + + public static final String CONTENT_TYPE = "Content-Type"; + public static final String CONTENT_ENCODING = "Content-Encoding"; + public static final String APPLICATION_JSON = "application/json"; Review Comment: it is another category and belongs to the value type, in order to facilitate the subsequent addition of new values, can we put it in a separate block? ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestResult.java: ########## @@ -77,15 +85,15 @@ public <T> List<T> readList(String key, Class<T> clazz) { JsonNode element = root.get(key); if (element == null) { throw new SerializeException( - "Can't find value of the key: %s in json.", key); + "Can't find value of the key: %s in json.", key); Review Comment: ditto ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java: ########## @@ -395,21 +391,17 @@ private RestResult delete(String path, String id, Request.Builder requestBuilder = getRequestBuilder(path, id, null, params); requestBuilder.delete(); - try (Response response = this.request( - () -> client.newCall(requestBuilder.build()).execute())) { + try (Response response = request(requestBuilder)) { checkStatus(response, 204, 202); return new RestResult(response); } } protected abstract void checkStatus(Response response, int... statuses); - protected Response request(Callable<Response> method) { - try { - return method.call(); - } catch (Exception e) { - throw new ClientException("Failed to do request", e); - } + @SneakyThrows + protected Response request(Request.Builder requestBuilder) { + return client.newCall(requestBuilder.build()).execute(); Review Comment: expect this.client style ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/RestResult.java: ########## @@ -21,39 +21,47 @@ 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.Response; + public class RestResult { private static final ObjectMapper MAPPER = new ObjectMapper(); private final int status; - private final MultivaluedMap<String, Object> headers; + private final RestHeaders headers; private final String content; public RestResult(Response response) { - this(response.getStatus(), response.readEntity(String.class), - response.getHeaders()); + this(response.code(), getResponseContent(response), + RestHeaders.convertToRestHeaders(response.headers())); } - public RestResult(int status, String content, - MultivaluedMap<String, Object> headers) { + public RestResult(int status, String content, RestHeaders 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); + } Review Comment: prefer to move these 2 methods to line 118 ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java: ########## @@ -360,132 +424,39 @@ public String getAuthContext() { return this.authContext.get(); } - private void attachAuthToRequest(Builder builder) { + public void setAuthContext(String auth) { + this.authContext.set(auth); + } Review Comment: prefer to not modify it, just keep it at line 418? ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/AbstractRestClient.java: ########## @@ -360,132 +424,39 @@ 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(RequestHeaders.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(); - - String encoding = null; - if (headers != null && !headers.isEmpty()) { - // Add headers - builder = builder.headers(headers); - encoding = (String) headers.getFirst("Content-Encoding"); - } - // Add auth header - this.attachAuthToRequest(builder); + @SneakyThrows + private X509TrustManager trustManagerForCertificates(String trustStoreFile, + String trustStorePass) { + char[] password = trustStorePass.toCharArray(); - /* - * 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); + // load keyStore + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + try (FileInputStream in = new FileInputStream(trustStoreFile)) { + keyStore.load(in, password); } - 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()); - } - 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); - } + TrustManagerFactory trustManagerFactory = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(keyStore); - 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); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { + throw new IllegalStateException("Unexpected default trust managers:" + + Arrays.toString(trustManagers)); Review Comment: expect this style: ```java throw new IllegalStateException("Unexpected default trust managers: " + Arrays.toString(trustManagers)); ``` ########## hugegraph-common/src/main/java/org/apache/hugegraph/rest/OkhttpBasicAuthInterceptor.java: ########## @@ -0,0 +1,46 @@ +/* + * 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.Credentials; +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +public class OkhttpBasicAuthInterceptor implements Interceptor { + + private final String credentials; + + public OkhttpBasicAuthInterceptor(String user, String password) { + this.credentials = Credentials.basic(user, password); + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + if (request.header(RequestHeaders.AUTHORIZATION) == null) { + Request authenticatedRequest = request.newBuilder() + .header(RequestHeaders.AUTHORIZATION, credentials) Review Comment: expect this.credentials -- 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