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

albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 5f52fab  Add a new storage structure for zookeeper serviceNameMapping 
(#7629)
5f52fab is described below

commit 5f52fab4fdf64c105ad8f09b8193837f251b0629
Author: xiaoheng1 <[email protected]>
AuthorDate: Thu Apr 29 19:22:22 2021 +0800

    Add a new storage structure for zookeeper serviceNameMapping (#7629)
    
    * fix #7628 Add a new storage structure for zookeeper serviceNameMapping
    
    * add publishConfigCas test case.
---
 .../common/config/configcenter/ConfigItem.java     | 58 ++++++++++++++++++++
 .../config/configcenter/DynamicConfiguration.java  | 17 ++++--
 .../support/nacos/NacosDynamicConfiguration.java   | 19 ++++++-
 .../zookeeper/ZookeeperDynamicConfiguration.java   | 19 +++++++
 .../ZookeeperDynamicConfigurationTest.java         | 21 +++++++-
 .../DynamicConfigurationServiceNameMapping.java    | 13 +++--
 .../dubbo/remoting/zookeeper/ZookeeperClient.java  |  5 ++
 .../zookeeper/curator/CuratorZookeeperClient.java  | 62 +++++++++++++++++++++-
 .../zookeeper/support/AbstractZookeeperClient.java | 48 ++++++++++++++---
 9 files changed, 241 insertions(+), 21 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigItem.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigItem.java
new file mode 100644
index 0000000..61d9305
--- /dev/null
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/ConfigItem.java
@@ -0,0 +1,58 @@
+/*
+ * 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.dubbo.common.config.configcenter;
+
+/**
+ * Hold content and version information
+ */
+public class ConfigItem {
+
+    /**
+     * configure item content.
+     */
+    private String content;
+    /**
+     * version information corresponding to the current configure item.
+     */
+    private Object stat;
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Object getStat() {
+        return stat;
+    }
+
+    public void setStat(Object stat) {
+        this.stat = stat;
+    }
+
+    public ConfigItem(String content, Object stat) {
+        this.content = content;
+        this.stat = stat;
+    }
+
+    public ConfigItem() {
+
+    }
+}
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
index 75e0a6e..6e31d7f 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/config/configcenter/DynamicConfiguration.java
@@ -101,6 +101,17 @@ public interface DynamicConfiguration extends 
Configuration, AutoCloseable {
     }
 
     /**
+     * get configItem which contains content and stat info.
+     * @param key
+     * @param group
+     * @return
+     */
+    default ConfigItem getConfigItem(String key, String group) {
+        String content = getConfig(key, group);
+        return new ConfigItem(content, null);
+    }
+
+    /**
      * Get the configuration mapped to the given key and the given group. If 
the
      * configuration fails to fetch after timeout exceeds, 
IllegalStateException will be thrown.
      *
@@ -157,15 +168,15 @@ public interface DynamicConfiguration extends 
Configuration, AutoCloseable {
     }
 
     /**
-     * publish config mapped to this given key and given group with md5s.
+     * publish config mapped to this given key and given group with stat.
      * @param key
      * @param group
      * @param content
-     * @param casMd5
+     * @param stat
      * @return
      * @throws UnsupportedOperationException
      */
-    default boolean publishConfigCas(String key, String group, String content, 
String casMd5) throws UnsupportedOperationException {
+    default boolean publishConfigCas(String key, String group, String content, 
Object stat) throws UnsupportedOperationException {
         return false;
     }
 
diff --git 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
index 34e2e84..ac46c7e 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-nacos/src/main/java/org/apache/dubbo/configcenter/support/nacos/NacosDynamicConfiguration.java
@@ -20,10 +20,12 @@ package org.apache.dubbo.configcenter.support.nacos;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
 import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.MD5Utils;
 import org.apache.dubbo.common.utils.StringUtils;
 
 import com.alibaba.fastjson.JSON;
@@ -217,6 +219,16 @@ public class NacosDynamicConfiguration implements 
DynamicConfiguration {
     }
 
     @Override
+    public ConfigItem getConfigItem(String key, String group) {
+        String content = getConfig(key, group);
+        String casMd5 = "";
+        if (StringUtils.isNotEmpty(content)) {
+            casMd5 = MD5Utils.getMd5(content);
+        }
+        return new ConfigItem(content, casMd5);
+    }
+
+    @Override
     public Object getInternalProperty(String key) {
         try {
             return configService.getConfig(key, DEFAULT_GROUP, 
getDefaultTimeout());
@@ -239,11 +251,14 @@ public class NacosDynamicConfiguration implements 
DynamicConfiguration {
     }
 
     @Override
-    public boolean publishConfigCas(String key, String group, String content, 
String casMd5) {
+    public boolean publishConfigCas(String key, String group, String content, 
Object stat) {
         boolean published = false;
         String resolvedGroup = resolveGroup(group);
         try {
-            published = configService.publishConfigCas(key, resolvedGroup, 
content, casMd5);
+            if (!(null != stat && stat instanceof String)) {
+                throw new IllegalArgumentException("nacos publishConfigCas 
requires stat of string type");
+            }
+            published = configService.publishConfigCas(key, resolvedGroup, 
content, (String) stat);
         } catch (NacosException e) {
             logger.error(e.getErrMsg(), e);
         }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
index fbdbf74..a4c3511 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.configcenter.support.zookeeper;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
 import 
org.apache.dubbo.common.config.configcenter.TreePathDynamicConfiguration;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
@@ -89,11 +90,24 @@ public class ZookeeperDynamicConfiguration extends 
TreePathDynamicConfiguration
     }
 
     @Override
+    public boolean publishConfigCas(String key, String group, String content, 
Object stat) {
+        String pathKey = buildPathKey(group, key);
+        zkClient.createOrUpdate(pathKey, content, false, stat);
+        return true;
+    }
+
+    @Override
     protected String doGetConfig(String pathKey) throws Exception {
         return zkClient.getContent(pathKey);
     }
 
     @Override
+    public ConfigItem getConfigItem(String key, String group) {
+        String pathKey = buildPathKey(group, key);
+        return zkClient.getConfigItem(pathKey);
+    }
+
+    @Override
     protected boolean doRemoveConfig(String pathKey) throws Exception {
         zkClient.delete(pathKey);
         return true;
@@ -113,4 +127,9 @@ public class ZookeeperDynamicConfiguration extends 
TreePathDynamicConfiguration
     protected void doRemoveListener(String pathKey, ConfigurationListener 
listener) {
         cacheListener.removeListener(pathKey, listener);
     }
+
+    @Override
+    public boolean hasSupportCas() {
+        return true;
+    }
 }
diff --git 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java
 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java
index 9d4a0c3..ad4b5a9 100644
--- 
a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java
+++ 
b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/test/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfigurationTest.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.configcenter.support.zookeeper;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.ConfigurationListener;
 import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
 import org.apache.dubbo.common.config.configcenter.DynamicConfigurationFactory;
@@ -75,7 +76,8 @@ public class ZookeeperDynamicConfigurationTest {
 
         configUrl = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort);
 
-        configuration = 
ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getExtension(configUrl.getProtocol()).getDynamicConfiguration(configUrl);
+        configuration = 
ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getExtension(configUrl.getProtocol())
+                .getDynamicConfiguration(configUrl);
     }
 
     @AfterAll
@@ -138,6 +140,23 @@ public class ZookeeperDynamicConfigurationTest {
     }
 
     @Test
+    public void testPublishConfigCas() {
+        String key = "user-service";
+        String group = "org.apache.dubbo.service.UserService";
+        String content = "test";
+        assertTrue(configuration.publishConfigCas(key, group, content, null));
+        ConfigItem configItem = configuration.getConfigItem(key, group);
+        assertEquals("test", configItem.getContent());
+        assertTrue(configuration.publishConfigCas(key, group, "newtest", 
configItem.getStat()));
+        try {
+            configuration.publishConfigCas(key, group, "newtest2", 
configItem.getStat());
+        } catch (Exception e) {
+            assertTrue(e.getMessage().contains("KeeperErrorCode = 
BadVersion"));
+        }
+        assertEquals("newtest", configuration.getConfigItem(key, 
group).getContent());
+    }
+
+    @Test
     public void testGetConfigKeysAndContents() {
 
         String group = "mapping";
diff --git 
a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
 
b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
index 86a8f3d..bac064a 100644
--- 
a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
+++ 
b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DynamicConfigurationServiceNameMapping.java
@@ -17,11 +17,11 @@
 package org.apache.dubbo.metadata;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
 import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.MD5Utils;
 import org.apache.dubbo.common.utils.StringUtils;
 
 import java.util.Collections;
@@ -133,17 +133,16 @@ public class DynamicConfigurationServiceNameMapping 
implements ServiceNameMappin
         DynamicConfiguration dynamicConfiguration = 
DynamicConfiguration.getDynamicConfiguration();
         String newConfigContent = appName;
         do {
-            String oldConfigContent = dynamicConfiguration.getConfig(key, 
group);
-            String casMd5 = "";
+            ConfigItem configItem = dynamicConfiguration.getConfigItem(key, 
group);
+            String oldConfigContent = configItem.getContent();
             if (StringUtils.isNotEmpty(oldConfigContent)) {
-                casMd5 = MD5Utils.getMd5(oldConfigContent);
-                boolean contains = StringUtils.isContains(oldConfigContent, 
appName);
+                boolean contains = 
StringUtils.isContains(configItem.getContent(), appName);
                 if (contains) {
                     return true;
                 }
-                newConfigContent = oldConfigContent.length() > 0 ? 
oldConfigContent + COMMA_SEPARATOR + appName : appName;
+                newConfigContent = oldConfigContent + COMMA_SEPARATOR + 
appName;
             }
-            result = dynamicConfiguration.publishConfigCas(key, group, 
newConfigContent, casMd5);
+            result = dynamicConfiguration.publishConfigCas(key, group, 
newConfigContent, configItem.getStat());
         } while (!result && currentRetryTimes++ <= PUBLISH_CONFIG_RETRY_TIMES);
 
         return result;
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
index 775d291..3b960e2 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.remoting.zookeeper;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -60,8 +61,12 @@ public interface ZookeeperClient {
 
     void create(String path, String content, boolean ephemeral);
 
+    void createOrUpdate(String path, String content, boolean ephemeral, Object 
stat);
+
     String getContent(String path);
 
+    ConfigItem getConfigItem(String path);
+
     boolean checkExists(String path);
 
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
index 625f001..a5d45e1 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.remoting.zookeeper.curator;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.remoting.zookeeper.ChildListener;
@@ -39,6 +40,7 @@ import org.apache.zookeeper.KeeperException.NoNodeException;
 import org.apache.zookeeper.KeeperException.NodeExistsException;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.data.Stat;
 
 import java.nio.charset.Charset;
 import java.util.List;
@@ -49,7 +51,8 @@ import java.util.concurrent.TimeUnit;
 
 import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
 
-public class CuratorZookeeperClient extends 
AbstractZookeeperClient<CuratorZookeeperClient.CuratorWatcherImpl, 
CuratorZookeeperClient.CuratorWatcherImpl> {
+public class CuratorZookeeperClient
+        extends 
AbstractZookeeperClient<CuratorZookeeperClient.CuratorWatcherImpl, 
CuratorZookeeperClient.CuratorWatcherImpl> {
 
     protected static final Logger logger = 
LoggerFactory.getLogger(CuratorZookeeperClient.class);
     private static final String ZK_SESSION_EXPIRE_KEY = "zk.session.expire";
@@ -145,6 +148,47 @@ public class CuratorZookeeperClient extends 
AbstractZookeeperClient<CuratorZooke
     }
 
     @Override
+    protected void update(String path, String data, Object stat) {
+        byte[] dataBytes = data.getBytes(CHARSET);
+        try {
+            if (null == stat || !(stat instanceof Stat)) {
+                throw new IllegalArgumentException("unable to get the version 
information of zookeeper data");
+            }
+            client.setData().withVersion(((Stat) 
stat).getVersion()).forPath(path, dataBytes);
+        } catch (NoNodeException e) {
+            logger.warn("ZNode " + path + "does not exists.", e);
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    protected void createOrUpdatePersistent(String path, String data, Object 
stat) {
+        try {
+            if (checkExists(path)) {
+                update(path, data, stat);
+            } else {
+                createPersistent(path, data);
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    protected void createOrUpdateEphemeral(String path, String data, Object 
stat) {
+        try {
+            if (checkExists(path)) {
+                update(path, data, stat);
+            } else {
+                createEphemeral(path, data);
+            }
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    @Override
     protected void deletePath(String path) {
         try {
             client.delete().deletingChildrenIfNeeded().forPath(path);
@@ -195,6 +239,22 @@ public class CuratorZookeeperClient extends 
AbstractZookeeperClient<CuratorZooke
     }
 
     @Override
+    public ConfigItem doGetConfigItem(String path) {
+        String content = null;
+        Stat stat = null;
+        try {
+            stat = new Stat();
+            byte[] dataBytes = 
client.getData().storingStatIn(stat).forPath(path);
+            content = (dataBytes == null || dataBytes.length == 0) ? null : 
new String(dataBytes, CHARSET);
+        } catch (NoNodeException e) {
+            // ignore NoNode Exception.
+        } catch (Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+        return new ConfigItem(content, stat);
+    }
+
+    @Override
     public void doClose() {
         client.close();
     }
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
index 42fe5c9..6121969 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperClient.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.remoting.zookeeper.support;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.configcenter.ConfigItem;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.ConcurrentHashSet;
@@ -43,13 +44,15 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
 
     private final Set<StateListener> stateListeners = new 
CopyOnWriteArraySet<StateListener>();
 
-    private final ConcurrentMap<String, ConcurrentMap<ChildListener, 
TargetChildListener>> childListeners = new ConcurrentHashMap<String, 
ConcurrentMap<ChildListener, TargetChildListener>>();
+    private final ConcurrentMap<String, ConcurrentMap<ChildListener, 
TargetChildListener>> childListeners =
+            new ConcurrentHashMap<String, ConcurrentMap<ChildListener, 
TargetChildListener>>();
 
-    private final ConcurrentMap<String, ConcurrentMap<DataListener, 
TargetDataListener>> listeners = new ConcurrentHashMap<String, 
ConcurrentMap<DataListener, TargetDataListener>>();
+    private final ConcurrentMap<String, ConcurrentMap<DataListener, 
TargetDataListener>> listeners =
+            new ConcurrentHashMap<String, ConcurrentMap<DataListener, 
TargetDataListener>>();
 
     private volatile boolean closed = false;
 
-    private final Set<String>  persistentExistNodePath = new 
ConcurrentHashSet<>();
+    private final Set<String> persistentExistNodePath = new 
ConcurrentHashSet<>();
 
     public AbstractZookeeperClient(URL url) {
         this.url = url;
@@ -61,7 +64,7 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
     }
 
     @Override
-    public void delete(String path){
+    public void delete(String path) {
         //never mind if ephemeral
         persistentExistNodePath.remove(path);
         deletePath(path);
@@ -71,7 +74,7 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
     @Override
     public void create(String path, boolean ephemeral) {
         if (!ephemeral) {
-            if(persistentExistNodePath.contains(path)){
+            if (persistentExistNodePath.contains(path)) {
                 return;
             }
             if (checkExists(path)) {
@@ -125,11 +128,11 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
     }
 
     @Override
-    public void removeDataListener(String path, DataListener listener ){
+    public void removeDataListener(String path, DataListener listener) {
         ConcurrentMap<DataListener, TargetDataListener> dataListenerMap = 
listeners.get(path);
         if (dataListenerMap != null) {
             TargetDataListener targetListener = 
dataListenerMap.remove(listener);
-            if(targetListener != null){
+            if (targetListener != null) {
                 removeTargetDataListener(path, targetListener);
             }
         }
@@ -182,6 +185,19 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
     }
 
     @Override
+    public void createOrUpdate(String path, String content, boolean ephemeral, 
Object stat) {
+        int i = path.lastIndexOf('/');
+        if (i > 0) {
+            create(path.substring(0, i), false);
+        }
+        if (ephemeral) {
+            createOrUpdateEphemeral(path, content, stat);
+        } else {
+            createOrUpdatePersistent(path, content, stat);
+        }
+    }
+
+    @Override
     public String getContent(String path) {
         if (!checkExists(path)) {
             return null;
@@ -189,6 +205,14 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
         return doGetContent(path);
     }
 
+    @Override
+    public ConfigItem getConfigItem(String path) {
+        if (!checkExists(path)) {
+            return new ConfigItem();
+        }
+        return doGetConfigItem(path);
+    }
+
     protected abstract void doClose();
 
     protected abstract void createPersistent(String path);
@@ -199,6 +223,13 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
 
     protected abstract void createEphemeral(String path, String data);
 
+    protected abstract void update(String path, String data, Object stat);
+
+    protected abstract void createOrUpdatePersistent(String path, String data, 
Object stat);
+
+    protected abstract void createOrUpdateEphemeral(String path, String data, 
Object stat);
+
+    @Override
     public abstract boolean checkExists(String path);
 
     protected abstract TargetChildListener createTargetChildListener(String 
path, ChildListener listener);
@@ -217,8 +248,11 @@ public abstract class 
AbstractZookeeperClient<TargetDataListener, TargetChildLis
 
     protected abstract String doGetContent(String path);
 
+    protected abstract ConfigItem doGetConfigItem(String path);
+
     /**
      * we invoke the zookeeper client to delete the node
+     *
      * @param path the node path
      */
     protected abstract void deletePath(String path);

Reply via email to