This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new ca69cee  [SCB-1711] support kie (#1518)
ca69cee is described below

commit ca69ceeec7a6eae824ad749dba15e8a6b9389ba3
Author: GuoYL <53255576+guoyl...@users.noreply.github.com>
AuthorDate: Wed Feb 12 11:46:28 2020 +0800

    [SCB-1711] support kie (#1518)
    
    * [SCB-1711] support kie
    
    (cherry picked from commit 833af5050ca3e26e75b327b499b0f9534f55d8b6)
    (cherry picked from commit cb19774f1ee1ac900c3d0be6c21b841a1758da0a)
    
    * [SCB-1711] optimization code
---
 coverage-reports/pom.xml                           |   4 +
 dependencies/default/pom.xml                       |   5 +
 distribution/pom.xml                               |   4 +
 .../config-kie}/pom.xml                            |  33 ++--
 .../sources/KieConfigurationSourceImpl.java        | 131 +++++++++++++
 .../config/kie/client/ConnFailEvent.java           |  35 ++++
 .../config/kie/client/ConnSuccEvent.java           |  22 +++
 .../servicecomb/config/kie/client/KieClient.java   | 165 +++++++++++++++++
 .../servicecomb/config/kie/client/KieConfig.java   |  98 ++++++++++
 .../servicecomb/config/kie/client/KieUtil.java     | 148 +++++++++++++++
 .../servicecomb/config/kie/client/KieWatcher.java  |  86 +++++++++
 .../servicecomb/config/kie/model/KVBody.java       |  65 +++++++
 .../apache/servicecomb/config/kie/model/KVDoc.java | 118 ++++++++++++
 .../servicecomb/config/kie/model/KVResponse.java   |  73 ++++++++
 .../config/kie/model/LabelDocResponse.java         |  46 +++++
 .../servicecomb/config/kie/model/ValueType.java    |  37 ++++
 ...comb.config.spi.ConfigCenterConfigurationSource |  18 ++
 .../config/kie/client/TestKieClient.java           | 205 +++++++++++++++++++++
 .../config/kie/client/TestKieConfig.java           |  46 +++++
 .../config/kie/client/TestKieWatcher.java          |  54 ++++++
 .../kie/sources/TestKieConfigurationSource.java    |  96 ++++++++++
 .../src/test/resources/microservice.yaml           |  56 ++++++
 dynamic-config/pom.xml                             |   1 +
 handlers/handler-router/pom.xml                    |   1 +
 24 files changed, 1528 insertions(+), 19 deletions(-)

diff --git a/coverage-reports/pom.xml b/coverage-reports/pom.xml
index 1103359..30a9100 100644
--- a/coverage-reports/pom.xml
+++ b/coverage-reports/pom.xml
@@ -184,6 +184,10 @@
     </dependency>
     <dependency>
       <groupId>org.apache.servicecomb</groupId>
+      <artifactId>config-kie</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
       <artifactId>edge-core</artifactId>
     </dependency>
     <dependency>
diff --git a/dependencies/default/pom.xml b/dependencies/default/pom.xml
index 15539c0..56c7903 100644
--- a/dependencies/default/pom.xml
+++ b/dependencies/default/pom.xml
@@ -1077,6 +1077,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.servicecomb</groupId>
+        <artifactId>config-kie</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.servicecomb</groupId>
         <artifactId>deployment</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 4f97aee..47afed4 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -61,6 +61,10 @@
       <groupId>org.apache.servicecomb</groupId>
       <artifactId>config-cc</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>config-kie</artifactId>
+    </dependency>
 
     <!-- edge -->
     <dependency>
diff --git a/handlers/handler-router/pom.xml b/dynamic-config/config-kie/pom.xml
similarity index 69%
copy from handlers/handler-router/pom.xml
copy to dynamic-config/config-kie/pom.xml
index f5b02d1..4aa67e5 100644
--- a/handlers/handler-router/pom.xml
+++ b/dynamic-config/config-kie/pom.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
+
 <!--
   ~ Licensed to the Apache Software Foundation (ASF) under one or more
   ~ contributor license agreements.  See the NOTICE file distributed with
@@ -20,42 +21,36 @@
   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>handlers</artifactId>
+    <artifactId>dynamic-config</artifactId>
     <groupId>org.apache.servicecomb</groupId>
     <version>2.0.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <artifactId>handler-router</artifactId>
+  <artifactId>config-kie</artifactId>
+  <name>Java Chassis::Dynamic Config::Kie</name>
 
   <dependencies>
     <dependency>
-      <groupId>com.netflix.ribbon</groupId>
-      <artifactId>ribbon-loadbalancer</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-beans</artifactId>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>foundation-config</artifactId>
     </dependency>
     <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>deployment</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.yaml</groupId>
-      <artifactId>snakeyaml</artifactId>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>foundation-ssl</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.servicecomb</groupId>
-      <artifactId>common-rest</artifactId>
+      <artifactId>foundation-vertx</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.servicecomb</groupId>
-      <artifactId>handler-loadbalance</artifactId>
+      <groupId>io.vertx</groupId>
+      <artifactId>vertx-codegen</artifactId>
+      <scope>provided</scope>
     </dependency>
   </dependencies>
 </project>
\ No newline at end of file
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/archaius/sources/KieConfigurationSourceImpl.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/archaius/sources/KieConfigurationSourceImpl.java
new file mode 100644
index 0000000..dc9c1af
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/archaius/sources/KieConfigurationSourceImpl.java
@@ -0,0 +1,131 @@
+/*
+ * 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.servicecomb.config.kie.archaius.sources;
+
+import static com.netflix.config.WatchedUpdateResult.createIncremental;
+
+import com.google.common.collect.ImmutableMap;
+import com.netflix.config.ConcurrentCompositeConfiguration;
+import com.netflix.config.WatchedUpdateListener;
+import com.netflix.config.WatchedUpdateResult;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import org.apache.commons.configuration.Configuration;
+import org.apache.servicecomb.config.ConfigMapping;
+import org.apache.servicecomb.config.kie.client.KieClient;
+import org.apache.servicecomb.config.kie.client.KieConfig;
+import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KieConfigurationSourceImpl implements 
ConfigCenterConfigurationSource {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(KieConfigurationSourceImpl.class);
+
+  private static final String KIE_CONFIG_URL_KEY = "servicecomb.kie.serverUri";
+
+  private final Map<String, Object> valueCache = new ConcurrentHashMap<>();
+
+  private List<WatchedUpdateListener> listeners = new CopyOnWriteArrayList<>();
+
+  private UpdateHandler updateHandler = new UpdateHandler();
+
+  private KieClient kieClient;
+
+  @Override
+  public boolean isValidSource(Configuration localConfiguration) {
+    if (localConfiguration.getProperty(KIE_CONFIG_URL_KEY) == null) {
+      LOGGER.warn("Kie configuration source is not configured!");
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public void init(Configuration localConfiguration) {
+    KieConfig.setFinalConfig((ConcurrentCompositeConfiguration) 
localConfiguration);
+    kieClient = new KieClient(updateHandler);
+    kieClient.refreshKieConfig();
+  }
+
+  @Override
+  public void destroy() {
+    if (kieClient == null) {
+      return;
+    }
+    kieClient.destroy();
+  }
+
+  @Override
+  public void addUpdateListener(WatchedUpdateListener watchedUpdateListener) {
+    listeners.add(watchedUpdateListener);
+  }
+
+  @Override
+  public void removeUpdateListener(WatchedUpdateListener 
watchedUpdateListener) {
+    listeners.remove(watchedUpdateListener);
+  }
+
+  @Override
+  public Map<String, Object> getCurrentData() throws Exception {
+    return valueCache;
+  }
+
+
+  private void updateConfiguration(WatchedUpdateResult result) {
+    for (WatchedUpdateListener l : listeners) {
+      try {
+        l.updateConfiguration(result);
+      } catch (Throwable ex) {
+        LOGGER.error("Error in invoking WatchedUpdateListener", ex);
+      }
+    }
+  }
+
+  public class UpdateHandler {
+
+    public void handle(String action, Map<String, Object> parseConfigs) {
+      if (parseConfigs == null || parseConfigs.isEmpty()) {
+        return;
+      }
+      Map<String, Object> configuration = 
ConfigMapping.getConvertedMap(parseConfigs);
+      if ("create".equals(action)) {
+        valueCache.putAll(configuration);
+        updateConfiguration(createIncremental(ImmutableMap.<String, 
Object>copyOf(configuration),
+            null,
+            null));
+      } else if ("set".equals(action)) {
+        valueCache.putAll(configuration);
+        updateConfiguration(
+            createIncremental(null, ImmutableMap.<String, 
Object>copyOf(configuration),
+                null));
+      } else if ("delete".equals(action)) {
+        configuration.keySet().forEach(valueCache::remove);
+        updateConfiguration(createIncremental(null,
+            null,
+            ImmutableMap.<String, Object>copyOf(configuration)));
+      } else {
+        LOGGER.error("action: {} is invalid.", action);
+        return;
+      }
+      LOGGER.warn("Config value cache changed: action:{}; item:{}", action, 
configuration.keySet());
+    }
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnFailEvent.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnFailEvent.java
new file mode 100644
index 0000000..1e34810
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnFailEvent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+public class ConnFailEvent {
+
+  private String msg;
+
+  public ConnFailEvent(String msg) {
+    this.msg = msg;
+  }
+
+  public String getMsg() {
+    return msg;
+  }
+
+  public void setMsg(String msg) {
+    this.msg = msg;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnSuccEvent.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnSuccEvent.java
new file mode 100644
index 0000000..95d9758
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/ConnSuccEvent.java
@@ -0,0 +1,22 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+public class ConnSuccEvent {
+
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
new file mode 100644
index 0000000..c606c2c
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieClient.java
@@ -0,0 +1,165 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.HttpClientRequest;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.http.HttpStatus;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl.UpdateHandler;
+import org.apache.servicecomb.config.kie.model.KVResponse;
+import org.apache.servicecomb.foundation.common.event.EventManager;
+import org.apache.servicecomb.foundation.common.net.IpPort;
+import org.apache.servicecomb.foundation.common.net.NetUtils;
+import org.apache.servicecomb.foundation.common.utils.JsonUtils;
+import org.apache.servicecomb.foundation.vertx.AddressResolverConfig;
+import org.apache.servicecomb.foundation.vertx.VertxUtils;
+import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager;
+import org.apache.servicecomb.foundation.vertx.client.ClientVerticle;
+import 
org.apache.servicecomb.foundation.vertx.client.http.HttpClientPoolFactory;
+import 
org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KieClient {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(KieClient.class);
+
+  private ScheduledExecutorService EXECUTOR = 
Executors.newScheduledThreadPool(1);
+
+  private static final long TIME_OUT = 10000;
+
+  private static final KieConfig KIE_CONFIG = KieConfig.INSTANCE;
+
+  private final int refreshInterval = KIE_CONFIG.getRefreshInterval();
+
+  private final int firstRefreshInterval = 
KIE_CONFIG.getFirstRefreshInterval();
+
+  private final String serviceUri = KIE_CONFIG.getServerUri();
+
+  private ClientPoolManager<HttpClientWithContext> clientMgr;
+
+  public KieClient(UpdateHandler updateHandler) {
+    KieWatcher.INSTANCE.setUpdateHandler(updateHandler);
+  }
+
+  public void refreshKieConfig() {
+    try {
+      deployConfigClient();
+    } catch (InterruptedException e) {
+      throw new IllegalStateException(e);
+    }
+    EXECUTOR
+        .scheduleWithFixedDelay(new ConfigRefresh(serviceUri), 
firstRefreshInterval,
+            refreshInterval, TimeUnit.SECONDS);
+  }
+
+  private void deployConfigClient() throws InterruptedException {
+    VertxOptions vertxOptions = new VertxOptions();
+    
vertxOptions.setAddressResolverOptions(AddressResolverConfig.getAddressResover("kie.consumer",
+        KieConfig.getFinalConfig()));
+    Vertx vertx = VertxUtils.getOrCreateVertxByName("kie", vertxOptions);
+
+    HttpClientOptions httpClientOptions = new HttpClientOptions();
+    clientMgr = new ClientPoolManager<>(vertx, new 
HttpClientPoolFactory(httpClientOptions));
+
+    DeploymentOptions deployOptions = 
VertxUtils.createClientDeployOptions(clientMgr, 1);
+    VertxUtils.blockDeploy(vertx, ClientVerticle.class, deployOptions);
+  }
+
+  public void destroy() {
+    if (EXECUTOR != null) {
+      EXECUTOR.shutdown();
+      EXECUTOR = null;
+    }
+  }
+
+  class ConfigRefresh implements Runnable {
+
+    private final String serviceUri;
+
+    ConfigRefresh(String serviceUris) {
+      this.serviceUri = serviceUris;
+    }
+
+    @Override
+    public void run() {
+      try {
+        refreshConfig();
+      } catch (Throwable e) {
+        LOGGER.error("client refresh thread exception ", e);
+      }
+    }
+
+    //todo : latch down
+    @SuppressWarnings("deprecation")
+    void refreshConfig() {
+      String path = "/v1/"
+          + KieConfig.INSTANCE.getDomainName()
+          + "/kie/kv?label=app:"
+          + KieConfig.INSTANCE.getAppName();
+      clientMgr.findThreadBindClientPool().runOnContext(client -> {
+        IpPort ipPort = NetUtils.parseIpPortFromURI(serviceUri);
+        HttpClientRequest request = client
+            .get(ipPort.getPort(), ipPort.getHostOrIp(), path, rsp -> {
+              if (rsp.statusCode() == HttpResponseStatus.OK.code()) {
+                rsp.bodyHandler(buf -> {
+                  try {
+                    Map<String, Object> resMap = 
KieUtil.getConfigByLabel(JsonUtils.OBJ_MAPPER
+                        .readValue(buf.toString(), KVResponse.class));
+                    KieWatcher.INSTANCE.refreshConfigItems(resMap);
+                    EventManager.post(new ConnSuccEvent());
+                  } catch (IOException e) {
+                    EventManager.post(new ConnFailEvent(
+                        "config update result parse fail " + e.getMessage()));
+                    LOGGER.error("Config update from {} failed. Error message 
is [{}].",
+                        serviceUri,
+                        e.getMessage());
+                  }
+                });
+                // latch.countDown();
+              } else if (rsp.statusCode() == HttpStatus.SC_NOT_FOUND) {
+                EventManager.post(new ConnSuccEvent());
+//                latch.countDown();
+              } else {
+                EventManager.post(new ConnFailEvent("fetch config fail"));
+                LOGGER.error("Config update from {} failed. Error message is 
[{}].",
+                    serviceUri,
+                    rsp.statusMessage());
+              }
+            }).setTimeout(TIME_OUT);
+        request.exceptionHandler(e -> {
+          EventManager.post(new ConnFailEvent("fetch config fail"));
+          LOGGER.error("Config update from {} failed. Error message is [{}].",
+              serviceUri,
+              e.getMessage());
+//          latch.countDown();
+        });
+        request.end();
+      });
+    }
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieConfig.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieConfig.java
new file mode 100644
index 0000000..a0b45e2
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieConfig.java
@@ -0,0 +1,98 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import static 
org.apache.servicecomb.foundation.common.base.ServiceCombConstants.DEFAULT_SERVICECOMB_ENV;
+import static 
org.apache.servicecomb.foundation.common.base.ServiceCombConstants.SERVICECOMB_ENV;
+
+import com.netflix.config.ConcurrentCompositeConfiguration;
+
+public class KieConfig {
+
+  public static final KieConfig INSTANCE = new KieConfig();
+
+  private static ConcurrentCompositeConfiguration finalConfig;
+
+  private static final String SERVER_URL_KEY = "servicecomb.kie.serverUri";
+
+  private static final String REFRESH_INTERVAL = 
"servicecomb.kie.refreshInterval";
+
+  private static final String FIRST_REFRESH_INTERVAL = 
"servicecomb.kie.firstRefreshInterval";
+
+  private static final String DOMAIN_NAME = "servicecomb.kie.domainName";
+
+  private static final String APPLICATION_NAME = "APPLICATION_ID";
+
+  private static final String SERVICE_NAME = "service_description.name";
+
+  private static final String SERVICE_VERSION = "service_description.version";
+
+  private static final String INSTANCE_TAGS = 
"instance_description.properties.tags";
+
+
+  private static final int DEFAULT_REFRESH_INTERVAL = 3000;
+
+  private static final int DEFAULT_FIRST_REFRESH_INTERVAL = 0;
+
+  private KieConfig() {
+  }
+
+  public static ConcurrentCompositeConfiguration getFinalConfig() {
+    return finalConfig;
+  }
+
+  public static void setFinalConfig(ConcurrentCompositeConfiguration 
finalConfig) {
+    KieConfig.finalConfig = finalConfig;
+  }
+
+  public String getVersion() {
+    return finalConfig.getString(SERVICE_VERSION);
+  }
+
+  public String getServiceName() {
+    return finalConfig.getString(SERVICE_NAME);
+  }
+
+  public String getTags() {
+    return finalConfig.getString(INSTANCE_TAGS);
+  }
+
+  public String getEnvironment() {
+    return finalConfig.getString(SERVICECOMB_ENV, DEFAULT_SERVICECOMB_ENV);
+  }
+
+  public String getAppName() {
+    return finalConfig.getString(APPLICATION_NAME);
+  }
+
+  public String getDomainName() {
+    return finalConfig.getString(DOMAIN_NAME, "default");
+  }
+
+  public String getServerUri() {
+    return finalConfig.getString(SERVER_URL_KEY);
+  }
+
+  public int getRefreshInterval() {
+    return finalConfig.getInt(REFRESH_INTERVAL, DEFAULT_REFRESH_INTERVAL);
+  }
+
+  public int getFirstRefreshInterval() {
+    return finalConfig.getInt(FIRST_REFRESH_INTERVAL, 
DEFAULT_FIRST_REFRESH_INTERVAL);
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieUtil.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieUtil.java
new file mode 100644
index 0000000..1e91d37
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieUtil.java
@@ -0,0 +1,148 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import java.io.StringReader;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import org.apache.servicecomb.config.kie.model.KVDoc;
+import org.apache.servicecomb.config.kie.model.KVResponse;
+import org.apache.servicecomb.config.kie.model.ValueType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.util.StringUtils;
+
+public class KieUtil {
+  private static final Logger LOGGER = LoggerFactory.getLogger(KieUtil.class);
+
+  public static String encrypt(String dataStr) {
+    MessageDigest messageDigest = null;
+    String result = "";
+    try {
+      messageDigest = MessageDigest.getInstance("MD5");
+      messageDigest.update(dataStr.getBytes(StandardCharsets.UTF_8));
+      result = new BigInteger(1, 
messageDigest.digest(dataStr.getBytes(StandardCharsets.UTF_8)))
+          .toString(16);
+    } catch (NoSuchAlgorithmException e) {
+      LOGGER.error("Failed to generate MD5 . ", e);
+    }
+    return result;
+  }
+
+  public static Map<String, Object> getConfigByLabel(KVResponse resp) {
+    Map<String, Object> resultMap = new HashMap<>();
+    List<KVDoc> appList = new ArrayList<>();
+    List<KVDoc> serviceList = new ArrayList<>();
+    List<KVDoc> versionList = new ArrayList<>();
+    for (KVDoc kvDoc : resp.getData()) {
+      Map<String, String> labelsMap = kvDoc.getLabels();
+      //todo:how to deal env
+      if (labelsMap.containsKey("app") && labelsMap.get("app")
+          .equals(KieConfig.INSTANCE.getAppName())
+          && labelsMap.containsKey("env") && labelsMap.get("env")
+          .equals(KieConfig.INSTANCE.getEnvironment())) {
+        if (!labelsMap.containsKey("service")) {
+          appList.add(kvDoc);
+        }
+        if (labelsMap.containsKey("service") && labelsMap.get("service")
+            .equals(KieConfig.INSTANCE.getServiceName())) {
+          if (!kvDoc.getLabels().containsKey("version")) {
+            serviceList.add(kvDoc);
+          }
+          if (labelsMap.containsKey("version") && labelsMap.get("version")
+              .equals(KieConfig.INSTANCE.getServiceName())) {
+            versionList.add(kvDoc);
+          }
+        }
+      }
+    }
+    //kv is priority
+    for (KVDoc kvDoc : appList) {
+      resultMap.putAll(processValueType(kvDoc));
+    }
+    for (KVDoc kvDoc : serviceList) {
+      resultMap.putAll(processValueType(kvDoc));
+    }
+    for (KVDoc kvDoc : versionList) {
+      resultMap.putAll(processValueType(kvDoc));
+    }
+    return resultMap;
+  }
+
+  public static Map<String, String> processValueType(KVDoc kvDoc) {
+    ValueType vtype;
+    try {
+      vtype = ValueType.valueOf(kvDoc.getValueType());
+    } catch (IllegalArgumentException e) {
+      throw new RuntimeException("value type not support");
+    }
+    Properties properties = new Properties();
+    Map<String, String> kvMap = new HashMap<>();
+    try {
+      if (vtype == (ValueType.YMAL) || vtype == (ValueType.YML)) {
+        YamlPropertiesFactoryBean yamlFactory = new 
YamlPropertiesFactoryBean();
+        yamlFactory.setResources(new 
ByteArrayResource(kvDoc.getValue().getBytes()));
+        properties = yamlFactory.getObject();
+      } else if (vtype == (ValueType.PROPERTIES)) {
+        properties.load(new StringReader(kvDoc.getValue()));
+      } else if (vtype == (ValueType.TEXT) || vtype == (ValueType.STRING)) {
+        kvMap.put(kvDoc.getKey(), kvDoc.getValue());
+        return kvMap;
+      } else {
+        kvMap.put(kvDoc.getKey(), kvDoc.getValue());
+        return kvMap;
+      }
+      kvMap = toMap(kvDoc.getKey(), properties);
+      return kvMap;
+    } catch (Exception e) {
+      LOGGER.error("read config failed");
+    }
+    return Collections.emptyMap();
+  }
+
+
+  @SuppressWarnings("unchecked")
+  private static Map<String, String> toMap(String prefix, Properties 
properties) {
+    Map<String, String> result = new HashMap<>();
+    Enumeration<String> keys = (Enumeration<String>) 
properties.propertyNames();
+    while (keys.hasMoreElements()) {
+      String key = keys.nextElement();
+      if (!StringUtils.isEmpty(prefix)) {
+        key = prefix + "." + key;
+      }
+      Object value = properties.getProperty(key);
+      if (value != null) {
+        result.put(key, ((String) value).trim());
+      } else {
+        result.put(key, null);
+      }
+    }
+    return result;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieWatcher.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieWatcher.java
new file mode 100644
index 0000000..4ea5e26
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/client/KieWatcher.java
@@ -0,0 +1,86 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import java.util.HashMap;
+import java.util.Map;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl.UpdateHandler;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+public class KieWatcher {
+
+  public static final KieWatcher INSTANCE = new KieWatcher();
+
+  private UpdateHandler updateHandler;
+
+  private String refreshRecord;
+
+  Map<String, Object> lastTimeData;
+
+  private KieWatcher() {
+  }
+
+  public void setUpdateHandler(UpdateHandler updateHandler) {
+    this.updateHandler = updateHandler;
+  }
+
+  public void refreshConfigItems(Map<String, Object> remoteItems) {
+    String md5Vaule = KieUtil.encrypt(remoteItems.toString());
+    if (CollectionUtils.isEmpty(remoteItems)) {
+      updateHandler.handle("delete", remoteItems);
+      lastTimeData = remoteItems;
+      return;
+    }
+    if (StringUtils.isEmpty(refreshRecord)) {
+      refreshRecord = md5Vaule;
+      updateHandler.handle("create", remoteItems);
+      lastTimeData = remoteItems;
+      return;
+    }
+    if (md5Vaule.equals(refreshRecord)) {
+      return;
+    }
+    refreshRecord = md5Vaule;
+    doRefresh(remoteItems);
+    lastTimeData = remoteItems;
+  }
+
+
+  private void doRefresh(Map<String, Object> remoteItems) {
+    Map<String, Object> itemsCreated = new HashMap<>();
+    Map<String, Object> itemsDeleted = new HashMap<>();
+    Map<String, Object> itemsModified = new HashMap<>();
+    for (String itemKey : remoteItems.keySet()) {
+      if (!lastTimeData.containsKey(itemKey)) {
+        itemsCreated.put(itemKey, remoteItems.get(itemKey));
+      } else if (!remoteItems.get(itemKey).equals(lastTimeData.get(itemKey))) {
+        itemsModified.put(itemKey, remoteItems.get(itemKey));
+      }
+    }
+    for (String itemKey : lastTimeData.keySet()) {
+      if (!remoteItems.containsKey(itemKey)) {
+        itemsDeleted.put(itemKey, "");
+      }
+    }
+    updateHandler.handle("create", itemsCreated);
+    updateHandler.handle("set", itemsModified);
+    updateHandler.handle("delete", itemsDeleted);
+  }
+
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVBody.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVBody.java
new file mode 100644
index 0000000..b7deee0
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVBody.java
@@ -0,0 +1,65 @@
+/*
+ * 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.servicecomb.config.kie.model;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.servicecomb.config.kie.client.KieConfig;
+
+public class KVBody {
+
+  private Map<String, String> labels = new HashMap<String, String>();
+
+  private String value;
+
+  @JsonAlias("value_type")
+  private String valueType;
+
+  public Map<String, String> getLabels() {
+    return labels;
+  }
+
+  public void setLabels(Map<String, String> labels) {
+    this.labels = labels;
+  }
+
+  public void initLabels() {
+    labels.put("env", KieConfig.INSTANCE.getEnvironment());
+    labels.put("app", KieConfig.INSTANCE.getAppName());
+    labels.put("service", KieConfig.INSTANCE.getServiceName());
+    labels.put("version", KieConfig.INSTANCE.getVersion());
+    labels.put("tags", KieConfig.INSTANCE.getTags());
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  public String getValueType() {
+    return valueType;
+  }
+
+  public void setValueType(String valueType) {
+    this.valueType = valueType;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVDoc.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVDoc.java
new file mode 100644
index 0000000..73c02e8
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVDoc.java
@@ -0,0 +1,118 @@
+/*
+ * 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.servicecomb.config.kie.model;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import java.util.HashMap;
+import java.util.Map;
+
+public class KVDoc {
+
+  @JsonAlias("_id")
+  private String id;
+
+  private String check;
+
+  private String domain;
+
+  private String key;
+
+  @JsonAlias("label_id")
+  private String labelId;
+
+  private Map<String, String> labels = new HashMap<String, String>();
+
+  private Integer revision;
+
+  private String value;
+
+  @JsonAlias("value_type")
+  private String valueType;
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public void setKey(String key) {
+    this.key = key;
+  }
+
+  public String getCheck() {
+    return check;
+  }
+
+  public String getDomain() {
+    return domain;
+  }
+
+  public String getLabelId() {
+    return labelId;
+  }
+
+  public Map<String, String> getLabels() {
+    return labels;
+  }
+
+  public Integer getRevision() {
+    return revision;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public void setCheck(String check) {
+    this.check = check;
+  }
+
+  public void setDomain(String domain) {
+    this.domain = domain;
+  }
+
+  public void setLabelId(String labelId) {
+    this.labelId = labelId;
+  }
+
+  public void setLabels(Map<String, String> labels) {
+    this.labels = labels;
+  }
+
+  public void setRevision(Integer revision) {
+    this.revision = revision;
+  }
+
+  public void setValueType(String valueType) {
+    this.valueType = valueType;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  public String getValueType() {
+    return valueType;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVResponse.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVResponse.java
new file mode 100644
index 0000000..79bc6aa
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/KVResponse.java
@@ -0,0 +1,73 @@
+/*
+ * 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.servicecomb.config.kie.model;
+
+import java.util.List;
+
+public class KVResponse {
+
+  private List<KVDoc> data;
+
+  private LabelDocResponse label;
+
+  private Integer num;
+
+  private Integer size;
+
+  private Integer total;
+
+  public Integer getNum() {
+    return num;
+  }
+
+  public void setNum(Integer num) {
+    this.num = num;
+  }
+
+  public Integer getSize() {
+    return size;
+  }
+
+  public void setSize(Integer size) {
+    this.size = size;
+  }
+
+  public Integer getTotal() {
+    return total;
+  }
+
+  public void setTotal(Integer total) {
+    this.total = total;
+  }
+
+  public List<KVDoc> getData() {
+    return data;
+  }
+
+  public LabelDocResponse getLabel() {
+    return label;
+  }
+
+  public void setData(List<KVDoc> data) {
+    this.data = data;
+  }
+
+  public void setLabel(LabelDocResponse label) {
+    this.label = label;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/LabelDocResponse.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/LabelDocResponse.java
new file mode 100644
index 0000000..fb2b541
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/LabelDocResponse.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.model;
+
+import com.fasterxml.jackson.annotation.JsonAlias;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LabelDocResponse {
+
+  @JsonAlias("label_id")
+  private String labelId;
+
+  private Map<String, String> labels = new HashMap<String, String>();
+
+  public String getLabelId() {
+    return labelId;
+  }
+
+  public Map<String, String> getLabels() {
+    return labels;
+  }
+
+  public void setLabelId(String labelId) {
+    this.labelId = labelId;
+  }
+
+  public void setLabels(Map<String, String> labels) {
+    this.labels = labels;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/ValueType.java
 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/ValueType.java
new file mode 100644
index 0000000..0658be2
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/java/org/apache/servicecomb/config/kie/model/ValueType.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.model;
+
+public enum ValueType {
+  YML("yml"),
+  YMAL("yaml"),
+  STRING("string"),
+  TEXT("text"),
+  JSON("json"),
+  PROPERTIES("properties");
+  
+  private String value;
+
+  ValueType(String value) {
+    this.value = value;
+  }
+
+  public String getValue() {
+    return this.value;
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource
 
b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource
new file mode 100644
index 0000000..c696fa9
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/main/resources/META-INF/services/org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource
@@ -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.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl
\ No newline at end of file
diff --git 
a/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieClient.java
 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieClient.java
new file mode 100644
index 0000000..2bcd0f1
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieClient.java
@@ -0,0 +1,205 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import com.google.common.eventbus.Subscribe;
+import io.vertx.core.Handler;
+import io.vertx.core.MultiMap;
+import io.vertx.core.buffer.Buffer;
+import io.vertx.core.http.HttpClient;
+import io.vertx.core.http.HttpClientRequest;
+import io.vertx.core.http.HttpClientResponse;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.json.JsonObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import mockit.Deencapsulation;
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+import org.apache.servicecomb.config.ConfigUtil;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl.UpdateHandler;
+import org.apache.servicecomb.config.kie.client.KieClient.ConfigRefresh;
+import org.apache.servicecomb.foundation.common.event.EventManager;
+import org.apache.servicecomb.foundation.vertx.client.ClientPoolManager;
+import 
org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
+import 
org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext.RunHandler;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@SuppressWarnings("deprecation")
+public class TestKieClient {
+
+  String mockKvResponse = "{\n"
+      + "  \"data\": [\n"
+      + "    {\n"
+      + "      \"_id\": \"string\",\n"
+      + "      \"check\": \"string\",\n"
+      + "      \"domain\": \"string\",\n"
+      + "      \"key\": \"string\",\n"
+      + "      \"label_id\": \"string\",\n"
+      + "      \"labels\": {\n"
+      + "        \"additionalProp1\": \"string\",\n"
+      + "        \"additionalProp2\": \"string\",\n"
+      + "        \"additionalProp3\": \"string\"\n"
+      + "      },\n"
+      + "      \"project\": \"string\",\n"
+      + "      \"revision\": 0,\n"
+      + "      \"value\": \"string\",\n"
+      + "      \"value_type\": \"string\"\n"
+      + "    }\n"
+      + "  ],\n"
+      + "  \"label\": {\n"
+      + "    \"label_id\": \"string\",\n"
+      + "    \"labels\": {\n"
+      + "      \"additionalProp1\": \"string\",\n"
+      + "      \"additionalProp2\": \"string\",\n"
+      + "      \"additionalProp3\": \"string\"\n"
+      + "    }\n"
+      + "  },\n"
+      + "  \"num\": 0,\n"
+      + "  \"size\": 0,\n"
+      + "  \"total\": 0\n"
+      + "}";
+
+  @BeforeClass
+  public static void setUpClass() {
+    KieConfig.setFinalConfig(ConfigUtil.createLocalConfig());
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testRefreshKieConfig() {
+    HttpClientRequest request = Mockito.mock(HttpClientRequest.class);
+    Mockito.when(request.method()).thenReturn(HttpMethod.GET);
+    
Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap());
+    Buffer rsp = Mockito.mock(Buffer.class);
+    Mockito.when(rsp.toJsonObject()).thenReturn(new 
JsonObject(mockKvResponse));
+    HttpClientResponse event = Mockito.mock(HttpClientResponse.class);
+    
Mockito.when(event.bodyHandler(Mockito.any(Handler.class))).then(invocation -> {
+      Handler<Buffer> handler = invocation.getArgumentAt(0, Handler.class);
+      handler.handle(rsp);
+      return null;
+    });
+    Mockito.when(event.statusCode()).thenReturn(200);
+    HttpClient httpClient = Mockito.mock(HttpClient.class);
+    Mockito.when(
+        httpClient.get(Mockito.anyInt(), Mockito.anyString(), 
Mockito.anyString(),
+            Mockito.any(Handler.class)))
+        .then(invocation -> {
+          Handler<HttpClientResponse> handler = invocation.getArgumentAt(3, 
Handler.class);
+          handler.handle(event);
+          return request;
+        });
+    new MockUp<HttpClientWithContext>() {
+      @Mock
+      public void runOnContext(RunHandler handler) {
+        handler.run(httpClient);
+      }
+    };
+    UpdateHandler updateHandler = new KieConfigurationSourceImpl().new 
UpdateHandler();
+    KieClient kie = new KieClient(updateHandler);
+    kie.refreshKieConfig();
+  }
+
+
+  public static class ConfigRefreshExceptionEvent {
+    Map<String, String> map;
+
+    public ConfigRefreshExceptionEvent(Map<String, String> map) {
+      this.map = map;
+    }
+
+    @Subscribe
+    public void testMsg(Object event) {
+      if (event instanceof ConnFailEvent) {
+        map.put("result", "Fail event trigger");
+      }
+      if (event instanceof ConnSuccEvent) {
+        map.put("result", "Succ event trigger");
+      }
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testConfigRefreshException(@Mocked 
ClientPoolManager<HttpClientWithContext> clientMgr,
+      @Mocked HttpClientWithContext httpClientWithContext) {
+    KieConfigurationSourceImpl impl = new KieConfigurationSourceImpl();
+    Map<String, String> map = new HashMap<>();
+    EventManager.register(new ConfigRefreshExceptionEvent(map));
+    UpdateHandler updateHandler = impl.new UpdateHandler();
+    HttpClientRequest request = Mockito.mock(HttpClientRequest.class);
+    
Mockito.when(request.headers()).thenReturn(MultiMap.caseInsensitiveMultiMap());
+    Buffer rsp = Mockito.mock(Buffer.class);
+    Mockito.when(rsp.toString()).thenReturn(mockKvResponse);
+
+    HttpClientResponse event = Mockito.mock(HttpClientResponse.class);
+    
Mockito.when(event.bodyHandler(Mockito.any(Handler.class))).then(invocation -> {
+      Handler<Buffer> handler = invocation.getArgumentAt(0, Handler.class);
+      handler.handle(rsp);
+      return null;
+    });
+    Mockito.when(event.statusCode()).thenReturn(400);
+    Buffer buf = Mockito.mock(Buffer.class);
+    Mockito.when(buf.toJsonObject()).thenReturn(new 
JsonObject(mockKvResponse));
+    HttpClient httpClient = Mockito.mock(HttpClient.class);
+    Mockito.when(
+        httpClient.get(Mockito.anyInt(), Mockito.anyString(), 
Mockito.anyString(),
+            Mockito.any(Handler.class)))
+        .then(invocation -> {
+          Handler<HttpClientResponse> handler = invocation.getArgumentAt(3, 
Handler.class);
+          handler.handle(event);
+          return request;
+        });
+    new MockUp<HttpClientWithContext>() {
+      @Mock
+      public void runOnContext(RunHandler handler) {
+        handler.run(httpClient);
+      }
+    };
+    new Expectations() {
+      {
+        clientMgr.findThreadBindClientPool();
+        result = httpClientWithContext;
+      }
+    };
+    KieClient kie = new KieClient(updateHandler);
+    Deencapsulation.setField(kie, "clientMgr", clientMgr);
+    ConfigRefresh refresh = kie.new 
ConfigRefresh("http://configcentertest:30103";);
+    refresh.run();
+    Assert.assertEquals("Fail event trigger", map.get("result"));
+    Mockito.when(event.statusCode()).thenReturn(200);
+    refresh.run();
+    Assert.assertEquals("Succ event trigger", map.get("result"));
+  }
+
+  @Test
+  public void destroy() {
+    KieClient kieClient = new KieClient(null);
+    ScheduledExecutorService executor = Deencapsulation.getField(kieClient, 
"EXECUTOR");
+    Assert.assertFalse(executor.isShutdown());
+    executor.shutdown();
+    Assert.assertTrue(executor.isShutdown());
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieConfig.java
 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieConfig.java
new file mode 100644
index 0000000..d0f0676
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.config.kie.client;
+
+import org.apache.servicecomb.config.ConfigUtil;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestKieConfig {
+
+  @BeforeClass
+  public static void setUpClass() {
+    KieConfig.setFinalConfig(ConfigUtil.createLocalConfig());
+  }
+
+  @Test
+  public void getServerUri() {
+    String servers = KieConfig.INSTANCE.getServerUri();
+    Assert.assertEquals("https://172.16.8.7:30103";, servers);
+  }
+
+  @Test
+  public void getEnvironment() {
+    Assert.assertEquals("testing", KieConfig.INSTANCE.getEnvironment());
+    System.setProperty("SERVICECOMB_ENV", "development");
+    KieConfig.setFinalConfig(ConfigUtil.createLocalConfig());
+    Assert.assertEquals("development", KieConfig.INSTANCE.getEnvironment());
+  }
+
+}
diff --git 
a/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieWatcher.java
 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieWatcher.java
new file mode 100644
index 0000000..126107e
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/client/TestKieWatcher.java
@@ -0,0 +1,54 @@
+/*
+ * 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.servicecomb.config.kie.client;
+
+import java.util.HashMap;
+import java.util.Map;
+import mockit.Deencapsulation;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl.UpdateHandler;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestKieWatcher {
+
+  private KieConfigurationSourceImpl kieSource = new 
KieConfigurationSourceImpl();
+
+  private UpdateHandler uh = kieSource.new UpdateHandler();
+
+  {
+    KieWatcher.INSTANCE.setUpdateHandler(uh);
+  }
+
+  @Test
+  public void testRefreshConfigItems() {
+    boolean status = true;
+    Map<String, Object> configMap = new HashMap<>();
+    configMap.put("key1", "application1");
+    configMap.put("key2", "application2");
+    configMap.put("key3", "application3");
+    configMap.put("key4", "application4");
+    Map<String, Object> result = null;
+    try {
+      result = Deencapsulation.invoke(KieWatcher.INSTANCE, 
"refreshConfigItems", configMap);
+    } catch (Exception e) {
+      status = false;
+    }
+    Assert.assertTrue(status);
+  }
+}
diff --git 
a/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/sources/TestKieConfigurationSource.java
 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/sources/TestKieConfigurationSource.java
new file mode 100644
index 0000000..73cfae5
--- /dev/null
+++ 
b/dynamic-config/config-kie/src/test/java/org/apache/servicecomb/config/kie/sources/TestKieConfigurationSource.java
@@ -0,0 +1,96 @@
+/*
+ * 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.servicecomb.config.kie.sources;
+
+import com.netflix.config.WatchedUpdateListener;
+import com.netflix.config.WatchedUpdateResult;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import mockit.Deencapsulation;
+import mockit.Mock;
+import mockit.MockUp;
+import org.apache.commons.lang.reflect.FieldUtils;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl;
+import 
org.apache.servicecomb.config.kie.archaius.sources.KieConfigurationSourceImpl.UpdateHandler;
+import org.apache.servicecomb.config.kie.client.KieClient;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestKieConfigurationSource {
+
+  @Test
+  public void testCreate() {
+
+    KieConfigurationSourceImpl kieSource = new KieConfigurationSourceImpl();
+    kieSource.addUpdateListener(result -> 
Assert.assertTrue(!result.getAdded().isEmpty()));
+    UpdateHandler udateHandler = Deencapsulation.getField(kieSource, 
UpdateHandler.class);
+    Map<String, Object> addedItems = new HashMap<>();
+    addedItems.put("testKey", "testValue");
+    udateHandler.handle("create", addedItems);
+  }
+
+  @Test
+  public void testUpdate() {
+
+    KieConfigurationSourceImpl kieSource = new KieConfigurationSourceImpl();
+    kieSource.addUpdateListener(result -> 
Assert.assertTrue(!result.getChanged().isEmpty()));
+    UpdateHandler udateHandler = Deencapsulation.getField(kieSource, 
UpdateHandler.class);
+    Map<String, Object> addedItems = new HashMap<>();
+    addedItems.put("testKey", "testValue");
+    udateHandler.handle("set", addedItems);
+  }
+
+  @Test
+  public void testDelete() throws Exception {
+    KieConfigurationSourceImpl kieSource = new KieConfigurationSourceImpl();
+    kieSource.addUpdateListener(result -> 
Assert.assertTrue(!result.getDeleted().isEmpty()));
+    UpdateHandler udateHandler = Deencapsulation.getField(kieSource, 
UpdateHandler.class);
+    Map<String, Object> addedItems = new HashMap<>();
+    addedItems.put("testKey", "testValue");
+
+    kieSource.getCurrentData().put("testKey", "testValue");
+    udateHandler.handle("delete", addedItems);
+    Assert.assertTrue(kieSource.getCurrentData().isEmpty());
+  }
+
+  @Test
+  public void destroy_notInit() {
+    KieConfigurationSourceImpl kieSource = new KieConfigurationSourceImpl();
+
+    // need not throw exception
+    kieSource.destroy();
+  }
+
+  @Test
+  public void destroy_inited() throws IllegalAccessException {
+    AtomicInteger count = new AtomicInteger();
+    KieClient kieClient = new MockUp<KieClient>() {
+      @Mock
+      void destroy() {
+        count.incrementAndGet();
+      }
+    }.getMockInstance();
+    KieConfigurationSourceImpl kieSource = new KieConfigurationSourceImpl();
+    FieldUtils
+        .writeDeclaredField(kieSource, "kieClient", kieClient, true);
+
+    kieSource.destroy();
+
+    Assert.assertEquals(1, count.get());
+  }
+}
diff --git a/dynamic-config/config-kie/src/test/resources/microservice.yaml 
b/dynamic-config/config-kie/src/test/resources/microservice.yaml
new file mode 100644
index 0000000..43c4863
--- /dev/null
+++ b/dynamic-config/config-kie/src/test/resources/microservice.yaml
@@ -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.
+## ---------------------------------------------------------------------------
+
+host.name: 172.16.8.7
+trace:
+  handler:
+    enabled: false
+    sampler:
+      percent: 0.5
+  metric:
+    service:
+      enable: false
+validate:
+  parameter:
+    enabled: true
+  returnValue:
+    enabled: true
+  apiInvoke:
+    enabled: true
+shutDownHandler:
+  enabled: true
+  timeLimit: 30000
+eureka:
+  instance:
+    preferIpAddress: true
+    leaseRenewalIntervalInSeconds: 3
+    leaseExpirationDurationInSeconds: 5
+  client:
+    serviceUrl:
+      defaultZone: http://172.16.8.8:30100/
+servicecomb:
+  kie:
+    serverUri: https://172.16.8.7:30103
+  service:
+    registry:
+      autodiscovery: true
+      refreshInterval: 3000
+      firstRefreshInterval: 0
+
+service_description:
+  name: testDemo
+  environment: testing
diff --git a/dynamic-config/pom.xml b/dynamic-config/pom.xml
index afb0a20..71eaf00 100644
--- a/dynamic-config/pom.xml
+++ b/dynamic-config/pom.xml
@@ -35,6 +35,7 @@
     <module>config-apollo</module>
     <module>config-cc</module>
     <module>config-nacos</module>
+    <module>config-kie</module>
   </modules>
 
 </project>
diff --git a/handlers/handler-router/pom.xml b/handlers/handler-router/pom.xml
index f5b02d1..73ac5a9 100644
--- a/handlers/handler-router/pom.xml
+++ b/handlers/handler-router/pom.xml
@@ -27,6 +27,7 @@
   <modelVersion>4.0.0</modelVersion>
 
   <artifactId>handler-router</artifactId>
+  <name>Java Chassis::Handlers::Router</name>
 
   <dependencies>
     <dependency>

Reply via email to