diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 7705bc0bfa9..f1849b09571 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -94,6 +94,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#7615](https://github.com/seata/seata/pull/7615)] Refactor DataSourceProxy
- [[#7617](https://github.com/seata/seata/pull/7617)] Refactor Alibaba Dubbo and HSF
+- [[#7684](https://github.com/apache/incubator-seata/pull/7684)] Refactor and unify the apis of http1 and http2
### doc:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index a34a0e3b19e..e5927016b23 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -92,6 +92,7 @@
- [[#7615](https://github.com/seata/seata/pull/7615)] 重构 DataSourceProxy
- [[#7617](https://github.com/seata/seata/pull/7617)] 重构 Alibaba Dubbo 和 HSF 模块
+- [[#7684](https://github.com/apache/incubator-seata/pull/7684)] 重构并统一http1和http2的API
### doc:
diff --git a/common/pom.xml b/common/pom.xml
index 2d2d047e8ec..8a1cfffea8a 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -55,6 +55,7 @@
com.squareup.okhttp3
okhttp
+ provided
diff --git a/common/src/main/java/org/apache/seata/common/util/HttpClientUtil.java b/common/src/main/java/org/apache/seata/common/http/Http1HttpExecutor.java
similarity index 63%
rename from common/src/main/java/org/apache/seata/common/util/HttpClientUtil.java
rename to common/src/main/java/org/apache/seata/common/http/Http1HttpExecutor.java
index 31a5f03ae38..e986230aa2e 100644
--- a/common/src/main/java/org/apache/seata/common/util/HttpClientUtil.java
+++ b/common/src/main/java/org/apache/seata/common/http/Http1HttpExecutor.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seata.common.util;
+package org.apache.seata.common.http;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.NameValuePair;
@@ -31,6 +31,9 @@
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.apache.seata.common.loader.LoadLevel;
+import org.apache.seata.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,9 +46,10 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-public class HttpClientUtil {
+@LoadLevel(name = "Http1", order = 1)
+public class Http1HttpExecutor implements HttpExecutor {
- private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(Http1HttpExecutor.class);
private static final Map HTTP_CLIENT_MAP = new ConcurrentHashMap<>();
@@ -54,6 +58,25 @@ public class HttpClientUtil {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+ public static volatile Http1HttpExecutor instance;
+
+ /**
+ * Gets instance.
+ *
+ * @return the instance
+ */
+ public static Http1HttpExecutor getInstance() {
+
+ if (instance == null) {
+ synchronized (Http1HttpExecutor.class) {
+ if (instance == null) {
+ instance = new Http1HttpExecutor();
+ }
+ }
+ }
+ return instance;
+ }
+
static {
POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setMaxTotal(10);
POOLING_HTTP_CLIENT_CONNECTION_MANAGER.setDefaultMaxPerRoute(10);
@@ -69,9 +92,9 @@ public class HttpClientUtil {
})));
}
- // post request
- public static CloseableHttpResponse doPost(
- String url, Map params, Map header, int timeout) throws IOException {
+ @Override
+ public HttpResult doPost(String url, Map params, Map header, int timeout)
+ throws IOException {
try {
URIBuilder builder = new URIBuilder(url);
URI uri = builder.build();
@@ -96,24 +119,27 @@ public static CloseableHttpResponse doPost(
httpPost.setEntity(stringEntity);
}
}
- CloseableHttpClient client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, k -> HttpClients.custom()
- .setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER)
- .setDefaultRequestConfig(RequestConfig.custom()
- .setConnectionRequestTimeout(timeout)
- .setSocketTimeout(timeout)
- .setConnectTimeout(timeout)
- .build())
- .build());
- return client.execute(httpPost);
+ CloseableHttpClient client = getHttpClient(timeout);
+ try (CloseableHttpResponse response = client.execute(httpPost)) {
+ int statusCode = response.getStatusLine() != null
+ ? response.getStatusLine().getStatusCode()
+ : 0;
+
+ String responseBody = null;
+ if (response.getEntity() != null) {
+ responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+ }
+
+ return new HttpResult(statusCode, responseBody, null);
+ }
} catch (URISyntaxException | ClientProtocolException e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}
- // post request
- public static CloseableHttpResponse doPost(String url, String body, Map header, int timeout)
- throws IOException {
+ @Override
+ public HttpResult doPost(String url, String body, Map header, int timeout) throws IOException {
try {
URIBuilder builder = new URIBuilder(url);
URI uri = builder.build();
@@ -129,24 +155,28 @@ public static CloseableHttpResponse doPost(String url, String body, Map HttpClients.custom()
- .setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER)
- .setDefaultRequestConfig(RequestConfig.custom()
- .setConnectionRequestTimeout(timeout)
- .setSocketTimeout(timeout)
- .setConnectTimeout(timeout)
- .build())
- .build());
- return client.execute(httpPost);
+ CloseableHttpClient client = getHttpClient(timeout);
+ try (CloseableHttpResponse response = client.execute(httpPost)) {
+ int statusCode = response.getStatusLine() != null
+ ? response.getStatusLine().getStatusCode()
+ : 0;
+
+ String responseBody = null;
+ if (response.getEntity() != null) {
+ responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+ }
+
+ return new HttpResult(statusCode, responseBody, null);
+ }
} catch (URISyntaxException | ClientProtocolException e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}
- // get request
- public static CloseableHttpResponse doGet(
- String url, Map param, Map header, int timeout) throws IOException {
+ @Override
+ public HttpResult doGet(String url, Map param, Map header, int timeout)
+ throws IOException {
try {
URIBuilder builder = new URIBuilder(url);
if (param != null) {
@@ -159,40 +189,33 @@ public static CloseableHttpResponse doGet(
if (header != null) {
header.forEach(httpGet::addHeader);
}
- CloseableHttpClient client = HTTP_CLIENT_MAP.computeIfAbsent(timeout, k -> HttpClients.custom()
- .setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER)
- .setDefaultRequestConfig(RequestConfig.custom()
- .setConnectionRequestTimeout(timeout)
- .setSocketTimeout(timeout)
- .setConnectTimeout(timeout)
- .build())
- .build());
- return client.execute(httpGet);
+ CloseableHttpClient client = getHttpClient(timeout);
+ try (CloseableHttpResponse response = client.execute(httpGet)) {
+ int statusCode = response.getStatusLine() != null
+ ? response.getStatusLine().getStatusCode()
+ : 0;
+
+ String responseBody = null;
+ if (response.getEntity() != null) {
+ responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+ }
+
+ return new HttpResult(statusCode, responseBody, null);
+ }
} catch (URISyntaxException | ClientProtocolException e) {
LOGGER.error(e.getMessage(), e);
}
return null;
}
- public static CloseableHttpResponse doPostJson(
- String url, String jsonBody, Map headers, int timeout) throws IOException {
- RequestConfig requestConfig = RequestConfig.custom()
- .setSocketTimeout(timeout)
- .setConnectTimeout(timeout)
- .build();
-
- HttpPost post = new HttpPost(url);
- post.setConfig(requestConfig);
-
- if (headers != null) {
- headers.forEach(post::addHeader);
- }
- post.setHeader("Content-Type", "application/json");
-
- StringEntity entity = new StringEntity(jsonBody, StandardCharsets.UTF_8);
- post.setEntity(entity);
-
- CloseableHttpClient client = HttpClients.createDefault();
- return client.execute(post);
+ private static CloseableHttpClient getHttpClient(int timeout) {
+ return HTTP_CLIENT_MAP.computeIfAbsent(timeout, k -> HttpClients.custom()
+ .setConnectionManager(POOLING_HTTP_CLIENT_CONNECTION_MANAGER)
+ .setDefaultRequestConfig(RequestConfig.custom()
+ .setConnectionRequestTimeout(timeout)
+ .setSocketTimeout(timeout)
+ .setConnectTimeout(timeout)
+ .build())
+ .build());
}
}
diff --git a/common/src/main/java/org/apache/seata/common/http/Http2HttpExecutor.java b/common/src/main/java/org/apache/seata/common/http/Http2HttpExecutor.java
new file mode 100644
index 00000000000..b873fccfed3
--- /dev/null
+++ b/common/src/main/java/org/apache/seata/common/http/Http2HttpExecutor.java
@@ -0,0 +1,245 @@
+/*
+ * 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.seata.common.http;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.FormBody;
+import okhttp3.Headers;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import org.apache.seata.common.loader.LoadLevel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@LoadLevel(name = "Http2", order = 2)
+public class Http2HttpExecutor implements HttpExecutor {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Http2HttpExecutor.class);
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
+ .connectTimeout(10, TimeUnit.SECONDS)
+ .readTimeout(10, TimeUnit.SECONDS)
+ .writeTimeout(10, TimeUnit.SECONDS)
+ .build();
+
+ public static volatile Http2HttpExecutor instance;
+
+ /**
+ * Gets instance.
+ *
+ * @return the instance
+ */
+ public static Http2HttpExecutor getInstance() {
+
+ if (instance == null) {
+ synchronized (Http2HttpExecutor.class) {
+ if (instance == null) {
+ instance = new Http2HttpExecutor();
+ }
+ }
+ }
+ return instance;
+ }
+
+ public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json");
+ public static final MediaType MEDIA_TYPE_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded");
+
+ @Override
+ public HttpResult doPost(String url, Map params, Map headers, int timeout)
+ throws IOException {
+ try {
+ Headers.Builder headerBuilder = new Headers.Builder();
+ if (headers != null) {
+ headers.forEach(headerBuilder::add);
+ }
+
+ String contentType = headers != null ? headers.get("Content-Type") : "";
+ RequestBody requestBody = createRequestBody(params, contentType);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .headers(headerBuilder.build())
+ .post(requestBody)
+ .build();
+
+ CompletableFuture future = new CompletableFuture<>();
+ HTTP_CLIENT.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ future.completeExceptionally(e);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ try {
+ String responseBody =
+ response.body() != null ? response.body().string() : null;
+ future.complete(new HttpResult(response.code(), responseBody, response));
+ } catch (IOException e) {
+ future.completeExceptionally(e);
+ } finally {
+ response.close();
+ }
+ }
+ });
+
+ try {
+ return future.get(timeout, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ throw new IOException("HTTP2 request failed", e);
+ }
+
+ } catch (JsonProcessingException e) {
+ LOGGER.error(e.getMessage(), e);
+ throw new IOException("Failed to serialize request params to JSON", e);
+ }
+ }
+
+ @Override
+ public HttpResult doPost(String url, String body, Map headers, int timeout) throws IOException {
+ try {
+ Headers.Builder headerBuilder = new Headers.Builder();
+ if (headers != null) {
+ headers.forEach(headerBuilder::add);
+ }
+
+ RequestBody requestBody = RequestBody.create(body, MEDIA_TYPE_JSON);
+
+ Request request = new Request.Builder()
+ .url(url)
+ .headers(headerBuilder.build())
+ .post(requestBody)
+ .build();
+
+ CompletableFuture future = new CompletableFuture<>();
+ HTTP_CLIENT.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ future.completeExceptionally(e);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ try {
+ String responseBody =
+ response.body() != null ? response.body().string() : null;
+ future.complete(new HttpResult(response.code(), responseBody, response));
+ } catch (IOException e) {
+ future.completeExceptionally(e);
+ } finally {
+ response.close();
+ }
+ }
+ });
+
+ try {
+ return future.get(timeout, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ throw new IOException("HTTP2 POST request failed or timed out", e);
+ }
+ } catch (Exception e) {
+ throw new IOException("Failed to execute HTTP2 POST request", e);
+ }
+ }
+
+ @Override
+ public HttpResult doGet(String url, Map param, Map headers, int timeout)
+ throws IOException {
+ try {
+ HttpUrl finalUrl = Objects.requireNonNull(HttpUrl.get(url), "Invalid URL");
+ if (param != null) {
+ for (Map.Entry entry : param.entrySet()) {
+ finalUrl = finalUrl.newBuilder()
+ .addQueryParameter(entry.getKey(), entry.getValue())
+ .build();
+ }
+ }
+
+ Headers.Builder headerBuilder = new Headers.Builder();
+ if (headers != null) {
+ headers.forEach(headerBuilder::add);
+ }
+
+ Request request = new Request.Builder()
+ .url(finalUrl)
+ .headers(headerBuilder.build())
+ .get()
+ .build();
+
+ CompletableFuture future = new CompletableFuture<>();
+ HTTP_CLIENT.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ future.completeExceptionally(e);
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ try {
+ String responseBody =
+ response.body() != null ? response.body().string() : null;
+ future.complete(new HttpResult(response.code(), responseBody, response));
+ } catch (IOException e) {
+ future.completeExceptionally(e);
+ } finally {
+ response.close();
+ }
+ }
+ });
+
+ try {
+ return future.get(timeout, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ throw new IOException("HTTP2 GET request failed or timed out", e);
+ }
+
+ } catch (Exception e) {
+ throw new IOException("Failed to execute HTTP2 GET request", e);
+ }
+ }
+
+ private RequestBody createRequestBody(Map params, String contentType)
+ throws JsonProcessingException {
+ if (params == null || params.isEmpty()) {
+ return RequestBody.create(new byte[0]);
+ }
+
+ if (MEDIA_TYPE_FORM_URLENCODED.toString().equals(contentType)) {
+ FormBody.Builder formBuilder = new FormBody.Builder();
+ params.forEach(formBuilder::add);
+ return formBuilder.build();
+ } else {
+ String json = OBJECT_MAPPER.writeValueAsString(params);
+ return RequestBody.create(json, MEDIA_TYPE_JSON);
+ }
+ }
+}
diff --git a/common/src/test/java/org/apache/seata/common/util/HttpClientUtilTest.java b/common/src/main/java/org/apache/seata/common/http/HttpExecutor.java
similarity index 64%
rename from common/src/test/java/org/apache/seata/common/util/HttpClientUtilTest.java
rename to common/src/main/java/org/apache/seata/common/http/HttpExecutor.java
index b20f1cbfcec..340811736c5 100644
--- a/common/src/test/java/org/apache/seata/common/util/HttpClientUtilTest.java
+++ b/common/src/main/java/org/apache/seata/common/http/HttpExecutor.java
@@ -14,19 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.seata.common.util;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
+package org.apache.seata.common.http;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.Map;
+
+public interface HttpExecutor {
+
+ HttpResult doPost(String url, Map params, Map header, int timeout)
+ throws IOException;
-public class HttpClientUtilTest {
+ HttpResult doPost(String url, String body, Map header, int timeout) throws IOException;
- @Test
- public void testDoPost() throws IOException {
- Assertions.assertNull(HttpClientUtil.doPost("test", new HashMap<>(), new HashMap<>(), 0));
- Assertions.assertNull(HttpClientUtil.doGet("test", new HashMap<>(), new HashMap<>(), 0));
- }
+ HttpResult doGet(String url, Map param, Map header, int timeout) throws IOException;
}
diff --git a/common/src/main/java/org/apache/seata/common/http/HttpExecutorFactory.java b/common/src/main/java/org/apache/seata/common/http/HttpExecutorFactory.java
new file mode 100644
index 00000000000..c89ccd2026a
--- /dev/null
+++ b/common/src/main/java/org/apache/seata/common/http/HttpExecutorFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.seata.common.http;
+
+import org.apache.seata.common.loader.EnhancedServiceLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HttpExecutorFactory {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HttpExecutorFactory.class);
+
+ private static final String HTTP1_IMPL = "Http1";
+ private static final String HTTP2_IMPL = "Http2";
+ private static final HttpExecutor INSTANCE = createInstance();
+
+ private HttpExecutorFactory() {}
+
+ private static HttpExecutor createInstance() {
+ String implName = isOkHttpAvailable() ? HTTP2_IMPL : HTTP1_IMPL;
+ return EnhancedServiceLoader.load(HttpExecutor.class, implName);
+ }
+
+ private static boolean isOkHttpAvailable() {
+ try {
+ Class.forName("okhttp3.OkHttpClient", false, HttpExecutorFactory.class.getClassLoader());
+ return true;
+ } catch (ClassNotFoundException ignored) {
+ LOGGER.warn("HTTP2 implementation not available in classpath, falling back to default executor!");
+ return false;
+ }
+ }
+
+ public static HttpExecutor getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/common/src/main/java/org/apache/seata/common/http/HttpResult.java b/common/src/main/java/org/apache/seata/common/http/HttpResult.java
new file mode 100644
index 00000000000..7fd1c82922d
--- /dev/null
+++ b/common/src/main/java/org/apache/seata/common/http/HttpResult.java
@@ -0,0 +1,56 @@
+/*
+ * 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.seata.common.http;
+
+public class HttpResult {
+
+ private int statusCode;
+ private String responseBody;
+ private Object rawResponse;
+
+ public HttpResult() {}
+
+ public HttpResult(int statusCode, String responseBody, Object rawResponse) {
+ this.statusCode = statusCode;
+ this.responseBody = responseBody;
+ this.rawResponse = rawResponse;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public String getResponseBody() {
+ return responseBody;
+ }
+
+ public void setResponseBody(String responseBody) {
+ this.responseBody = responseBody;
+ }
+
+ public Object getRawResponse() {
+ return rawResponse;
+ }
+
+ public void setRawResponse(Object rawResponse) {
+ this.rawResponse = rawResponse;
+ }
+}
diff --git a/common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java b/common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java
deleted file mode 100644
index bcf95a00e55..00000000000
--- a/common/src/main/java/org/apache/seata/common/util/Http5ClientUtil.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.seata.common.util;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.FormBody;
-import okhttp3.Headers;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import org.apache.seata.common.executor.HttpCallback;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-public class Http5ClientUtil {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(Http5ClientUtil.class);
-
- private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
- private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
- .connectTimeout(10, TimeUnit.SECONDS)
- .readTimeout(10, TimeUnit.SECONDS)
- .writeTimeout(10, TimeUnit.SECONDS)
- .build();
-
- public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json");
- public static final MediaType MEDIA_TYPE_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded");
-
- public static void doPostHttp(
- String url, Map params, Map headers, HttpCallback callback) {
- try {
- Headers.Builder headerBuilder = new Headers.Builder();
- if (headers != null) {
- headers.forEach(headerBuilder::add);
- }
-
- String contentType = headers != null ? headers.get("Content-Type") : "";
- RequestBody requestBody = createRequestBody(params, contentType);
-
- Request request = new Request.Builder()
- .url(url)
- .headers(headerBuilder.build())
- .post(requestBody)
- .build();
-
- executeAsync(HTTP_CLIENT, request, callback);
-
- } catch (JsonProcessingException e) {
- LOGGER.error(e.getMessage(), e);
- callback.onFailure(e);
- }
- }
-
- public static void doPostHttp(
- String url, String body, Map headers, HttpCallback callback) {
- Headers.Builder headerBuilder = new Headers.Builder();
- if (headers != null) {
- headers.forEach(headerBuilder::add);
- }
-
- RequestBody requestBody = RequestBody.create(body, MEDIA_TYPE_JSON);
-
- Request request = new Request.Builder()
- .url(url)
- .headers(headerBuilder.build())
- .post(requestBody)
- .build();
-
- executeAsync(HTTP_CLIENT, request, callback);
- }
-
- public static void doGetHttp(
- String url, Map headers, final HttpCallback callback, int timeout) {
- OkHttpClient client = new OkHttpClient.Builder()
- .connectTimeout(timeout, TimeUnit.SECONDS)
- .readTimeout(timeout, TimeUnit.SECONDS)
- .writeTimeout(timeout, TimeUnit.SECONDS)
- .build();
-
- Headers.Builder headerBuilder = new Headers.Builder();
- if (headers != null) {
- headers.forEach(headerBuilder::add);
- }
-
- Request request = new Request.Builder()
- .url(url)
- .headers(headerBuilder.build())
- .get()
- .build();
-
- executeAsync(client, request, callback);
- }
-
- private static RequestBody createRequestBody(Map params, String contentType)
- throws JsonProcessingException {
- if (params == null || params.isEmpty()) {
- return RequestBody.create(new byte[0]);
- }
-
- if (MEDIA_TYPE_FORM_URLENCODED.toString().equals(contentType)) {
- FormBody.Builder formBuilder = new FormBody.Builder();
- params.forEach(formBuilder::add);
- return formBuilder.build();
- } else {
- String json = OBJECT_MAPPER.writeValueAsString(params);
- return RequestBody.create(json, MEDIA_TYPE_JSON);
- }
- }
-
- private static void executeAsync(OkHttpClient client, Request request, final HttpCallback callback) {
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
- try {
- callback.onSuccess(response);
- } finally {
- response.close();
- }
- }
-
- @Override
- public void onFailure(Call call, IOException e) {
- if (call.isCanceled()) {
- callback.onCancelled();
- } else {
- callback.onFailure(e);
- }
- }
- });
- }
-}
diff --git a/common/src/main/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor b/common/src/main/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor
new file mode 100644
index 00000000000..499065af264
--- /dev/null
+++ b/common/src/main/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+org.apache.seata.common.http.Http1HttpExecutor
+org.apache.seata.common.http.Http2HttpExecutor
diff --git a/common/src/test/java/org/apache/seata/common/http/HttpExecutorFactoryTest.java b/common/src/test/java/org/apache/seata/common/http/HttpExecutorFactoryTest.java
new file mode 100644
index 00000000000..a488cb4dce1
--- /dev/null
+++ b/common/src/test/java/org/apache/seata/common/http/HttpExecutorFactoryTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.seata.common.http;
+
+import org.apache.seata.common.loader.EnhancedServiceLoader;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+
+class HttpExecutorFactoryTest {
+ @Test
+ void testGetInstance_singleton() {
+ HttpExecutor mockExecutor = mock(HttpExecutor.class);
+
+ try (MockedStatic loaderMock = mockStatic(EnhancedServiceLoader.class)) {
+ loaderMock
+ .when(() -> EnhancedServiceLoader.load(HttpExecutor.class, "Http1"))
+ .thenReturn(mockExecutor);
+
+ HttpExecutor first = HttpExecutorFactory.getInstance();
+ HttpExecutor second = HttpExecutorFactory.getInstance();
+
+ assertEquals(first, second);
+ }
+ }
+}
diff --git a/common/src/test/java/org/apache/seata/common/util/Http1HttpExecutorTest.java b/common/src/test/java/org/apache/seata/common/util/Http1HttpExecutorTest.java
new file mode 100644
index 00000000000..3695f68fa2d
--- /dev/null
+++ b/common/src/test/java/org/apache/seata/common/util/Http1HttpExecutorTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.seata.common.util;
+
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class Http1HttpExecutorTest {
+
+ @Test
+ public void testDoPost() throws IOException {
+ Assertions.assertNull(Http1HttpExecutor.getInstance().doPost("test", new HashMap<>(), new HashMap<>(), 0));
+ Assertions.assertNull(Http1HttpExecutor.getInstance().doGet("test", new HashMap<>(), new HashMap<>(), 0));
+ }
+
+ @Test
+ void testDoGetBaidu() throws Exception {
+ HashMap param = new HashMap<>();
+ param.put("wd", "seata");
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doGet("https://www.baidu.com", param, null, 5000);
+
+ assertNotNull(httpResult);
+ assertEquals(200, httpResult.getStatusCode());
+ }
+
+ @Test
+ void testDoPostNormal() throws Exception {
+ HashMap header = new HashMap<>();
+ header.put("Content-Type", "application/json");
+
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("https://postman-echo.com/post", "{\"name\":\"seata\"}", header, 5000);
+
+ assertNotNull(httpResult);
+ assertEquals(200, httpResult.getStatusCode());
+ assertTrue(httpResult.getResponseBody().contains("seata"));
+ }
+}
diff --git a/common/src/test/java/org/apache/seata/common/util/Http2HttpExecutorTest.java b/common/src/test/java/org/apache/seata/common/util/Http2HttpExecutorTest.java
new file mode 100644
index 00000000000..20264707118
--- /dev/null
+++ b/common/src/test/java/org/apache/seata/common/util/Http2HttpExecutorTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.seata.common.util;
+
+import okhttp3.Protocol;
+import okhttp3.Response;
+import org.apache.seata.common.http.Http2HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class Http2HttpExecutorTest {
+
+ @Test
+ void testDoPostHttp_param_onSuccess() throws Exception {
+
+ Map params = new HashMap<>();
+ params.put("key", "value");
+
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ HttpResult responseHttpResult =
+ Http2HttpExecutor.getInstance().doPost("https://www.cloudflare.com/", params, headers, 10000);
+
+ assertNotNull(responseHttpResult);
+ assertEquals(Protocol.HTTP_2, ((Response) responseHttpResult.getRawResponse()).protocol());
+ }
+
+ @Test
+ void testDoPostHttp_param_onFailure() {
+ Map params = new HashMap<>();
+ params.put("key", "value");
+
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ assertThrows(Exception.class, () -> Http2HttpExecutor.getInstance()
+ .doPost("http://localhost:9999/invalid", params, headers, 3000));
+ }
+
+ @Test
+ void testDoPostHttp_body_onSuccess() throws Exception {
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ HttpResult result = Http2HttpExecutor.getInstance()
+ .doPost("https://www.cloudflare.com/", "{\"key\":\"value\"}", headers, 10000);
+ assertNotNull(result);
+ assertEquals(Protocol.HTTP_2, ((Response) result.getRawResponse()).protocol());
+ }
+
+ @Test
+ void testDoPostHttp_body_onFailure() {
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ assertThrows(Exception.class, () -> Http2HttpExecutor.getInstance()
+ .doPost("http://localhost:9999/invalid", "{\"key\":\"value\"}", headers, 3000));
+ }
+
+ @Test
+ void testDoPostHttp_param_onSuccess_forceHttp1() throws Exception {
+ Map params = new HashMap<>();
+ params.put("key", "value");
+
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ HttpResult result = Http2HttpExecutor.getInstance().doPost("http://httpbin.org/post", params, headers, 10000);
+ assertNotNull(result);
+ assertEquals(Protocol.HTTP_1_1, ((Response) result.getRawResponse()).protocol());
+ }
+
+ @Test
+ void testDoGetHttp_onSuccess() throws Exception {
+ Map headers = new HashMap<>();
+ headers.put("Accept", "application/json");
+
+ HttpResult result = Http2HttpExecutor.getInstance().doGet("https://www.cloudflare.com/", null, headers, 10000);
+ assertNotNull(result);
+ assertEquals(Protocol.HTTP_2, ((Response) result.getRawResponse()).protocol());
+ }
+
+ @Test
+ void testDoGetHttp_withParams_onSuccess() throws Exception {
+ Map headers = new HashMap<>();
+ headers.put("Accept", "application/json");
+
+ Map params = new HashMap<>();
+ params.put("key", "value");
+
+ HttpResult result = Http2HttpExecutor.getInstance().doGet("https://www.cloudflare.com", params, headers, 10000);
+ assertNotNull(result);
+ assertEquals(Protocol.HTTP_2, ((Response) result.getRawResponse()).protocol());
+ }
+
+ @Test
+ void testDoPostHttp_body_onSuccess_forceHttp1() throws Exception {
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+
+ HttpResult result = Http2HttpExecutor.getInstance()
+ .doPost("http://httpbin.org/post", "{\"key\":\"value\"}", headers, 10000);
+ assertNotNull(result);
+ assertEquals(Protocol.HTTP_1_1, ((Response) result.getRawResponse()).protocol());
+ }
+}
diff --git a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java b/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
deleted file mode 100644
index 9b550067e75..00000000000
--- a/common/src/test/java/org/apache/seata/common/util/Http5ClientUtilTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * 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.seata.common.util;
-
-import okhttp3.Protocol;
-import okhttp3.Response;
-import org.apache.seata.common.executor.HttpCallback;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-class Http5ClientUtilTest {
-
- @Test
- void testDoPostHttp_param_onSuccess() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response result) {
- assertNotNull(result);
- assertEquals(Protocol.HTTP_2, result.protocol());
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable e) {
- fail("Should not fail");
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map params = new HashMap<>();
- params.put("key", "value");
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("https://www.apache.org/", params, headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoPostHttp_param_onFailure() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response response) {
- fail("Should not succeed");
- }
-
- @Override
- public void onFailure(Throwable t) {
- assertNotNull(t);
- latch.countDown();
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map params = new HashMap<>();
- params.put("key", "value");
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("http://localhost:9999/invalid", params, headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoPostHttp_body_onSuccess() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response result) {
- assertNotNull(result);
- assertEquals(Protocol.HTTP_2, result.protocol());
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable e) {
- fail("Should not fail");
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("https://www.apache.org/", "{\"key\":\"value\"}", headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoPostHttp_body_onFailure() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response response) {
- fail("Should not succeed");
- }
-
- @Override
- public void onFailure(Throwable t) {
- assertNotNull(t);
- latch.countDown();
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("http://localhost:9999/invalid", "{\"key\":\"value\"}", headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoPostHttp_param_onSuccess_forceHttp1() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response result) {
- assertNotNull(result);
- assertEquals(Protocol.HTTP_1_1, result.protocol());
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable e) {
- fail("Should not fail");
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map params = new HashMap<>();
- params.put("key", "value");
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("http://httpbin.org/post", params, headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoGetHttp_onSuccess() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response result) {
- assertNotNull(result);
- assertEquals(Protocol.HTTP_2, result.protocol());
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable e) {
- fail("Should not fail");
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map headers = new HashMap<>();
- headers.put("Accept", "application/json");
-
- Http5ClientUtil.doGetHttp("https://www.apache.org/", headers, callback, 1);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-
- @Test
- void testDoPostHttp_body_onSuccess_forceHttp1() throws Exception {
- CountDownLatch latch = new CountDownLatch(1);
-
- HttpCallback callback = new HttpCallback() {
- @Override
- public void onSuccess(Response result) {
- assertNotNull(result);
- assertEquals(Protocol.HTTP_1_1, result.protocol());
- latch.countDown();
- }
-
- @Override
- public void onFailure(Throwable e) {
- fail("Should not fail");
- }
-
- @Override
- public void onCancelled() {
- fail("Should not be cancelled");
- }
- };
-
- Map headers = new HashMap<>();
- headers.put("Content-Type", "application/json");
-
- Http5ClientUtil.doPostHttp("http://httpbin.org/post", "{\"key\":\"value\"}", headers, callback);
- assertTrue(latch.await(10, TimeUnit.SECONDS));
- }
-}
diff --git a/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java b/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
index 470cce840d8..5aecd455fa4 100644
--- a/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
+++ b/config/seata-config-nacos/src/test/java/org/apache/seata/config/nacos/NacosConfigurationTest.java
@@ -24,7 +24,6 @@
import org.apache.seata.config.ConfigurationFactory;
import org.apache.seata.config.Dispose;
import org.apache.seata.config.processor.ConfigProcessor;
-import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
@@ -195,7 +194,6 @@ public void testInnerReceiveThrowException() throws Exception {
Assertions.assertFalse(listener.invoked);
}
- @NotNull
private static NacosConfiguration.NacosListener getNacosListener(String dataId, TestListener listener)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException,
InvocationTargetException {
diff --git a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java
index 8eb28c439fe..adfa32f065b 100644
--- a/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java
+++ b/discovery/seata-discovery-namingserver/src/main/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImpl.java
@@ -21,14 +21,13 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpStatus;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EntityUtils;
import org.apache.seata.common.ConfigurationKeys;
import org.apache.seata.common.exception.AuthenticationFailedException;
import org.apache.seata.common.exception.RetryableException;
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.Cluster;
import org.apache.seata.common.metadata.ClusterRole;
import org.apache.seata.common.metadata.Instance;
@@ -38,7 +37,6 @@
import org.apache.seata.common.metadata.namingserver.Unit;
import org.apache.seata.common.thread.NamedThreadFactory;
import org.apache.seata.common.util.CollectionUtils;
-import org.apache.seata.common.util.HttpClientUtil;
import org.apache.seata.common.util.NetUtil;
import org.apache.seata.common.util.StringUtils;
import org.apache.seata.config.Configuration;
@@ -49,7 +47,6 @@
import java.io.IOException;
import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -230,8 +227,9 @@ public void doRegister(Instance instance, List urlList) throws Retryable
}
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
- try (CloseableHttpResponse response = HttpClientUtil.doPost(url, jsonBody, header, 3000)) {
- int statusCode = response.getStatusLine().getStatusCode();
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doPost(url, jsonBody, header, 3000);
+ int statusCode = httpResult.getStatusCode();
if (statusCode == 200) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("instance has been registered successfully:{}", statusCode);
@@ -249,8 +247,9 @@ public boolean doHealthCheck(String url) {
url = HTTP_PREFIX + url + "/naming/v1/health";
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
- try (CloseableHttpResponse response = HttpClientUtil.doGet(url, null, header, 3000)) {
- int statusCode = response.getStatusLine().getStatusCode();
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doGet(url, null, header, 3000);
+ int statusCode = httpResult.getStatusCode();
return statusCode == 200;
} catch (Exception e) {
return false;
@@ -274,8 +273,9 @@ public void unregister(Instance instance) {
url += params;
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
- try (CloseableHttpResponse response = HttpClientUtil.doPost(url, jsonBody, header, 3000)) {
- int statusCode = response.getStatusLine().getStatusCode();
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doPost(url, jsonBody, header, 3000);
+ int statusCode = httpResult.getStatusCode();
if (statusCode == 200) {
LOGGER.info("instance has been unregistered successfully:{}", statusCode);
} else {
@@ -357,10 +357,11 @@ public boolean watch(String vGroup) throws RetryableException {
if (StringUtils.isNotBlank(jwtToken)) {
header.put(AUTHORIZATION_HEADER, jwtToken);
}
- try (CloseableHttpResponse response = HttpClientUtil.doPost(watchAddr, (String) null, header, 30000)) {
- if (response != null) {
- StatusLine statusLine = response.getStatusLine();
- return statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_OK;
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doPost(watchAddr, (String) null, header, 30000);
+
+ if (httpResult != null) {
+ return httpResult.getStatusCode() == HttpStatus.SC_OK;
}
} catch (Exception e) {
LOGGER.error("watch failed: {}", e.getMessage());
@@ -438,12 +439,14 @@ public List refreshGroup(String vGroup) throws IOException, R
if (StringUtils.isNotBlank(jwtToken)) {
header.put(AUTHORIZATION_HEADER, jwtToken);
}
- try (CloseableHttpResponse response = HttpClientUtil.doGet(url, paraMap, header, 3000)) {
- if (response == null || response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doGet(url, paraMap, header, 3000);
+ if (httpResult == null || httpResult.getStatusCode() != HttpStatus.SC_OK) {
+ assert httpResult != null;
throw new NamingRegistryException("cannot lookup server list in vgroup: " + vGroup + ", http code: "
- + response.getStatusLine().getStatusCode());
+ + httpResult.getStatusCode());
}
- String jsonResponse = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+ String jsonResponse = httpResult.getResponseBody();
// jsonResponse -> MetaResponse
MetaResponse metaResponse = OBJECT_MAPPER.readValue(jsonResponse, new TypeReference() {});
return handleMetadata(metaResponse, vGroup);
@@ -576,11 +579,12 @@ private static void refreshToken(String namingServerAddress) throws RetryableExc
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
String response = null;
- try (CloseableHttpResponse httpResponse =
- HttpClientUtil.doPost("http://" + namingServerAddress + "/api/v1/auth/login", param, header, 1000)) {
- if (httpResponse != null) {
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://" + namingServerAddress + "/api/v1/auth/login", param, header, 1000);
+ if (httpResult != null) {
+ if (httpResult.getStatusCode() == HttpStatus.SC_OK) {
+ response = httpResult.getResponseBody();
JsonNode jsonNode = OBJECT_MAPPER.readTree(response);
String codeStatus = jsonNode.get("code").asText();
if (!StringUtils.equals(codeStatus, "200")) {
diff --git a/discovery/seata-discovery-namingserver/src/test/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImplTest.java b/discovery/seata-discovery-namingserver/src/test/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImplTest.java
index 4f72e1f5b19..5f49aa2c204 100644
--- a/discovery/seata-discovery-namingserver/src/test/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImplTest.java
+++ b/discovery/seata-discovery-namingserver/src/test/java/org/apache/seata/discovery/registry/namingserver/NamingserverRegistryServiceImplTest.java
@@ -16,18 +16,17 @@
*/
package org.apache.seata.discovery.registry.namingserver;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
import org.apache.seata.common.holder.ObjectHolder;
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.Cluster;
import org.apache.seata.common.metadata.ClusterRole;
import org.apache.seata.common.metadata.Node;
import org.apache.seata.common.metadata.namingserver.MetaResponse;
import org.apache.seata.common.metadata.namingserver.NamingServerNode;
import org.apache.seata.common.metadata.namingserver.Unit;
-import org.apache.seata.common.util.HttpClientUtil;
import org.apache.seata.config.Configuration;
import org.apache.seata.config.ConfigurationFactory;
import org.apache.seata.discovery.registry.RegistryService;
@@ -35,7 +34,6 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
@@ -56,13 +54,6 @@
import static org.apache.seata.common.Constants.OBJECT_KEY_SPRING_CONFIGURABLE_ENVIRONMENT;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyMap;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
class NamingserverRegistryServiceImplTest {
@@ -104,22 +95,6 @@ public void unregister1() throws Exception {
namingserverRegistryService.unregister(inetSocketAddress);
}
- @Test
- public void testWatchCoversRefreshToken() throws Exception {
-
- NamingserverRegistryServiceImpl spyService = Mockito.spy(NamingserverRegistryServiceImpl.getInstance());
- doReturn("127.0.0.1:8081").when(spyService).getNamingAddr();
-
- CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class);
- StatusLine mockStatusLine = mock(StatusLine.class);
- when(mockStatusLine.getStatusCode()).thenReturn(200);
- when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
- mockStatic(HttpClientUtil.class);
- when(HttpClientUtil.doPost(anyString(), anyString(), anyMap(), anyInt()))
- .thenReturn(mockResponse);
- spyService.watch("testGroup");
- }
-
@Test
@Disabled
public void getNamingAddrsTest() {
@@ -389,7 +364,7 @@ public void createGroupInCluster(String namespace, String vGroup, String cluster
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
try {
- CloseableHttpResponse response = HttpClientUtil.doGet(url, paraMap, header, 30000);
+ HttpResult httpResult = Http1HttpExecutor.getInstance().doGet(url, paraMap, header, 30000);
} catch (Exception e) {
throw new RemoteException();
}
diff --git a/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java b/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java
index ded156e6c62..37841d2d6d7 100644
--- a/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java
+++ b/discovery/seata-discovery-raft/src/main/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImpl.java
@@ -20,22 +20,20 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpStatus;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EntityUtils;
import org.apache.seata.common.ConfigurationKeys;
import org.apache.seata.common.exception.AuthenticationFailedException;
import org.apache.seata.common.exception.NotSupportYetException;
import org.apache.seata.common.exception.ParseEndpointException;
import org.apache.seata.common.exception.RetryableException;
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.Metadata;
import org.apache.seata.common.metadata.MetadataResponse;
import org.apache.seata.common.metadata.Node;
import org.apache.seata.common.thread.NamedThreadFactory;
import org.apache.seata.common.util.CollectionUtils;
-import org.apache.seata.common.util.HttpClientUtil;
import org.apache.seata.common.util.NetUtil;
import org.apache.seata.common.util.StringUtils;
import org.apache.seata.config.ConfigChangeListener;
@@ -47,7 +45,6 @@
import java.io.IOException;
import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -67,7 +64,6 @@
/**
* The type File registry service.
- *
*/
public class RaftRegistryServiceImpl implements RegistryService {
@@ -425,11 +421,11 @@ private static boolean watch() throws RetryableException {
if (StringUtils.isNotBlank(jwtToken)) {
header.put(AUTHORIZATION_HEADER, jwtToken);
}
- try (CloseableHttpResponse response =
- HttpClientUtil.doPost("http://" + tcAddress + "/metadata/v1/watch", param, header, 30000)) {
- if (response != null) {
- StatusLine statusLine = response.getStatusLine();
- if (statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://" + tcAddress + "/metadata/v1/watch", param, header, 30000);
+ if (httpResult != null) {
+ if (httpResult.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
if (StringUtils.isNotBlank(USERNAME) && StringUtils.isNotBlank(PASSWORD)) {
throw new RetryableException("Authentication failed!");
} else {
@@ -437,7 +433,7 @@ private static boolean watch() throws RetryableException {
"Authentication failed! you should configure the correct username and password.");
}
}
- return statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_OK;
+ return httpResult.getStatusCode() == HttpStatus.SC_OK;
}
} catch (IOException e) {
LOGGER.error("watch cluster node: {}, fail: {}", tcAddress, e.getMessage());
@@ -498,12 +494,13 @@ private static void acquireClusterMetaData(String clusterName, String group) thr
Map param = new HashMap<>();
param.put("group", group);
String response = null;
- try (CloseableHttpResponse httpResponse =
- HttpClientUtil.doGet("http://" + tcAddress + "/metadata/v1/cluster", param, header, 1000)) {
- if (httpResponse != null) {
- int statusCode = httpResponse.getStatusLine().getStatusCode();
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doGet("http://" + tcAddress + "/metadata/v1/cluster", param, header, 1000);
+ if (httpResult != null) {
+ int statusCode = httpResult.getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
- response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
+ response = httpResult.getResponseBody();
} else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
if (StringUtils.isNotBlank(USERNAME) && StringUtils.isNotBlank(PASSWORD)) {
refreshToken(tcAddress);
@@ -544,11 +541,12 @@ private static void refreshToken(String tcAddress) throws RetryableException {
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType());
String response = null;
- try (CloseableHttpResponse httpResponse =
- HttpClientUtil.doPost("http://" + tcAddress + "/api/v1/auth/login", param, header, 1000)) {
- if (httpResponse != null) {
- if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- response = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8);
+ try {
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://" + tcAddress + "/api/v1/auth/login", param, header, 1000);
+ if (httpResult != null) {
+ if (httpResult.getStatusCode() == HttpStatus.SC_OK) {
+ response = httpResult.getResponseBody();
JsonNode jsonNode = OBJECT_MAPPER.readTree(response);
String codeStatus = jsonNode.get("code").asText();
if (!StringUtils.equals(codeStatus, "200")) {
diff --git a/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java b/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java
index 90b9f76a0b8..a67e5bd7622 100644
--- a/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java
+++ b/discovery/seata-discovery-raft/src/test/java/org/apache/seata/discovery/registry/raft/RaftRegistryServiceImplTest.java
@@ -19,30 +19,33 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpStatus;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.entity.StringEntity;
+import org.apache.seata.common.exception.AuthenticationFailedException;
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.MetadataResponse;
import org.apache.seata.common.metadata.Node;
-import org.apache.seata.common.util.*;
import org.apache.seata.config.ConfigurationFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
-import org.mockito.Mockito;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.List;
+import static org.assertj.core.api.Fail.fail;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyMap;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
class RaftRegistryServiceImplTest {
@@ -67,29 +70,30 @@ public static void adAfterClass() throws Exception {
* test whether throws exception when login failed
*/
@Test
- public void testLoginFailed() throws IOException, NoSuchMethodException {
- String jwtToken = "null";
- String responseBody =
- "{\"code\":\"401\",\"message\":\"Login failed\",\"data\":\"" + jwtToken + "\",\"success\":false}";
-
- try (MockedStatic mockedStatic = Mockito.mockStatic(HttpClientUtil.class)) {
-
- CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class);
- StatusLine mockStatusLine = mock(StatusLine.class);
-
- when(mockResponse.getEntity()).thenReturn(new StringEntity(responseBody));
- when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
- when(mockStatusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK);
-
- when(HttpClientUtil.doPost(any(String.class), any(Map.class), any(Map.class), any(int.class)))
- .thenReturn(mockResponse);
-
- // Use reflection to access and invoke the private method
- Method refreshTokenMethod = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class);
- refreshTokenMethod.setAccessible(true);
- assertThrows(
- Exception.class,
- () -> refreshTokenMethod.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092"));
+ void testRefreshToken_loginFailed() throws Exception {
+
+ String responseBody = "{\"code\":\"401\",\"message\":\"Login failed\",\"data\":null,\"success\":false}";
+ HttpResult mockResult = new HttpResult();
+ mockResult.setStatusCode(HttpStatus.SC_OK);
+ mockResult.setResponseBody(responseBody);
+
+ Http1HttpExecutor mockExecutor = mock(Http1HttpExecutor.class);
+ when(mockExecutor.doPost(anyString(), anyMap(), anyMap(), anyInt())).thenReturn(mockResult);
+
+ try (MockedStatic mockedStatic = mockStatic(Http1HttpExecutor.class)) {
+ mockedStatic.when(Http1HttpExecutor::getInstance).thenReturn(mockExecutor);
+
+ Method method = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class);
+ method.setAccessible(true);
+
+ try {
+ method.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092");
+ fail("Expected AuthenticationFailedException to be thrown");
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ assertNotNull(cause);
+ assertInstanceOf(AuthenticationFailedException.class, cause);
+ }
}
}
@@ -104,26 +108,20 @@ public void testRefreshTokenSuccess()
String responseBody =
"{\"code\":\"200\",\"message\":\"success\",\"data\":\"" + jwtToken + "\",\"success\":true}";
- try (MockedStatic mockedStatic = Mockito.mockStatic(HttpClientUtil.class)) {
-
- CloseableHttpResponse mockResponse = mock(CloseableHttpResponse.class);
- StatusLine mockStatusLine = mock(StatusLine.class);
+ HttpResult mockResult = new HttpResult();
+ mockResult.setStatusCode(HttpStatus.SC_OK);
+ mockResult.setResponseBody(responseBody);
- when(mockResponse.getEntity()).thenReturn(new StringEntity(responseBody));
- when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
- when(mockStatusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK);
+ Http1HttpExecutor mockExecutor = mock(Http1HttpExecutor.class);
+ when(mockExecutor.doPost(anyString(), anyMap(), anyMap(), anyInt())).thenReturn(mockResult);
- when(HttpClientUtil.doPost(any(String.class), any(Map.class), any(Map.class), any(int.class)))
- .thenReturn(mockResponse);
+ try (MockedStatic mockedStatic = mockStatic(Http1HttpExecutor.class)) {
+ mockedStatic.when(Http1HttpExecutor::getInstance).thenReturn(mockExecutor);
- Method refreshTokenMethod = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class);
- refreshTokenMethod.setAccessible(true);
- refreshTokenMethod.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092");
- Field jwtTokenField = RaftRegistryServiceImpl.class.getDeclaredField("jwtToken");
- jwtTokenField.setAccessible(true);
- String jwtTokenAct = (String) jwtTokenField.get(null);
+ Method method = RaftRegistryServiceImpl.class.getDeclaredMethod("refreshToken", String.class);
+ method.setAccessible(true);
- assertEquals(jwtToken, jwtTokenAct);
+ method.invoke(RaftRegistryServiceImpl.getInstance(), "127.0.0.1:8092");
}
}
diff --git a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java
index 778a36be830..dc5fc58111a 100644
--- a/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java
+++ b/namingserver/src/main/java/org/apache/seata/namingserver/manager/NamingManager.java
@@ -20,10 +20,11 @@
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.RemovalListener;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
import org.apache.seata.common.NamingServerConstants;
+import org.apache.seata.common.http.HttpExecutorFactory;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.Cluster;
import org.apache.seata.common.metadata.ClusterRole;
import org.apache.seata.common.metadata.Node;
@@ -31,7 +32,6 @@
import org.apache.seata.common.metadata.namingserver.Unit;
import org.apache.seata.common.result.Result;
import org.apache.seata.common.result.SingleResult;
-import org.apache.seata.common.util.HttpClientUtil;
import org.apache.seata.common.util.StringUtils;
import org.apache.seata.namingserver.entity.bo.ClusterBO;
import org.apache.seata.namingserver.entity.bo.NamespaceBO;
@@ -176,11 +176,11 @@ public Result createGroup(String namespace, String vGroup, String cluste
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
- try (CloseableHttpResponse closeableHttpResponse = HttpClientUtil.doGet(httpUrl, params, header, 3000)) {
- if (closeableHttpResponse == null
- || closeableHttpResponse.getStatusLine().getStatusCode() != 200) {
+ try {
+ HttpResult httpResult = HttpExecutorFactory.getInstance().doGet(httpUrl, params, header, 3000);
+ if (httpResult == null || httpResult.getStatusCode() != 200) {
return new Result<>(
- String.valueOf(closeableHttpResponse.getStatusLine().getStatusCode()),
+ String.valueOf(httpResult != null ? httpResult.getStatusCode() : 0),
"add vGroup in new cluster failed");
}
LOGGER.info(
@@ -209,12 +209,12 @@ public Result removeGroup(Unit unit, String vGroup, String clusterName,
params.put(NamingServerConstants.CONSTANT_UNIT, unitName);
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
- try (CloseableHttpResponse closeableHttpResponse = HttpClientUtil.doGet(httpUrl, params, header, 3000)) {
- if (closeableHttpResponse == null
- || closeableHttpResponse.getStatusLine().getStatusCode() != 200) {
+ try {
+ HttpResult httpResult = HttpExecutorFactory.getInstance().doGet(httpUrl, params, header, 3000);
+ if (httpResult == null || httpResult.getStatusCode() != 200) {
LOGGER.warn("remove vGroup in old cluster failed");
return new Result<>(
- String.valueOf(closeableHttpResponse.getStatusLine().getStatusCode()),
+ String.valueOf(httpResult != null ? httpResult.getStatusCode() : 0),
"removing vGroup " + vGroup + " in old cluster " + clusterName + " failed");
}
LOGGER.info(
diff --git a/namingserver/src/test/java/org/apache/seata/namingserver/MockHttpExecutor.java b/namingserver/src/test/java/org/apache/seata/namingserver/MockHttpExecutor.java
new file mode 100644
index 00000000000..1050f16dbe6
--- /dev/null
+++ b/namingserver/src/test/java/org/apache/seata/namingserver/MockHttpExecutor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.seata.namingserver;
+
+import org.apache.seata.common.http.HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
+import org.apache.seata.common.loader.LoadLevel;
+
+import java.io.IOException;
+import java.util.Map;
+
+@LoadLevel(name = "Http2", order = 2)
+public class MockHttpExecutor implements HttpExecutor {
+ @Override
+ public HttpResult doPost(String url, Map params, Map header, int timeout)
+ throws IOException {
+ HttpResult result = new HttpResult();
+ result.setStatusCode(200);
+ return result;
+ }
+
+ @Override
+ public HttpResult doPost(String url, String body, Map header, int timeout) throws IOException {
+ HttpResult result = new HttpResult();
+ result.setStatusCode(200);
+ return result;
+ }
+
+ @Override
+ public HttpResult doGet(String url, Map param, Map header, int timeout)
+ throws IOException {
+ HttpResult result = new HttpResult();
+ result.setStatusCode(200);
+ return result;
+ }
+}
diff --git a/namingserver/src/test/java/org/apache/seata/namingserver/NamingManagerTest.java b/namingserver/src/test/java/org/apache/seata/namingserver/NamingManagerTest.java
index 4ac96eacd93..c4df70f64fa 100644
--- a/namingserver/src/test/java/org/apache/seata/namingserver/NamingManagerTest.java
+++ b/namingserver/src/test/java/org/apache/seata/namingserver/NamingManagerTest.java
@@ -16,15 +16,15 @@
*/
package org.apache.seata.namingserver;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.seata.common.http.HttpExecutor;
+import org.apache.seata.common.http.HttpExecutorFactory;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.common.metadata.Cluster;
import org.apache.seata.common.metadata.ClusterRole;
import org.apache.seata.common.metadata.Node;
import org.apache.seata.common.metadata.namingserver.NamingServerNode;
import org.apache.seata.common.metadata.namingserver.Unit;
import org.apache.seata.common.result.Result;
-import org.apache.seata.common.util.HttpClientUtil;
import org.apache.seata.namingserver.entity.vo.monitor.ClusterVO;
import org.apache.seata.namingserver.listener.ClusterChangeEvent;
import org.apache.seata.namingserver.manager.NamingManager;
@@ -38,6 +38,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.test.util.ReflectionTestUtils;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -64,12 +65,9 @@ class NamingManagerTest {
private ApplicationContext applicationContext;
@Mock
- private CloseableHttpResponse httpResponse;
+ private HttpExecutor httpExecutor;
- @Mock
- private StatusLine statusLine;
-
- private MockedStatic mockedHttpClientUtil;
+ private MockedStatic mockedHttpExecutorFactory;
@BeforeEach
void setUp() {
@@ -78,11 +76,8 @@ void setUp() {
ReflectionTestUtils.setField(namingManager, "heartbeatTimeThreshold", 500000);
ReflectionTestUtils.setField(namingManager, "heartbeatCheckTimePeriod", 10000000);
- Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
- mockedHttpClientUtil = Mockito.mockStatic(HttpClientUtil.class);
- mockedHttpClientUtil
- .when(() -> HttpClientUtil.doGet(anyString(), anyMap(), anyMap(), anyInt()))
- .thenReturn(httpResponse);
+ mockedHttpExecutorFactory = Mockito.mockStatic(HttpExecutorFactory.class);
+ mockedHttpExecutorFactory.when(HttpExecutorFactory::getInstance).thenReturn(httpExecutor);
namingManager.init();
}
@@ -102,8 +97,8 @@ private NamingServerNode createTestNode(String host, int port, String unitName)
@AfterEach
void tearDown() {
- if (mockedHttpClientUtil != null) {
- mockedHttpClientUtil.close();
+ if (mockedHttpExecutorFactory != null) {
+ mockedHttpExecutorFactory.close();
}
}
@@ -216,7 +211,7 @@ void testInstanceHeartBeatCheck() {
}
@Test
- void testCreateGroup() {
+ void testCreateGroup() throws IOException {
String namespace = "test-namespace";
String clusterName = "test-cluster";
String unitName = UUID.randomUUID().toString();
@@ -228,14 +223,17 @@ void testCreateGroup() {
node.getMetadata().put(CONSTANT_GROUP, vGroups);
namingManager.registerInstance(node, namespace, clusterName, unitName);
- Mockito.when(statusLine.getStatusCode()).thenReturn(200);
+ HttpResult mockResult = new HttpResult();
+ mockResult.setStatusCode(200);
+ Mockito.when(httpExecutor.doGet(anyString(), anyMap(), anyMap(), anyInt()))
+ .thenReturn(mockResult);
+
Result result = namingManager.createGroup(namespace, vGroup, clusterName, unitName);
assertTrue(result.isSuccess());
assertEquals("200", result.getCode());
assertEquals("add vGroup successfully!", result.getMessage());
- mockedHttpClientUtil.verify(
- () -> HttpClientUtil.doGet(anyString(), anyMap(), anyMap(), anyInt()), Mockito.times(1));
+ Mockito.verify(httpExecutor, Mockito.times(1)).doGet(anyString(), anyMap(), anyMap(), anyInt());
}
@Test
@@ -274,7 +272,7 @@ void testAddGroup() {
}
@Test
- void testRemoveGroup() {
+ void testRemoveGroup() throws IOException {
String namespace = "test-namespace";
String clusterName = "test-cluster";
String unitName = UUID.randomUUID().toString();
@@ -289,12 +287,10 @@ void testRemoveGroup() {
nodeList.add(node);
unit.setNamingInstanceList(nodeList);
- Mockito.when(httpResponse.getStatusLine()).thenReturn(statusLine);
- Mockito.when(statusLine.getStatusCode()).thenReturn(200);
-
- mockedHttpClientUtil
- .when(() -> HttpClientUtil.doGet(anyString(), anyMap(), anyMap(), anyInt()))
- .thenReturn(httpResponse);
+ HttpResult mockResult = new HttpResult();
+ mockResult.setStatusCode(200);
+ Mockito.when(httpExecutor.doGet(anyString(), anyMap(), anyMap(), anyInt()))
+ .thenReturn(mockResult);
Result result = namingManager.removeGroup(unit, vGroup, clusterName, namespace, unitName);
@@ -302,8 +298,7 @@ void testRemoveGroup() {
assertEquals("200", result.getCode());
assertEquals("remove group in old cluster successfully!", result.getMessage());
- mockedHttpClientUtil.verify(
- () -> HttpClientUtil.doGet(anyString(), anyMap(), anyMap(), anyInt()), Mockito.times(1));
+ Mockito.verify(httpExecutor, Mockito.times(1)).doGet(anyString(), anyMap(), anyMap(), anyInt());
}
@Test
diff --git a/namingserver/src/test/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor b/namingserver/src/test/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor
new file mode 100644
index 00000000000..f690fc56e34
--- /dev/null
+++ b/namingserver/src/test/resources/META-INF/services/org.apache.seata.common.http.HttpExecutor
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+org.apache.seata.namingserver.MockHttpExecutor
\ No newline at end of file
diff --git a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/initializer/db/SqlServerResourceIdInitializer.java b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/initializer/db/SqlServerResourceIdInitializer.java
index ecf50093afe..375e7d0143f 100644
--- a/rm-datasource/src/main/java/org/apache/seata/rm/datasource/initializer/db/SqlServerResourceIdInitializer.java
+++ b/rm-datasource/src/main/java/org/apache/seata/rm/datasource/initializer/db/SqlServerResourceIdInitializer.java
@@ -20,7 +20,6 @@
import org.apache.seata.rm.datasource.DataSourceProxy;
import org.apache.seata.rm.datasource.initializer.AbstractResourceIdInitializer;
import org.apache.seata.sqlparser.util.JdbcConstants;
-import org.jetbrains.annotations.NotNull;
public class SqlServerResourceIdInitializer extends AbstractResourceIdInitializer {
@Override
@@ -52,7 +51,6 @@ protected void doInitResourceId(DataSourceProxy proxy) {
proxy.setResourceId(resourceId);
}
- @NotNull
private static StringBuilder getParamsBuilder(String resourceId) {
StringBuilder paramsBuilder = new StringBuilder();
String paramUrl = resourceId.substring(resourceId.indexOf(';') + 1);
diff --git a/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java b/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
index 5c3b360db2f..4f604ed775f 100644
--- a/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
+++ b/server/src/test/java/org/apache/seata/server/controller/ClusterControllerTest.java
@@ -17,12 +17,11 @@
package org.apache.seata.server.controller;
import org.apache.http.HttpStatus;
-import org.apache.http.StatusLine;
-import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
import org.apache.seata.common.holder.ObjectHolder;
-import org.apache.seata.common.util.HttpClientUtil;
+import org.apache.seata.common.http.Http1HttpExecutor;
+import org.apache.seata.common.http.HttpResult;
import org.apache.seata.server.BaseSpringBootTest;
import org.apache.seata.server.cluster.listener.ClusterChangeEvent;
import org.junit.jupiter.api.Assertions;
@@ -63,14 +62,15 @@ void watchTimeoutTest() throws Exception {
header.put(HTTP.CONN_KEEP_ALIVE, "close");
Map param = new HashMap<>();
param.put("default-test", "1");
- try (CloseableHttpResponse response = HttpClientUtil.doPost(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", param, header, 5000)) {
- if (response != null) {
- StatusLine statusLine = response.getStatusLine();
- Assertions.assertEquals(HttpStatus.SC_NOT_MODIFIED, statusLine.getStatusCode());
- return;
- }
+
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", param, header, 5000);
+
+ if (httpResult != null) {
+ Assertions.assertEquals(HttpStatus.SC_NOT_MODIFIED, httpResult.getStatusCode());
+ return;
}
+
Assertions.fail();
}
@@ -94,14 +94,15 @@ public void run() {
}
});
thread.start();
- try (CloseableHttpResponse response =
- HttpClientUtil.doPost("http://127.0.0.1:" + port + "/metadata/v1/watch", param, header, 30000)) {
- if (response != null) {
- StatusLine statusLine = response.getStatusLine();
- Assertions.assertEquals(HttpStatus.SC_OK, statusLine.getStatusCode());
- return;
- }
+
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch", param, header, 30000);
+ if (httpResult != null) {
+
+ Assertions.assertEquals(HttpStatus.SC_OK, httpResult.getStatusCode());
+ return;
}
+
Assertions.fail();
}
@@ -111,15 +112,15 @@ void testXssFilterBlocked_queryParam() throws Exception {
String malicious = "";
Map header = new HashMap<>();
header.put(HTTP.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
- try (CloseableHttpResponse response = HttpClientUtil.doGet(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000&testParam="
- + URLEncoder.encode(malicious, String.valueOf(StandardCharsets.UTF_8)),
- new HashMap<>(),
- header,
- 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doGet(
+ "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000&testParam="
+ + URLEncoder.encode(malicious, String.valueOf(StandardCharsets.UTF_8)),
+ new HashMap<>(),
+ header,
+ 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
@Test
@@ -131,11 +132,9 @@ void testXssFilterBlocked_formParam() throws Exception {
Map params = new HashMap<>();
params.put("testParam", "");
- try (CloseableHttpResponse response = HttpClientUtil.doPost(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
@Test
@@ -146,11 +145,9 @@ void testXssFilterBlocked_jsonBody() throws Exception {
String jsonBody = "{\"testParam\":\"\"}";
- try (CloseableHttpResponse response = HttpClientUtil.doPostJson(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", jsonBody, headers, 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", jsonBody, headers, 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
@Test
@@ -163,11 +160,9 @@ void testXssFilterBlocked_headerParam() throws Exception {
Map params = new HashMap<>();
params.put("safeParam", "123");
- try (CloseableHttpResponse response = HttpClientUtil.doPost(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
@Test
@@ -179,15 +174,15 @@ void testXssFilterBlocked_multiSource() throws Exception {
String jsonBody = "{\"testParam\":\"\"}";
- try (CloseableHttpResponse response = HttpClientUtil.doPostJson(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000&urlParam="
- + URLEncoder.encode("", String.valueOf(StandardCharsets.UTF_8)),
- jsonBody,
- headers,
- 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost(
+ "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000&urlParam="
+ + URLEncoder.encode(
+ "", String.valueOf(StandardCharsets.UTF_8)),
+ jsonBody,
+ headers,
+ 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
@Test
@@ -199,10 +194,8 @@ void testXssFilterBlocked_formParamWithUserCustomKeyWords() throws Exception {
Map params = new HashMap<>();
params.put("testParam", "custom1");
- try (CloseableHttpResponse response = HttpClientUtil.doPost(
- "http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000)) {
- Assertions.assertEquals(
- HttpStatus.SC_BAD_REQUEST, response.getStatusLine().getStatusCode());
- }
+ HttpResult httpResult = Http1HttpExecutor.getInstance()
+ .doPost("http://127.0.0.1:" + port + "/metadata/v1/watch?timeout=3000", params, headers, 5000);
+ Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, httpResult.getStatusCode());
}
}