You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by yu...@apache.org on 2022/10/12 12:15:25 UTC
[shenyu] branch master updated: [type:feat] ZookeeperInstanceRegisterRepository and HttpClientShenyuHttpClient. (#3930) (#3965)
This is an automated email from the ASF dual-hosted git repository.
yunlong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 6a4f4e7bc [type:feat] ZookeeperInstanceRegisterRepository and HttpClientShenyuHttpClient. (#3930) (#3965)
6a4f4e7bc is described below
commit 6a4f4e7bc2b9b113217606bb76c93248649a949f
Author: 杨文杰 <31...@users.noreply.github.com>
AuthorDate: Wed Oct 12 20:15:14 2022 +0800
[type:feat] ZookeeperInstanceRegisterRepository and HttpClientShenyuHttpClient. (#3930) (#3965)
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
* [type:feat] shenyu-sdk-httpclient and shenyu-register-instance-zookeeper#selectInstancesAndWatcher. #3930
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
* Implementation ShenyuInstanceRegisterRepository#selectInstancesAndWatcher in ZookeeperInstanceRegisterRepository and Implementation HttpClientShenyuHttpClient
---
.../instance/zookeeper/ZookeeperClient.java | 15 +++
.../ZookeeperInstanceRegisterRepository.java | 35 ++++++-
.../ZookeeperInstanceRegisterRepositoryTest.java | 45 +++++++-
shenyu-sdk/pom.xml | 1 +
shenyu-sdk/{ => shenyu-sdk-httpclient}/pom.xml | 35 +++++--
.../sdk/httpclient/HttpClientShenyuHttpClient.java | 113 +++++++++++++++++++++
.../httpclient/HttpClientShenyuHttpClientTest.java | 45 ++++++++
7 files changed, 278 insertions(+), 11 deletions(-)
diff --git a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperClient.java b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperClient.java
index 15ce67e88..3812073cf 100644
--- a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperClient.java
+++ b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperClient.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.register.instance.zookeeper;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
@@ -236,6 +237,20 @@ public class ZookeeperClient {
return cache;
}
+ /**
+ * add children watcher.
+ * @param key selectKey
+ * @param curatorWatcher watcher
+ * @return children List
+ */
+ public List<String> subscribeChildrenChanges(final String key, final CuratorWatcher curatorWatcher) {
+ try {
+ return client.getChildren().usingWatcher(curatorWatcher).forPath(key);
+ } catch (Exception e) {
+ throw new ShenyuException(e);
+ }
+ }
+
/**
* find cache with key.
* @param key key.
diff --git a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepository.java b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepository.java
index ee78fe896..9f869665e 100644
--- a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepository.java
+++ b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/main/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepository.java
@@ -18,21 +18,29 @@
package org.apache.shenyu.register.instance.zookeeper;
import org.apache.commons.lang3.StringUtils;
+import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.shenyu.common.config.ShenyuConfig.InstanceConfig;
import org.apache.shenyu.common.constant.Constants;
import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.InstanceRegisterDTO;
import org.apache.shenyu.register.common.path.RegisterPathConstants;
+import org.apache.shenyu.register.common.subsriber.WatcherListener;
import org.apache.shenyu.register.instance.api.ShenyuInstanceRegisterRepository;
import org.apache.shenyu.spi.Join;
import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.WatchedEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.Objects;
+import java.util.Collections;
/**
* The type Zookeeper instance register repository.
@@ -82,7 +90,7 @@ public class ZookeeperInstanceRegisterRepository implements ShenyuInstanceRegist
client.start();
}
-
+
@Override
public void persistInstance(final InstanceRegisterDTO instance) {
String uriNodeName = buildInstanceNodeName(instance);
@@ -95,7 +103,30 @@ public class ZookeeperInstanceRegisterRepository implements ShenyuInstanceRegist
nodeDataMap.put(realNode, nodeData);
client.createOrUpdate(realNode, nodeData, CreateMode.EPHEMERAL);
}
-
+
+ @Override
+ public List<InstanceRegisterDTO> selectInstancesAndWatcher(final String selectKey, final WatcherListener watcherListener) {
+ final Function<List<String>, List<InstanceRegisterDTO>> getInstanceRegisterFun = childrenList -> childrenList.stream().map(childPath -> {
+ String instanceRegisterJsonStr = client.get(RegisterPathConstants.buildRealNode(selectKey, childPath));
+ return GsonUtils.getInstance().fromJson(instanceRegisterJsonStr, InstanceRegisterDTO.class);
+ }).collect(Collectors.toList());
+
+ List<String> childrenPathList = client.subscribeChildrenChanges(selectKey, new CuratorWatcher() {
+ @Override
+ public void process(final WatchedEvent event) throws Exception {
+ if (watcherListener != null) {
+ String path = Objects.isNull(event.getPath()) ? "" : event.getPath();
+ List<String> childrenList = StringUtils.isNotBlank(path) ? client.subscribeChildrenChanges(path, this)
+ : Collections.emptyList();
+ if (!childrenList.isEmpty()) {
+ watcherListener.listener(getInstanceRegisterFun.apply(childrenList));
+ }
+ }
+ }
+ });
+ return getInstanceRegisterFun.apply(childrenPathList);
+ }
+
@Override
public void close() {
client.close();
diff --git a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/test/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepositoryTest.java b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/test/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepositoryTest.java
index c1ff22c61..220218922 100644
--- a/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/test/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepositoryTest.java
+++ b/shenyu-register-center/shenyu-register-instance/shenyu-register-instance-zookeeper/src/test/java/org/apache/shenyu/register/instance/zookeeper/ZookeeperInstanceRegisterRepositoryTest.java
@@ -18,23 +18,30 @@
package org.apache.shenyu.register.instance.zookeeper;
import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.listen.Listenable;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.shenyu.common.config.ShenyuConfig;
+import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.common.dto.InstanceRegisterDTO;
+import org.apache.shenyu.register.common.path.RegisterPathConstants;
+import org.apache.shenyu.register.common.subsriber.WatcherListener;
+import org.apache.zookeeper.WatchedEvent;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Properties;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockConstruction;
-import static org.mockito.Mockito.when;
public class ZookeeperInstanceRegisterRepositoryTest {
@@ -64,4 +71,40 @@ public class ZookeeperInstanceRegisterRepositoryTest {
repository.close();
}
}
+
+ @Test
+ public void testSelectInstancesAndWatcher() throws Exception {
+ InstanceRegisterDTO data = InstanceRegisterDTO.builder()
+ .appName("shenyu-test")
+ .host("shenyu-host")
+ .port(9195)
+ .build();
+ final Listenable listenable = mock(Listenable.class);
+ final CuratorWatcher[] watcherArr = new CuratorWatcher[1];
+
+ try (MockedConstruction<ZookeeperClient> construction = mockConstruction(ZookeeperClient.class, (mock, context) -> {
+ final CuratorFramework curatorFramework = mock(CuratorFramework.class);
+ when(mock.getClient()).thenReturn(curatorFramework);
+ when(mock.subscribeChildrenChanges(anyString(), any(CuratorWatcher.class))).thenAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ watcherArr[0] = (CuratorWatcher) args[1];
+ return Collections.singletonList("shenyu-test");
+ });
+ when(mock.get(anyString())).thenReturn(GsonUtils.getInstance().toJson(data));
+ when(curatorFramework.getConnectionStateListenable()).thenReturn(listenable);
+ })) {
+ final ZookeeperInstanceRegisterRepository repository = new ZookeeperInstanceRegisterRepository();
+ ShenyuConfig.InstanceConfig config = new ShenyuConfig.InstanceConfig();
+ repository.init(config);
+ final Properties configProps = config.getProps();
+ configProps.setProperty("digest", "digest");
+ repository.init(config);
+ repository.selectInstancesAndWatcher(RegisterPathConstants.buildInstanceParentPath(), mock(WatcherListener.class));
+ WatchedEvent mockEvent = mock(WatchedEvent.class);
+ when(mockEvent.getPath()).thenReturn(RegisterPathConstants.buildInstanceParentPath());
+ watcherArr[0].process(mockEvent);
+ repository.close();
+ }
+ }
+
}
diff --git a/shenyu-sdk/pom.xml b/shenyu-sdk/pom.xml
index 10666c39d..8c86e4398 100644
--- a/shenyu-sdk/pom.xml
+++ b/shenyu-sdk/pom.xml
@@ -30,5 +30,6 @@
<modules>
<module>shenyu-sdk-core</module>
<module>shenyu-sdk-spring</module>
+ <module>shenyu-sdk-httpclient</module>
</modules>
</project>
\ No newline at end of file
diff --git a/shenyu-sdk/pom.xml b/shenyu-sdk/shenyu-sdk-httpclient/pom.xml
similarity index 58%
copy from shenyu-sdk/pom.xml
copy to shenyu-sdk/shenyu-sdk-httpclient/pom.xml
index 10666c39d..9a6c39245 100644
--- a/shenyu-sdk/pom.xml
+++ b/shenyu-sdk/shenyu-sdk-httpclient/pom.xml
@@ -19,16 +19,35 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
+ <artifactId>shenyu-sdk</artifactId>
<groupId>org.apache.shenyu</groupId>
- <artifactId>shenyu</artifactId>
<version>2.5.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
- <artifactId>shenyu-sdk</artifactId>
- <packaging>pom</packaging>
-
- <modules>
- <module>shenyu-sdk-core</module>
- <module>shenyu-sdk-spring</module>
- </modules>
+
+
+ <artifactId>shenyu-sdk-httpclient</artifactId>
+
+ <properties>
+ <maven.compiler.source>8</maven.compiler.source>
+ <maven.compiler.target>8</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <artifactId>shenyu-sdk-core</artifactId>
+ <groupId>org.apache.shenyu</groupId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpcore</artifactId>
+ </dependency>
+ </dependencies>
+
</project>
\ No newline at end of file
diff --git a/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClient.java b/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClient.java
new file mode 100644
index 000000000..6dc20becd
--- /dev/null
+++ b/shenyu-sdk/shenyu-sdk-httpclient/src/main/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClient.java
@@ -0,0 +1,113 @@
+/*
+ * 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.shenyu.sdk.httpclient;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.apache.shenyu.sdk.core.ShenyuRequest;
+import org.apache.shenyu.sdk.core.ShenyuResponse;
+import org.apache.shenyu.sdk.core.http.ShenyuHttpClient;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.LinkedList;
+import java.util.stream.Collectors;
+
+/**
+ * shenyu httpclient.
+ */
+public class HttpClientShenyuHttpClient implements ShenyuHttpClient {
+
+ private final HttpClientConnectionManager connectionManager;
+
+ public HttpClientShenyuHttpClient(final HttpClientConnectionManager connectionManager) {
+ this.connectionManager = connectionManager;
+ }
+
+ private HttpClient getHttpClient() {
+ return HttpClients.custom().setConnectionManager(connectionManager).build();
+ }
+
+ @Override
+ public ShenyuResponse execute(final ShenyuRequest request) throws IOException {
+ String url = request.getUrl();
+ String body = request.getBody();
+ RequestBuilder requestBuilder;
+
+ switch (request.getHttpMethod()) {
+ case GET:
+ requestBuilder = RequestBuilder.get(url);
+ break;
+ case HEAD:
+ requestBuilder = RequestBuilder.head(url);
+ break;
+ case POST:
+ requestBuilder = RequestBuilder.post(url);
+ break;
+ case PUT:
+ requestBuilder = RequestBuilder.put(url);
+ break;
+ case DELETE:
+ requestBuilder = RequestBuilder.delete(url);
+ break;
+ case OPTIONS:
+ requestBuilder = RequestBuilder.options(url);
+ break;
+ case TRACE:
+ requestBuilder = RequestBuilder.trace(url);
+ break;
+ default:
+ requestBuilder = RequestBuilder.patch(url);
+ break;
+ }
+ if (StringUtils.isNotBlank(body)) {
+ requestBuilder.setEntity(createStringEntity(body));
+ }
+
+ Map<String, Collection<String>> headers = request.getHeaders();
+ for (String name : headers.keySet()) {
+ for (String value : headers.get(name)) {
+ requestBuilder.addHeader(name, value);
+ }
+ }
+
+ HttpResponse response = getHttpClient().execute(requestBuilder.build());
+ return new ShenyuResponse(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase(),
+ Arrays.stream(response.getAllHeaders()).collect(Collectors.groupingBy(Header::getName, HashMap::new,
+ Collectors.mapping(Header::getValue, Collectors.toCollection(LinkedList::new)))),
+ EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8), request);
+ }
+
+ private StringEntity createStringEntity(final String body) {
+ StringEntity stringEntity = new StringEntity(body, StandardCharsets.UTF_8);
+ stringEntity.setContentType("application/json;charset=UTF-8");
+ return stringEntity;
+ }
+
+}
diff --git a/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClientTest.java b/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClientTest.java
new file mode 100644
index 000000000..6b732e8a0
--- /dev/null
+++ b/shenyu-sdk/shenyu-sdk-httpclient/src/test/java/org/apache/shenyu/sdk/httpclient/HttpClientShenyuHttpClientTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shenyu.sdk.httpclient;
+
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.shenyu.sdk.core.ShenyuRequest;
+import org.apache.shenyu.sdk.core.ShenyuResponse;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpClientShenyuHttpClientTest {
+
+ @Test
+ public void testShenyuHttpClient() throws IOException {
+ HttpClientShenyuHttpClient shenyuHttpClient = new HttpClientShenyuHttpClient(new PoolingHttpClientConnectionManager());
+ Map<String, Collection<String>> headerMap = new HashMap<>();
+ headerMap.put("header", Arrays.asList("test1", "test2"));
+ ShenyuRequest shenyuRequest = ShenyuRequest.create(ShenyuRequest.HttpMethod.GET, "https://shenyu.apache.org",
+ headerMap, null, null);
+ ShenyuResponse response = shenyuHttpClient.execute(shenyuRequest);
+ Assertions.assertNotNull(response);
+ }
+
+}