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

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


The following commit(s) were added to refs/heads/3.1 by this push:
     new 213944c03e Add code that shows error code 2-2, 1-9, 5-1 with code 
optimization. (#10452)
213944c03e is described below

commit 213944c03ecfd27b7a92257b92acde503cc3c628
Author: Andy Cheung <[email protected]>
AuthorDate: Sun Aug 14 10:40:44 2022 +0800

    Add code that shows error code 2-2, 1-9, 5-1 with code optimization. 
(#10452)
    
    * Optimize javadoc in Protocol.
    
    * Optimize javadoc in Protocol.
    
    * Add error 2-2 in ReferenceConfig.
    
    * Add error code 5-1 in CuratorZookeeperClient and Curator5ZookeeperClient.
    
    * Optimize Javadoc of ZookeeperClient.
    
    * Forbids the instantiation and optimize comments of UrlUtils.
    
    * Fix typo in FrameworkExecutorRepository.
    
    * Throw created illegalStateException instead of throwing a new one.
    
    * Add error code 1-9 constructor of AbstractRegistry.
    
    * Optimize comments and modifiers.
    
    * Optimize appearance of error code 1-9.
---
 .../manager/FrameworkExecutorRepository.java       |  2 +-
 .../org/apache/dubbo/common/utils/UrlUtils.java    | 48 +++++++++++++++----
 .../org/apache/dubbo/config/ReferenceConfig.java   |  8 +++-
 .../ServiceInstanceHostPortCustomizer.java         |  2 +-
 .../dubbo/registry/support/AbstractRegistry.java   | 54 ++++++++++++++++++----
 .../support/CacheableFailbackRegistry.java         | 38 +++++++++++++--
 .../registry/CacheableFailbackRegistryTest.java    | 14 +++---
 .../dubbo/remoting/zookeeper/ZookeeperClient.java  | 20 ++++++--
 .../curator5/Curator5ZookeeperClient.java          | 14 ++++--
 .../zookeeper/curator/CuratorZookeeperClient.java  | 14 ++++--
 .../main/java/org/apache/dubbo/rpc/Protocol.java   | 30 +++++++++++-
 11 files changed, 197 insertions(+), 47 deletions(-)

diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepository.java
 
b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepository.java
index df4e10eb2a..d630ee473e 100644
--- 
a/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepository.java
+++ 
b/dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/manager/FrameworkExecutorRepository.java
@@ -91,7 +91,7 @@ public class FrameworkExecutorRepository implements 
Disposable {
 
     /**
      * Returns a scheduler from the scheduler list, call this method whenever 
you need a scheduler for a cron job.
-     * If your cron cannot burden the possible schedule delay caused by 
sharing the same scheduler, please consider define a dedicate one.
+     * If your cron cannot burden the possible schedule delay caused by 
sharing the same scheduler, please consider define a dedicated one.
      *
      * @return ScheduledExecutorService
      */
diff --git 
a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java 
b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
index f0246c0192..11b1e3faa2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java
@@ -63,10 +63,17 @@ import static 
org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGIST
 
 public class UrlUtils {
 
+    /**
+     * Forbids the instantiation.
+     */
+    private UrlUtils() {
+        throw new UnsupportedOperationException("No instance of 'UrlUtils' for 
you! ");
+    }
+
     /**
      * in the url string,mark the param begin
      */
-    private final static String URL_PARAM_STARTING_SYMBOL = "?";
+    private static final String URL_PARAM_STARTING_SYMBOL = "?";
 
     public static URL parseURL(String address, Map<String, String> defaults) {
         if (StringUtils.isEmpty(address)) {
@@ -212,7 +219,8 @@ public class UrlUtils {
     }
 
     public static Map<String, String> convertSubscribe(Map<String, String> 
subscribe) {
-        Map<String, String> newSubscribe = new HashMap<String, String>();
+        Map<String, String> newSubscribe = new HashMap<>();
+
         for (Map.Entry<String, String> entry : subscribe.entrySet()) {
             String serviceName = entry.getKey();
             String serviceQuery = entry.getValue();
@@ -234,11 +242,13 @@ public class UrlUtils {
                 newSubscribe.put(serviceName, serviceQuery);
             }
         }
+
         return newSubscribe;
     }
 
     public static Map<String, Map<String, String>> revertRegister(Map<String, 
Map<String, String>> register) {
-        Map<String, Map<String, String>> newRegister = new HashMap<String, 
Map<String, String>>();
+        Map<String, Map<String, String>> newRegister = new HashMap<>();
+
         for (Map.Entry<String, Map<String, String>> entry : 
register.entrySet()) {
             String serviceName = entry.getKey();
             Map<String, String> serviceUrls = entry.getValue();
@@ -265,11 +275,14 @@ public class UrlUtils {
                 newRegister.put(serviceName, serviceUrls);
             }
         }
+
         return newRegister;
     }
 
     public static Map<String, String> revertSubscribe(Map<String, String> 
subscribe) {
-        Map<String, String> newSubscribe = new HashMap<String, String>();
+
+        Map<String, String> newSubscribe = new HashMap<>();
+
         for (Map.Entry<String, String> entry : subscribe.entrySet()) {
             String serviceName = entry.getKey();
             String serviceQuery = entry.getValue();
@@ -385,32 +398,47 @@ public class UrlUtils {
     public static boolean isMatch(URL consumerUrl, URL providerUrl) {
         String consumerInterface = consumerUrl.getServiceInterface();
         String providerInterface = providerUrl.getServiceInterface();
-        //FIXME accept providerUrl with '*' as interface name, after carefully 
thought about all possible scenarios I think it's ok to add this condition.
+
+        // FIXME accept providerUrl with '*' as interface name, after 
carefully thought about all possible scenarios I think it's ok to add this 
condition.
+
+        // Return false if the consumer interface is not equals the provider 
interface,
+        // except one of the interface configurations is equals '*' (i.e. any 
value).
         if (!(ANY_VALUE.equals(consumerInterface)
             || ANY_VALUE.equals(providerInterface)
             || StringUtils.isEquals(consumerInterface, providerInterface))) {
             return false;
         }
 
-        if (!isMatchCategory(providerUrl.getCategory(DEFAULT_CATEGORY),
-            consumerUrl.getCategory(DEFAULT_CATEGORY))) {
+        // If the category of provider URL does not match the category of 
consumer URL.
+        // Usually, the provider URL's category is empty, and the default 
category ('providers') is present.
+        // Hence, the category of the provider URL is 'providers'.
+        // Through observing of the Zookeeper registry, I found that the 
category of the consumer URL is 'consumers'.
+        if (!isMatchCategory(providerUrl.getCategory(DEFAULT_CATEGORY), 
consumerUrl.getCategory(DEFAULT_CATEGORY))) {
             return false;
         }
+
+        // If the provider is not enabled, return false.
         if (!providerUrl.getParameter(ENABLED_KEY, true)
             && !ANY_VALUE.equals(consumerUrl.getParameter(ENABLED_KEY))) {
             return false;
         }
 
+        // Obtain consumer's group, version and classifier.
         String consumerGroup = consumerUrl.getGroup();
         String consumerVersion = consumerUrl.getVersion();
         String consumerClassifier = consumerUrl.getParameter(CLASSIFIER_KEY, 
ANY_VALUE);
 
+        // Obtain provider's group, version and classifier.
         String providerGroup = providerUrl.getGroup();
         String providerVersion = providerUrl.getVersion();
         String providerClassifier = providerUrl.getParameter(CLASSIFIER_KEY, 
ANY_VALUE);
-        return (ANY_VALUE.equals(consumerGroup) || 
StringUtils.isEquals(consumerGroup, providerGroup) || 
StringUtils.isContains(consumerGroup, providerGroup))
-            && (ANY_VALUE.equals(consumerVersion) || 
StringUtils.isEquals(consumerVersion, providerVersion))
-            && (consumerClassifier == null || 
ANY_VALUE.equals(consumerClassifier) || 
StringUtils.isEquals(consumerClassifier, providerClassifier));
+
+        // If Group, Version, Classifier all matches, return true.
+        boolean groupMatches = ANY_VALUE.equals(consumerGroup) || 
StringUtils.isEquals(consumerGroup, providerGroup) || 
StringUtils.isContains(consumerGroup, providerGroup);
+        boolean versionMatches = ANY_VALUE.equals(consumerVersion) || 
StringUtils.isEquals(consumerVersion, providerVersion);
+        boolean classifierMatches = consumerClassifier == null || 
ANY_VALUE.equals(consumerClassifier) || 
StringUtils.isEquals(consumerClassifier, providerClassifier);
+
+        return groupMatches && versionMatches && classifierMatches;
     }
 
     public static boolean isMatchGlobPattern(String pattern, String value, URL 
param) {
diff --git 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
index 19d278329f..8dd76c073a 100644
--- 
a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
+++ 
b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java
@@ -638,7 +638,9 @@ public class ReferenceConfig<T> extends 
ReferenceConfigBase<T> {
 
     private void checkInvokerAvailable() throws IllegalStateException {
         if (shouldCheck() && !invoker.isAvailable()) {
-            throw new IllegalStateException("Failed to check the status of the 
service "
+            // 2-2 - No provider available.
+
+            IllegalStateException illegalStateException = new 
IllegalStateException("Failed to check the status of the service "
                     + interfaceName
                     + ". No provider available for the service "
                     + (group == null ? "" : group + "/")
@@ -648,6 +650,10 @@ public class ReferenceConfig<T> extends 
ReferenceConfigBase<T> {
                     + invoker.getUrl()
                     + " to the consumer "
                     + NetUtils.getLocalHost() + " use dubbo version " + 
Version.getVersion());
+
+            logger.error("2-2", "provider not started", "", "No provider 
available.", illegalStateException);
+
+            throw illegalStateException;
         }
     }
 
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizer.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizer.java
index 3b8c193c3f..9e5a20742a 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizer.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/ServiceInstanceHostPortCustomizer.java
@@ -75,7 +75,7 @@ public class ServiceInstanceHostPortCustomizer implements 
ServiceInstanceCustomi
                     // 4-2 - Can't find an instance URL using the default 
preferredProtocol.
 
                     logger.warn("4-2", "typo in preferred protocol", "",
-                        "Can't find an instance URL  using the default 
preferredProtocol \"" + preferredProtocol + "\", " +
+                        "Can't find an instance URL using the default 
preferredProtocol \"" + preferredProtocol + "\", " +
                         "falling back to the strategy that pick the first 
found protocol. " +
                         "Please try modifying the config of 
dubbo.application.protocol");
 
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
index 170a684f78..b9e83baf79 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java
@@ -69,7 +69,10 @@ import static 
org.apache.dubbo.registry.Constants.REGISTRY_FILESAVE_SYNC_KEY;
 import static org.apache.dubbo.registry.Constants.USER_HOME;
 
 /**
- * AbstractRegistry. (SPI, Prototype, ThreadSafe)
+ * <p>
+ * Provides a fail-safe registry service backed by cache file. The 
consumer/provider can still find each other when registry center crashed.
+ *
+ * (SPI, Prototype, ThreadSafe)
  */
 public abstract class AbstractRegistry implements Registry {
 
@@ -101,7 +104,9 @@ public abstract class AbstractRegistry implements Registry {
     protected RegistryManager registryManager;
     protected ApplicationModel applicationModel;
 
-    public AbstractRegistry(URL url) {
+    private static final String CAUSE_MULTI_DUBBO_USING_SAME_FILE = "multiple 
Dubbo instance are using the same file";
+
+    protected AbstractRegistry(URL url) {
         setUrl(url);
         registryManager = 
url.getOrDefaultApplicationModel().getBeanFactory().getBean(RegistryManager.class);
         localCacheEnabled = 
url.getParameter(REGISTRY_LOCAL_FILE_CACHE_ENABLED, true);
@@ -110,19 +115,36 @@ public abstract class AbstractRegistry implements 
Registry {
         if (localCacheEnabled) {
             // Start file save timer
             syncSaveFile = url.getParameter(REGISTRY_FILESAVE_SYNC_KEY, false);
+
             String defaultFilename = System.getProperty(USER_HOME) + 
DUBBO_REGISTRY + url.getApplication() +
                 "-" + url.getAddress().replaceAll(":", "-") + CACHE;
+
             String filename = url.getParameter(FILE_KEY, defaultFilename);
             File file = null;
+
             if (ConfigUtils.isNotEmpty(filename)) {
                 file = new File(filename);
                 if (!file.exists() && file.getParentFile() != null && 
!file.getParentFile().exists()) {
                     if (!file.getParentFile().mkdirs()) {
-                        throw new IllegalArgumentException("Invalid registry 
cache file " + file + ", cause: Failed to create directory " + 
file.getParentFile() + "!");
+
+                        IllegalArgumentException illegalArgumentException = 
new IllegalArgumentException(
+                            "Invalid registry cache file " + file + ", cause: 
Failed to create directory " + file.getParentFile() + "!");
+
+                        if (logger != null) {
+                            // 1-9 failed to read / save registry cache file.
+
+                            logger.error("1-9", "cache directory inaccessible",
+                                "Try adjusting permission of the directory.",
+                                "failed to create directory", 
illegalArgumentException);
+                        }
+
+                        throw illegalArgumentException;
                     }
                 }
             }
+
             this.file = file;
+
             // When starting the subscription center,
             // we need to read the local cache file for future Registry fault 
tolerance processing.
             loadProperties();
@@ -189,13 +211,22 @@ public abstract class AbstractRegistry implements 
Registry {
             if (!lockfile.exists()) {
                 lockfile.createNewFile();
             }
+
             try (RandomAccessFile raf = new RandomAccessFile(lockfile, "rw");
                  FileChannel channel = raf.getChannel()) {
                 FileLock lock = channel.tryLock();
                 if (lock == null) {
-                    throw new IOException("Can not lock the registry cache 
file " + file.getAbsolutePath() + ", " +
+
+                    IOException ioException = new IOException("Can not lock 
the registry cache file " + file.getAbsolutePath() + ", " +
                         "ignore and retry later, maybe multi java process use 
the file, please config: dubbo.registry.file=xxx.properties");
+
+                    // 1-9 failed to read / save registry cache file.
+                    logger.warn("1-9", CAUSE_MULTI_DUBBO_USING_SAME_FILE, "",
+                        "Adjust dubbo.registry.file.", ioException);
+
+                    throw ioException;
                 }
+
                 // Save
                 try {
                     if (!file.exists()) {
@@ -226,26 +257,30 @@ public abstract class AbstractRegistry implements 
Registry {
             }
         } catch (Throwable e) {
             savePropertiesRetryTimes.incrementAndGet();
+
             if (savePropertiesRetryTimes.get() >= 
MAX_RETRY_TIMES_SAVE_PROPERTIES) {
                 if (e instanceof OverlappingFileLockException) {
                     // fix #9341, ignore OverlappingFileLockException
                     logger.info("Failed to save registry cache file for file 
overlapping lock exception, file name " + file.getName());
                 } else {
                     // 1-9 failed to read / save registry cache file.
-                    logger.warn("1-9", "multiple Dubbo instance are using the 
same file", "",
+                    logger.warn("1-9", CAUSE_MULTI_DUBBO_USING_SAME_FILE, "",
                         "Failed to save registry cache file after retrying " + 
MAX_RETRY_TIMES_SAVE_PROPERTIES + " times, cause: " + e.getMessage(), e);
                 }
+
                 savePropertiesRetryTimes.set(0);
                 return;
             }
+
             if (version < lastCacheChanged.get()) {
                 savePropertiesRetryTimes.set(0);
                 return;
             } else {
                 registryCacheExecutor.execute(() -> 
doSaveProperties(lastCacheChanged.incrementAndGet()));
             }
+
             if (!(e instanceof OverlappingFileLockException)) {
-                logger.warn("1-9", "multiple Dubbo instance are using the same 
file",
+                logger.warn("1-9", CAUSE_MULTI_DUBBO_USING_SAME_FILE,
                     "However, the retrying count limit is not exceeded. Dubbo 
will still try.",
                     "Failed to save registry cache file, will retry, cause: " 
+ e.getMessage(), e);
             }
@@ -271,13 +306,13 @@ public abstract class AbstractRegistry implements 
Registry {
             }
         } catch (IOException e) {
             // 1-9 failed to read / save registry cache file.
-            logger.warn("1-9", "multiple Dubbo instance are using the same 
file", "",
+            logger.warn("1-9", CAUSE_MULTI_DUBBO_USING_SAME_FILE, "",
                 e.getMessage(), e);
 
         } catch (Throwable e) {
             // 1-9 failed to read / save registry cache file.
 
-            logger.warn("1-9", "multiple Dubbo instance are using the same 
file", "",
+            logger.warn("1-9", CAUSE_MULTI_DUBBO_USING_SAME_FILE, "",
                 "Failed to load registry cache file " + file, e);
         }
     }
@@ -442,7 +477,7 @@ public abstract class AbstractRegistry implements Registry {
     }
 
     /**
-     * Notify changes from the Provider side.
+     * Notify changes from the provider side.
      *
      * @param url      consumer side url
      * @param listener listener
@@ -481,6 +516,7 @@ public abstract class AbstractRegistry implements Registry {
             List<URL> categoryList = entry.getValue();
             categoryNotified.put(category, categoryList);
             listener.notify(categoryList);
+
             // We will update our cache file after each notification.
             // When our Registry has a subscribed failure due to network 
jitter, we can return at least the existing cache URL.
             if (localCacheEnabled) {
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
index 5a9fc8a439..b1cccf267e 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/CacheableFailbackRegistry.java
@@ -62,7 +62,14 @@ import static 
org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_P
 import static 
org.apache.dubbo.common.constants.RegistryConstants.PROVIDERS_CATEGORY;
 
 /**
- * Useful for registries who's sdk returns raw string as provider instance, 
for example, zookeeper and etcd.
+ * <p>
+ * Based on FailbackRegistry, it adds a URLAddress and URLParam cache to save 
RAM space.
+ *
+ * <p>
+ * It's useful for registries whose sdk returns raw string as provider 
instance. For example, Zookeeper and etcd.
+ *
+ * @see org.apache.dubbo.registry.support.FailbackRegistry
+ * @see org.apache.dubbo.registry.support.AbstractRegistry
  */
 public abstract class CacheableFailbackRegistry extends FailbackRegistry {
     private static final ErrorTypeAwareLogger logger = 
LoggerFactory.getErrorTypeAwareLogger(CacheableFailbackRegistry.class);
@@ -71,16 +78,18 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
 
     protected Map<String, URLAddress> stringAddress = new 
ConcurrentHashMap<>();
     protected Map<String, URLParam> stringParam = new ConcurrentHashMap<>();
+
     private ScheduledExecutorService cacheRemovalScheduler;
     private int cacheRemovalTaskIntervalInMillis;
     private int cacheClearWaitingThresholdInMillis;
+
     private Map<ServiceAddressURL, Long> waitForRemove = new 
ConcurrentHashMap<>();
     private Semaphore semaphore = new Semaphore(1);
 
     private final Map<String, String> extraParameters;
     protected final Map<URL, Map<String, ServiceAddressURL>> stringUrls = new 
ConcurrentHashMap<>();
 
-    public CacheableFailbackRegistry(URL url) {
+    protected CacheableFailbackRegistry(URL url) {
         super(url);
         extraParameters = new HashMap<>(8);
         extraParameters.put(CHECK_KEY, String.valueOf(false));
@@ -114,7 +123,7 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
     protected void evictURLCache(URL url) {
         Map<String, ServiceAddressURL> oldURLs = stringUrls.remove(url);
         try {
-            if (oldURLs != null && oldURLs.size() > 0) {
+            if (oldURLs != null && !oldURLs.isEmpty()) {
                 logger.info("Evicting urls for service " + url.getServiceKey() 
+ ", size " + oldURLs.size());
                 Long currentTimestamp = System.currentTimeMillis();
                 for (Map.Entry<String, ServiceAddressURL> entry : 
oldURLs.entrySet()) {
@@ -127,8 +136,18 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
                 }
             }
         } catch (Exception e) {
+            // It seems that the most possible statement that causes exception 
is the 'schedule()' method.
+
+            // The executor that 
FrameworkExecutorRepository.nextScheduledExecutor() method returns
+            // is made by Executors.newSingleThreadScheduledExecutor().
+
+            // After observing the code of 
ScheduledThreadPoolExecutor.delayedExecute,
+            // it seems that it only throws RejectedExecutionException when 
the thread pool is shutdown.
+
+            // When? FrameworkExecutorRepository gets destroyed.
+
             // 1-3: URL evicting failed.
-            logger.warn("1-3", "", "",
+            logger.warn("1-3", "thread pool getting destroyed", "",
                 "Failed to evict url for " + url.getServiceKey(), e);
         }
     }
@@ -216,11 +235,13 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
 
     protected ServiceAddressURL createURL(String rawProvider, URL consumerURL, 
Map<String, String> extraParameters) {
         boolean encoded = true;
+
         // use encoded value directly to avoid URLDecoder.decode allocation.
         int paramStartIdx = rawProvider.indexOf(ENCODED_QUESTION_MARK);
         if (paramStartIdx == -1) {// if ENCODED_QUESTION_MARK does not show, 
mark as not encoded.
             encoded = false;
         }
+
         String[] parts = URLStrParser.parseRawURLToArrays(rawProvider, 
paramStartIdx);
         if (parts.length <= 1) {
             // 1-5 Received URL without any parameters.
@@ -232,7 +253,10 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
 
         String rawAddress = parts[0];
         String rawParams = parts[1];
+
+        // Workaround for 'effectively final': duplicate the encoded variable.
         boolean isEncoded = encoded;
+
         URLAddress address = stringAddress.computeIfAbsent(rawAddress, k -> 
URLAddress.parse(k, getDefaultURLProtocol(), isEncoded));
         address.setTimestamp(System.currentTimeMillis());
 
@@ -240,9 +264,11 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
         param.setTimestamp(System.currentTimeMillis());
 
         ServiceAddressURL cachedURL = createServiceURL(address, param, 
consumerURL);
+
         if (isMatch(consumerURL, cachedURL)) {
             return cachedURL;
         }
+
         return null;
     }
 
@@ -332,7 +358,9 @@ public abstract class CacheableFailbackRegistry extends 
FailbackRegistry {
 
     protected abstract boolean isMatch(URL subscribeUrl, URL providerUrl);
 
-
+    /**
+     * The cached URL removal task, which will be run on a scheduled thread 
pool. (It will be run after a delay.)
+     */
     private class RemovalTask implements Runnable {
         @Override
         public void run() {
diff --git 
a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
 
b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
index 0e52a74aa6..946e0eead1 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/CacheableFailbackRegistryTest.java
@@ -34,7 +34,7 @@ import static 
org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL
 import static 
org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class CacheableFailbackRegistryTest {
+class CacheableFailbackRegistryTest {
 
     static String service;
     static URL serviceUrl;
@@ -70,7 +70,7 @@ public class CacheableFailbackRegistryTest {
     }
 
     @Test
-    public void testFullURLCache() {
+    void testFullURLCache() {
         final AtomicReference<Integer> resCount = new AtomicReference<>(0);
         registry = new MockCacheableRegistryImpl(registryUrl);
         URL url = URLStrParser.parseEncodedStr(urlStr);
@@ -101,7 +101,7 @@ public class CacheableFailbackRegistryTest {
     }
 
     @Test
-    public void testURLAddressCache() {
+    void testURLAddressCache() {
         final AtomicReference<Integer> resCount = new AtomicReference<>(0);
         registry = new MockCacheableRegistryImpl(registryUrl);
         URL url = URLStrParser.parseEncodedStr(urlStr);
@@ -127,7 +127,7 @@ public class CacheableFailbackRegistryTest {
     }
 
     @Test
-    public void testURLParamCache() {
+    void testURLParamCache() {
         final AtomicReference<Integer> resCount = new AtomicReference<>(0);
         registry = new MockCacheableRegistryImpl(registryUrl);
         URL url = URLStrParser.parseEncodedStr(urlStr);
@@ -153,7 +153,7 @@ public class CacheableFailbackRegistryTest {
     }
 
     @Test
-    public void testRemove() {
+    void testRemove() {
         final AtomicReference<Integer> resCount = new AtomicReference<>(0);
         registry = new MockCacheableRegistryImpl(registryUrl);
         URL url = URLStrParser.parseEncodedStr(urlStr);
@@ -193,7 +193,7 @@ public class CacheableFailbackRegistryTest {
     }
 
     @Test
-    public void testEmptyProtection() {
+    void testEmptyProtection() {
         final AtomicReference<Integer> resCount = new AtomicReference<>(0);
         final AtomicReference<List<URL>> currentUrls = new AtomicReference<>();
         final List<URL> EMPTY_LIST = new ArrayList<>();
@@ -239,6 +239,4 @@ public class CacheableFailbackRegistryTest {
         assertEquals(EMPTY_LIST, currentUrls.get());
 
     }
-
-
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
index dfdc403690..bb001da671 100644
--- 
a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/zookeeper/ZookeeperClient.java
@@ -47,18 +47,28 @@ public interface ZookeeperClient {
     List<String> addChildListener(String path, ChildListener listener);
 
     /**
-     * @param path    directory. All child of path will be listened.
-     * @param listener
+     * Attach data listener to current Zookeeper client.
+     *
+     * @param path    directory. All children of path will be listened.
+     * @param listener The data listener object.
      */
     void addDataListener(String path, DataListener listener);
 
     /**
-     * @param path    directory. All child of path will be listened.
-     * @param listener
-     * @param executor another thread
+     * Attach data listener to current Zookeeper client. The listener will be 
executed using the given executor.
+     *
+     * @param path    directory. All children of path will be listened.
+     * @param listener The data listener object.
+     * @param executor the executor that will execute the listener.
      */
     void addDataListener(String path, DataListener listener, Executor 
executor);
 
+    /**
+     * Detach data listener.
+     *
+     * @param path    directory. All listener of children of the path will be 
detached.
+     * @param listener The data listener object.
+     */
     void removeDataListener(String path, DataListener listener);
 
     void removeChildListener(String path, ChildListener listener);
diff --git 
a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/main/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClient.java
 
b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/main/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClient.java
index 52c1d9f301..604f29d38a 100644
--- 
a/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/main/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClient.java
+++ 
b/dubbo-remoting/dubbo-remoting-zookeeper-curator5/src/main/java/org/apache/dubbo/remoting/zookeeper/curator5/Curator5ZookeeperClient.java
@@ -18,7 +18,7 @@ package org.apache.dubbo.remoting.zookeeper.curator5;
 
 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.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.remoting.zookeeper.AbstractZookeeperClient;
 import org.apache.dubbo.remoting.zookeeper.ChildListener;
@@ -59,7 +59,7 @@ import static 
org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
 
 public class Curator5ZookeeperClient extends 
AbstractZookeeperClient<Curator5ZookeeperClient.NodeCacheListenerImpl, 
Curator5ZookeeperClient.CuratorWatcherImpl> {
 
-    protected static final Logger logger = 
LoggerFactory.getLogger(Curator5ZookeeperClient.class);
+    protected static final ErrorTypeAwareLogger logger = 
LoggerFactory.getErrorTypeAwareLogger(Curator5ZookeeperClient.class);
 
     private static final Charset CHARSET = StandardCharsets.UTF_8;
     private final CuratorFramework client;
@@ -94,9 +94,17 @@ public class Curator5ZookeeperClient extends 
AbstractZookeeperClient<Curator5Zoo
             client.getConnectionStateListenable().addListener(new 
CuratorConnectionStateListener(url));
             client.start();
             boolean connected = client.blockUntilConnected(timeout, 
TimeUnit.MILLISECONDS);
+
             if (!connected) {
-                throw new IllegalStateException("zookeeper not connected");
+                IllegalStateException illegalStateException = new 
IllegalStateException("zookeeper not connected");
+
+                // 5-1 Failed to connect to configuration center.
+                logger.error("5-1", "Zookeeper server offline", "",
+                    "Failed to connect with zookeeper", illegalStateException);
+
+                throw illegalStateException;
             }
+
         } catch (Exception e) {
             throw new IllegalStateException(e.getMessage(), e);
         }
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 13a0018178..30cc4d574a 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
@@ -18,7 +18,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.ErrorTypeAwareLogger;
 import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.NamedThreadFactory;
 import org.apache.dubbo.common.utils.StringUtils;
@@ -63,7 +63,7 @@ import static 
org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
 
 public class CuratorZookeeperClient extends 
AbstractZookeeperClient<CuratorZookeeperClient.NodeCacheListenerImpl, 
CuratorZookeeperClient.CuratorWatcherImpl> {
 
-    protected static final Logger logger = 
LoggerFactory.getLogger(CuratorZookeeperClient.class);
+    protected static final ErrorTypeAwareLogger logger = 
LoggerFactory.getErrorTypeAwareLogger(CuratorZookeeperClient.class);
 
     private static final Charset CHARSET = StandardCharsets.UTF_8;
     private final CuratorFramework client;
@@ -97,10 +97,18 @@ public class CuratorZookeeperClient extends 
AbstractZookeeperClient<CuratorZooke
             client = builder.build();
             client.getConnectionStateListenable().addListener(new 
CuratorConnectionStateListener(url));
             client.start();
+
             boolean connected = client.blockUntilConnected(timeout, 
TimeUnit.MILLISECONDS);
             if (!connected) {
-                throw new IllegalStateException("zookeeper not connected");
+                IllegalStateException illegalStateException = new 
IllegalStateException("zookeeper not connected");
+
+                // 5-1 Failed to connect to configuration center.
+                logger.error("5-1", "Zookeeper server offline", "",
+                    "Failed to connect with zookeeper", illegalStateException);
+
+                throw illegalStateException;
             }
+
             CuratorWatcherImpl.closed = false;
         } catch (Exception e) {
             close();
diff --git 
a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Protocol.java 
b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Protocol.java
index 838801dbfc..0bbc24f34c 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Protocol.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Protocol.java
@@ -25,7 +25,35 @@ import java.util.Collections;
 import java.util.List;
 
 /**
- * Protocol. (API/SPI, Singleton, ThreadSafe)
+ * RPC Protocol extension interface, which encapsulates the details of remote 
invocation. <br /><br />
+ *
+ * <p>Conventions:
+ *
+ * <li>
+ *     When user invokes the 'invoke()' method in object that the method 
'refer()' returns,
+ *     the protocol needs to execute the 'invoke()' method of Invoker object 
that received by 'export()' method,
+ *     which should have the same URL.
+ * </li>
+ *
+ * <li>
+ *     Invoker that returned by 'refer()' is implemented by the protocol. The 
remote invocation request should be sent by that Invoker.
+ * </li>
+ *
+ * <li>
+ *     The invoker that 'export()' receives will be implemented by framework. 
Protocol implementation should not care with that.
+ * </li>
+ *
+ * <p>Attentions:
+ *
+ * <li>
+ *     The Protocol implementation does not care the transparent proxy. The 
invoker will be converted to business interface by other layer.
+ * </li>
+ *
+ * <li>
+ *     The protocol doesn't need to be backed by TCP connection. It can also 
be backed by file sharing or inter-process communication.
+ * </li>
+ *
+ * (API/SPI, Singleton, ThreadSafe)
  */
 @SPI(value = "dubbo", scope = ExtensionScope.FRAMEWORK)
 public interface Protocol {

Reply via email to