diff --git a/.gitattributes b/.gitattributes
index bb5d205725..c8c7a66c9b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,20 @@
-# Git will understand that all files specified are not text,
-# and it should not try to change them.
-# This will prevent file formatting (such as `crlf` endings to `lf` endings) while commit.
-* -text
\ No newline at end of file
+# 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.
+#
+
+# Auto detect text files and perform LF normalization
+* text=auto
+
+*.java text eol=lf
\ No newline at end of file
diff --git a/.github/workflows/build-and-test-3.yml b/.github/workflows/build-and-test-3.yml
index 9225474848..a7a3f666f0 100644
--- a/.github/workflows/build-and-test-3.yml
+++ b/.github/workflows/build-and-test-3.yml
@@ -39,7 +39,25 @@ jobs:
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
- ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean source:jar install -Pjacoco,rat,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+ ./mvnw --batch-mode -U -e --no-transfer-progress clean source:jar install -Pjacoco,rat,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
+ - name: "Pack rat file if failure"
+ if: failure()
+ run: 7z a ${{ github.workspace }}/rat.zip *rat.txt -r
+ - name: "Upload rat file if failure"
+ if: failure()
+ uses: actions/upload-artifact@v2
+ with:
+ name: "rat-file"
+ path: ${{ github.workspace }}/rat.zip
+ - name: "Pack checkstyle file if failure"
+ if: failure()
+ run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
+ - name: "Upload checkstyle file if failure"
+ if: failure()
+ uses: actions/upload-artifact@v2
+ with:
+ name: "checkstyle-file"
+ path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
@@ -72,22 +90,13 @@ jobs:
- name: "Test with Maven with Integration Tests"
timeout-minutes: 40
if: ${{ startsWith( matrix.os, 'ubuntu') }}
- run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true
+ run: ./mvnw --batch-mode -U -e --no-transfer-progress clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true
- name: "Test with Maven without Integration Tests"
env:
DISABLE_FILE_SYSTEM_TEST: true
timeout-minutes: 50
if: ${{ startsWith( matrix.os, 'windows') }}
- run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"rat.skip=false" -D"maven.javadoc.skip=true"
- - name: "Pack rat file if failure"
- if: failure()
- run: 7z a ${{ github.workspace }}/rat.zip *rat.txt -r
- - name: "Upload rat file if failure"
- if: failure()
- uses: actions/upload-artifact@v2
- with:
- name: "rat-file-${{ matrix.os }}-JDK${{ matrix.jdk }}"
- path: ${{ github.workspace }}/rat.zip
+ run: ./mvnw --batch-mode -U -e --no-transfer-progress clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v1
diff --git a/LICENSE b/LICENSE
index 89ce3a5434..4702175190 100644
--- a/LICENSE
+++ b/LICENSE
@@ -279,4 +279,4 @@ https://developers.google.com/protocol-buffers/ and is licensed under the follow
Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This
- support library is itself covered by the above license.
\ No newline at end of file
+ support library is itself covered by the above license.
diff --git a/NOTICE b/NOTICE
index 9e952c6dff..7ea7a3ba1c 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,14 +1,14 @@
-Apache Dubbo
-Copyright 2018-2021 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-This product contains code form the Netty Project:
-
-The Netty Project
-=================
-Please visit the Netty web site for more information:
- * http://netty.io/
-
-Copyright 2014 The Netty Project
+Apache Dubbo
+Copyright 2018-2021 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product contains code form the Netty Project:
+
+The Netty Project
+=================
+Please visit the Netty web site for more information:
+ * http://netty.io/
+
+Copyright 2014 The Netty Project
diff --git a/codestyle/checkstyle-suppressions.xml b/codestyle/checkstyle-suppressions.xml
index 1817cf762c..0b2fa10a02 100644
--- a/codestyle/checkstyle-suppressions.xml
+++ b/codestyle/checkstyle-suppressions.xml
@@ -4,5 +4,6 @@
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
\ No newline at end of file
diff --git a/codestyle/checkstyle.xml b/codestyle/checkstyle.xml
index 050fbede37..413cc720f6 100644
--- a/codestyle/checkstyle.xml
+++ b/codestyle/checkstyle.xml
@@ -12,6 +12,10 @@
+
+
+
+
diff --git a/codestyle/checkstyle_unix.xml b/codestyle/checkstyle_unix.xml
new file mode 100644
index 0000000000..589c7d7af6
--- /dev/null
+++ b/codestyle/checkstyle_unix.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/compiler/src/main/java/org/apache/dubbo/gen/dubbo/DubboGenerator.java b/compiler/src/main/java/org/apache/dubbo/gen/dubbo/DubboGenerator.java
index 1c35f0a3ef..1abf2a0064 100644
--- a/compiler/src/main/java/org/apache/dubbo/gen/dubbo/DubboGenerator.java
+++ b/compiler/src/main/java/org/apache/dubbo/gen/dubbo/DubboGenerator.java
@@ -39,4 +39,4 @@ public class DubboGenerator extends AbstractGenerator {
protected String getClassSuffix() {
return "Dubbo";
}
-}
\ No newline at end of file
+}
diff --git a/dubbo-build-tools/pom.xml b/dubbo-build-tools/pom.xml
index 966218d4da..a1a0c60df1 100644
--- a/dubbo-build-tools/pom.xml
+++ b/dubbo-build-tools/pom.xml
@@ -64,6 +64,7 @@
**/.classpath**/.project**/target/**
+ **/generated/****/*.logCONTRIBUTING.mdREADME.md
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/registry/AddressListener.java b/dubbo-cluster/src/main/java/org/apache/dubbo/registry/AddressListener.java
index 684cb64732..bd1947a4e9 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/registry/AddressListener.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/registry/AddressListener.java
@@ -38,4 +38,4 @@ public interface AddressListener {
}
-}
\ No newline at end of file
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
index 1fdadf8b21..04cc57339f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
@@ -1,59 +1,59 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-
-/**
- * Cluster. (SPI, Singleton, ThreadSafe)
- *
- * Cluster
- * Fault-Tolerant
- *
- */
-@SPI(Cluster.DEFAULT)
-public interface Cluster {
-
- String DEFAULT = "failover";
-
- /**
- * Merge the directory invokers to a virtual invoker.
- *
- * @param
- * @param directory
- * @return cluster invoker
- * @throws RpcException
- */
- @Adaptive
- Invoker join(Directory directory) throws RpcException;
-
- static Cluster getCluster(String name) {
- return getCluster(name, true);
- }
-
- static Cluster getCluster(String name, boolean wrap) {
- if (StringUtils.isEmpty(name)) {
- name = Cluster.DEFAULT;
- }
- return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap);
- }
-}
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+
+/**
+ * Cluster. (SPI, Singleton, ThreadSafe)
+ *
+ * Cluster
+ * Fault-Tolerant
+ *
+ */
+@SPI(Cluster.DEFAULT)
+public interface Cluster {
+
+ String DEFAULT = "failover";
+
+ /**
+ * Merge the directory invokers to a virtual invoker.
+ *
+ * @param
+ * @param directory
+ * @return cluster invoker
+ * @throws RpcException
+ */
+ @Adaptive
+ Invoker join(Directory directory) throws RpcException;
+
+ static Cluster getCluster(String name) {
+ return getCluster(name, true);
+ }
+
+ static Cluster getCluster(String name, boolean wrap) {
+ if (StringUtils.isEmpty(name)) {
+ name = Cluster.DEFAULT;
+ }
+ return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
index 2a69f6efb5..3b1d25e5c3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
@@ -1,119 +1,119 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.utils.CollectionUtils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
-import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
-
-/**
- * Configurator. (SPI, Prototype, ThreadSafe)
- *
- */
-public interface Configurator extends Comparable {
-
- /**
- * Get the configurator url.
- *
- * @return configurator url.
- */
- URL getUrl();
-
- /**
- * Configure the provider url.
- *
- * @param url - old provider url.
- * @return new provider url.
- */
- URL configure(URL url);
-
-
- /**
- * Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
- * calculated
- *
- * URL contract:
- *
- *
override://0.0.0.0/...( or override://ip:port...?anyhost=true)¶1=value1... means global rules
- * (all of the providers take effect)
- *
override://ip:port...?anyhost=false Special rules (only for a certain provider)
- *
override:// rule is not supported... ,needs to be calculated by registry itself
- *
override://0.0.0.0/ without parameters means clearing the override
- *
- *
- * @param urls URL list to convert
- * @return converted configurator list
- */
- static Optional> toConfigurators(List urls) {
- if (CollectionUtils.isEmpty(urls)) {
- return Optional.empty();
- }
-
- ConfiguratorFactory configuratorFactory = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
- .getAdaptiveExtension();
-
- List configurators = new ArrayList<>(urls.size());
- for (URL url : urls) {
- if (EMPTY_PROTOCOL.equals(url.getProtocol())) {
- configurators.clear();
- break;
- }
- Map override = new HashMap<>(url.getParameters());
- //The anyhost parameter of override may be added automatically, it can't change the judgement of changing url
- override.remove(ANYHOST_KEY);
- if (CollectionUtils.isEmptyMap(override)) {
- continue;
- }
- configurators.add(configuratorFactory.getConfigurator(url));
- }
- Collections.sort(configurators);
- return Optional.of(configurators);
- }
-
- /**
- * Sort by host, then by priority
- * 1. the url with a specific host ip should have higher priority than 0.0.0.0
- * 2. if two url has the same host, compare by priority value;
- */
- @Override
- default int compareTo(Configurator o) {
- if (o == null) {
- return -1;
- }
-
- int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());
- // host is the same, sort by priority
- if (ipCompare == 0) {
- int i = getUrl().getParameter(PRIORITY_KEY, 0);
- int j = o.getUrl().getParameter(PRIORITY_KEY, 0);
- return Integer.compare(i, j);
- } else {
- return ipCompare;
- }
- }
-}
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.utils.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
+import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
+
+/**
+ * Configurator. (SPI, Prototype, ThreadSafe)
+ *
+ */
+public interface Configurator extends Comparable {
+
+ /**
+ * Get the configurator url.
+ *
+ * @return configurator url.
+ */
+ URL getUrl();
+
+ /**
+ * Configure the provider url.
+ *
+ * @param url - old provider url.
+ * @return new provider url.
+ */
+ URL configure(URL url);
+
+
+ /**
+ * Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
+ * calculated
+ *
+ * URL contract:
+ *
+ *
override://0.0.0.0/...( or override://ip:port...?anyhost=true)¶1=value1... means global rules
+ * (all of the providers take effect)
+ *
override://ip:port...?anyhost=false Special rules (only for a certain provider)
+ *
override:// rule is not supported... ,needs to be calculated by registry itself
+ *
override://0.0.0.0/ without parameters means clearing the override
+ *
+ *
+ * @param urls URL list to convert
+ * @return converted configurator list
+ */
+ static Optional> toConfigurators(List urls) {
+ if (CollectionUtils.isEmpty(urls)) {
+ return Optional.empty();
+ }
+
+ ConfiguratorFactory configuratorFactory = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
+ .getAdaptiveExtension();
+
+ List configurators = new ArrayList<>(urls.size());
+ for (URL url : urls) {
+ if (EMPTY_PROTOCOL.equals(url.getProtocol())) {
+ configurators.clear();
+ break;
+ }
+ Map override = new HashMap<>(url.getParameters());
+ //The anyhost parameter of override may be added automatically, it can't change the judgement of changing url
+ override.remove(ANYHOST_KEY);
+ if (CollectionUtils.isEmptyMap(override)) {
+ continue;
+ }
+ configurators.add(configuratorFactory.getConfigurator(url));
+ }
+ Collections.sort(configurators);
+ return Optional.of(configurators);
+ }
+
+ /**
+ * Sort by host, then by priority
+ * 1. the url with a specific host ip should have higher priority than 0.0.0.0
+ * 2. if two url has the same host, compare by priority value;
+ */
+ @Override
+ default int compareTo(Configurator o) {
+ if (o == null) {
+ return -1;
+ }
+
+ int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());
+ // host is the same, sort by priority
+ if (ipCompare == 0) {
+ int i = getUrl().getParameter(PRIORITY_KEY, 0);
+ int j = o.getUrl().getParameter(PRIORITY_KEY, 0);
+ return Integer.compare(i, j);
+ } else {
+ return ipCompare;
+ }
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
index 026d6f54ed..8b2722c29f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
@@ -1,39 +1,39 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-
-/**
- * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)
- *
- */
-@SPI
-public interface ConfiguratorFactory {
-
- /**
- * get the configurator instance.
- *
- * @param url - configurator url.
- * @return configurator instance.
- */
- @Adaptive("protocol")
- Configurator getConfigurator(URL url);
-
-}
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)
+ *
+ */
+@SPI
+public interface ConfiguratorFactory {
+
+ /**
+ * get the configurator instance.
+ *
+ * @param url - configurator url.
+ * @return configurator instance.
+ */
+ @Adaptive("protocol")
+ Configurator getConfigurator(URL url);
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
index 5a92d97814..c797218029 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
@@ -1,72 +1,72 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-
-import java.util.List;
-
-/**
- * Directory. (SPI, Prototype, ThreadSafe)
- *
- * Directory Service
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- */
-public interface Directory extends Node {
-
- /**
- * get service type.
- *
- * @return service type.
- */
- Class getInterface();
-
- /**
- * list invokers.
- *
- * @return invokers
- */
- List> list(Invocation invocation) throws RpcException;
-
- List> getAllInvokers();
-
- URL getConsumerUrl();
-
- boolean isDestroyed();
-
- default boolean isEmpty() {
- return CollectionUtils.isEmpty(getAllInvokers());
- }
-
- default boolean isServiceDiscovery() {
- return false;
- }
-
- void discordAddresses();
-
- RouterChain getRouterChain();
-
- default boolean isNotificationReceived() {
- return false;
- }
-}
\ No newline at end of file
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.Node;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.List;
+
+/**
+ * Directory. (SPI, Prototype, ThreadSafe)
+ *
+ * Directory Service
+ *
+ * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
+ */
+public interface Directory extends Node {
+
+ /**
+ * get service type.
+ *
+ * @return service type.
+ */
+ Class getInterface();
+
+ /**
+ * list invokers.
+ *
+ * @return invokers
+ */
+ List> list(Invocation invocation) throws RpcException;
+
+ List> getAllInvokers();
+
+ URL getConsumerUrl();
+
+ boolean isDestroyed();
+
+ default boolean isEmpty() {
+ return CollectionUtils.isEmpty(getAllInvokers());
+ }
+
+ default boolean isServiceDiscovery() {
+ return false;
+ }
+
+ void discordAddresses();
+
+ RouterChain getRouterChain();
+
+ default boolean isNotificationReceived() {
+ return false;
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
index 4e6ced18a0..94b28a8bc3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
@@ -1,50 +1,50 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
-
-import java.util.List;
-
-/**
- * LoadBalance. (SPI, Singleton, ThreadSafe)
- *
- * Load-Balancing
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- */
-@SPI(RandomLoadBalance.NAME)
-public interface LoadBalance {
-
- /**
- * select one invoker in list.
- *
- * @param invokers invokers.
- * @param url refer url
- * @param invocation invocation.
- * @return selected invoker.
- */
- @Adaptive("loadbalance")
- Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException;
-
-}
\ No newline at end of file
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
+
+import java.util.List;
+
+/**
+ * LoadBalance. (SPI, Singleton, ThreadSafe)
+ *
+ * Load-Balancing
+ *
+ * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
+ */
+@SPI(RandomLoadBalance.NAME)
+public interface LoadBalance {
+
+ /**
+ * select one invoker in list.
+ *
+ * @param invokers invokers.
+ * @param url refer url
+ * @param invocation invocation.
+ * @return selected invoker.
+ */
+ @Adaptive("loadbalance")
+ Invoker select(List> invokers, URL url, Invocation invocation) throws RpcException;
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
index c412ff8f23..287701291e 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
@@ -1,103 +1,103 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-
-import java.util.List;
-
-/**
- * Router. (SPI, Prototype, ThreadSafe)
- *
- * Routing
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- * @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation)
- */
-public interface Router extends Comparable {
-
- int DEFAULT_PRIORITY = Integer.MAX_VALUE;
-
- /**
- * Get the router url.
- *
- * @return url
- */
- URL getUrl();
-
- /**
- * Filter invokers with current routing rule and only return the invokers that comply with the rule.
- *
- * @param invokers invoker list
- * @param url refer url
- * @param invocation invocation
- * @return routed invokers
- * @throws RpcException
- */
- List> route(List> invokers, URL url, Invocation invocation) throws RpcException;
-
-
- /**
- * Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a
- * chance to prepare before {@link Router#route(List, URL, Invocation)} gets called.
- *
- * @param invokers invoker list
- * @param invoker's type
- */
- default void notify(List> invokers) {
-
- }
-
- /**
- * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
- * rule change.
- *
- * @return true if the router need to execute every time.
- */
- boolean isRuntime();
-
- /**
- * To decide whether this router should take effect when none of the invoker can match the router rule, which
- * means the {@link #route(List, URL, Invocation)} would be empty. Most of time, most router implementation would
- * default this value to false.
- *
- * @return true to execute if none of invokers matches the current router
- */
- boolean isForce();
-
- /**
- * Router's priority, used to sort routers.
- *
- * @return router's priority
- */
- int getPriority();
-
- default void stop() {
- //do nothing by default
- }
-
- @Override
- default int compareTo(Router o) {
- if (o == null) {
- throw new IllegalArgumentException();
- }
- return Integer.compare(this.getPriority(), o.getPriority());
- }
-}
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.List;
+
+/**
+ * Router. (SPI, Prototype, ThreadSafe)
+ *
+ * Routing
+ *
+ * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
+ * @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation)
+ */
+public interface Router extends Comparable {
+
+ int DEFAULT_PRIORITY = Integer.MAX_VALUE;
+
+ /**
+ * Get the router url.
+ *
+ * @return url
+ */
+ URL getUrl();
+
+ /**
+ * Filter invokers with current routing rule and only return the invokers that comply with the rule.
+ *
+ * @param invokers invoker list
+ * @param url refer url
+ * @param invocation invocation
+ * @return routed invokers
+ * @throws RpcException
+ */
+ List> route(List> invokers, URL url, Invocation invocation) throws RpcException;
+
+
+ /**
+ * Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a
+ * chance to prepare before {@link Router#route(List, URL, Invocation)} gets called.
+ *
+ * @param invokers invoker list
+ * @param invoker's type
+ */
+ default void notify(List> invokers) {
+
+ }
+
+ /**
+ * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
+ * rule change.
+ *
+ * @return true if the router need to execute every time.
+ */
+ boolean isRuntime();
+
+ /**
+ * To decide whether this router should take effect when none of the invoker can match the router rule, which
+ * means the {@link #route(List, URL, Invocation)} would be empty. Most of time, most router implementation would
+ * default this value to false.
+ *
+ * @return true to execute if none of invokers matches the current router
+ */
+ boolean isForce();
+
+ /**
+ * Router's priority, used to sort routers.
+ *
+ * @return router's priority
+ */
+ int getPriority();
+
+ default void stop() {
+ //do nothing by default
+ }
+
+ @Override
+ default int compareTo(Router o) {
+ if (o == null) {
+ throw new IllegalArgumentException();
+ }
+ return Integer.compare(this.getPriority(), o.getPriority());
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
index b7644b3459..3a98a587a3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
@@ -1,47 +1,47 @@
-/*
- * 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.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-
-/**
- * RouterFactory. (SPI, Singleton, ThreadSafe)
- *
- * Note Router has a different behaviour since 2.7.0, for each type of Router, there will only has one Router instance
- * for each service. See {@link CacheableRouterFactory} and {@link RouterChain} for how to extend a new Router or how
- * the Router instances are loaded.
- */
-@SPI
-public interface RouterFactory {
-
- /**
- * Create router.
- * Since 2.7.0, most of the time, we will not use @Adaptive feature, so it's kept only for compatibility.
- *
- * @param url url
- * @return router instance
- */
- @Adaptive("protocol")
- Router getRouter(URL url);
-}
+/*
+ * 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.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ * RouterFactory. (SPI, Singleton, ThreadSafe)
+ *
+ * Note Router has a different behaviour since 2.7.0, for each type of Router, there will only has one Router instance
+ * for each service. See {@link CacheableRouterFactory} and {@link RouterChain} for how to extend a new Router or how
+ * the Router instances are loaded.
+ */
+@SPI
+public interface RouterFactory {
+
+ /**
+ * Create router.
+ * Since 2.7.0, most of the time, we will not use @Adaptive feature, so it's kept only for compatibility.
+ *
+ * @param url url
+ * @return router instance
+ */
+ @Adaptive("protocol")
+ Router getRouter(URL url);
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
index 751d284142..a61288983f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
@@ -1,170 +1,170 @@
-/*
- * 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.rpc.cluster.configurator;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.remoting.Constants;
-import org.apache.dubbo.rpc.cluster.Configurator;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
-import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
-import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.INTERFACES;
-import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
-import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
-
-/**
- * AbstractOverrideConfigurator
- */
-public abstract class AbstractConfigurator implements Configurator {
-
- private static final String TILDE = "~";
-
- private final URL configuratorUrl;
-
- public AbstractConfigurator(URL url) {
- if (url == null) {
- throw new IllegalArgumentException("configurator url == null");
- }
- this.configuratorUrl = url;
- }
-
- @Override
- public URL getUrl() {
- return configuratorUrl;
- }
-
- @Override
- public URL configure(URL url) {
- // If override url is not enabled or is invalid, just return.
- if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) {
- return url;
- }
- /*
- * This if branch is created since 2.7.0.
- */
- String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);
- if (StringUtils.isNotEmpty(apiVersion)) {
- String currentSide = url.getSide();
- String configuratorSide = configuratorUrl.getSide();
- if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
- url = configureIfMatch(NetUtils.getLocalHost(), url);
- } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) &&
- url.getPort() == configuratorUrl.getPort()) {
- url = configureIfMatch(url.getHost(), url);
- }
- }
- /*
- * This else branch is deprecated and is left only to keep compatibility with versions before 2.7.0
- */
- else {
- url = configureDeprecated(url);
- }
- return url;
- }
-
- @Deprecated
- private URL configureDeprecated(URL url) {
- // If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
- if (configuratorUrl.getPort() != 0) {
- if (url.getPort() == configuratorUrl.getPort()) {
- return configureIfMatch(url.getHost(), url);
- }
- } else {
- /*
- * override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0.
- * 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore.
- * 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider.
- */
- if (url.getSide(PROVIDER).equals(CONSUMER)) {
- // NetUtils.getLocalHost is the ip address consumer registered to registry.
- return configureIfMatch(NetUtils.getLocalHost(), url);
- } else if (url.getSide(CONSUMER).equals(PROVIDER)) {
- // take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
- return configureIfMatch(ANYHOST_VALUE, url);
- }
- }
- return url;
- }
-
- private URL configureIfMatch(String host, URL url) {
- if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
- // TODO, to support wildcards
- String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
- if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) {
- String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
- String currentApplication = url.getApplication(url.getUsername());
- if (configApplication == null || ANY_VALUE.equals(configApplication)
- || configApplication.equals(currentApplication)) {
- Set conditionKeys = new HashSet();
- conditionKeys.add(CATEGORY_KEY);
- conditionKeys.add(Constants.CHECK_KEY);
- conditionKeys.add(DYNAMIC_KEY);
- conditionKeys.add(ENABLED_KEY);
- conditionKeys.add(GROUP_KEY);
- conditionKeys.add(VERSION_KEY);
- conditionKeys.add(APPLICATION_KEY);
- conditionKeys.add(SIDE_KEY);
- conditionKeys.add(CONFIG_VERSION_KEY);
- conditionKeys.add(COMPATIBLE_CONFIG_KEY);
- conditionKeys.add(INTERFACES);
- for (Map.Entry entry : configuratorUrl.getParameters().entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- boolean startWithTilde = startWithTilde(key);
- if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
- if (startWithTilde) {
- conditionKeys.add(key);
- }
- if (value != null && !ANY_VALUE.equals(value)
- && !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
- return url;
- }
- }
- }
- return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
- }
- }
- }
- return url;
- }
-
- private boolean startWithTilde(String key) {
- if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) {
- return true;
- }
- return false;
- }
-
- protected abstract URL doConfigure(URL currentUrl, URL configUrl);
-
-}
+/*
+ * 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.rpc.cluster.configurator;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.Constants;
+import org.apache.dubbo.rpc.cluster.Configurator;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
+import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.INTERFACES;
+import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
+
+/**
+ * AbstractOverrideConfigurator
+ */
+public abstract class AbstractConfigurator implements Configurator {
+
+ private static final String TILDE = "~";
+
+ private final URL configuratorUrl;
+
+ public AbstractConfigurator(URL url) {
+ if (url == null) {
+ throw new IllegalArgumentException("configurator url == null");
+ }
+ this.configuratorUrl = url;
+ }
+
+ @Override
+ public URL getUrl() {
+ return configuratorUrl;
+ }
+
+ @Override
+ public URL configure(URL url) {
+ // If override url is not enabled or is invalid, just return.
+ if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) {
+ return url;
+ }
+ /*
+ * This if branch is created since 2.7.0.
+ */
+ String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);
+ if (StringUtils.isNotEmpty(apiVersion)) {
+ String currentSide = url.getSide();
+ String configuratorSide = configuratorUrl.getSide();
+ if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
+ url = configureIfMatch(NetUtils.getLocalHost(), url);
+ } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) &&
+ url.getPort() == configuratorUrl.getPort()) {
+ url = configureIfMatch(url.getHost(), url);
+ }
+ }
+ /*
+ * This else branch is deprecated and is left only to keep compatibility with versions before 2.7.0
+ */
+ else {
+ url = configureDeprecated(url);
+ }
+ return url;
+ }
+
+ @Deprecated
+ private URL configureDeprecated(URL url) {
+ // If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
+ if (configuratorUrl.getPort() != 0) {
+ if (url.getPort() == configuratorUrl.getPort()) {
+ return configureIfMatch(url.getHost(), url);
+ }
+ } else {
+ /*
+ * override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0.
+ * 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore.
+ * 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider.
+ */
+ if (url.getSide(PROVIDER).equals(CONSUMER)) {
+ // NetUtils.getLocalHost is the ip address consumer registered to registry.
+ return configureIfMatch(NetUtils.getLocalHost(), url);
+ } else if (url.getSide(CONSUMER).equals(PROVIDER)) {
+ // take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
+ return configureIfMatch(ANYHOST_VALUE, url);
+ }
+ }
+ return url;
+ }
+
+ private URL configureIfMatch(String host, URL url) {
+ if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
+ // TODO, to support wildcards
+ String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
+ if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) {
+ String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
+ String currentApplication = url.getApplication(url.getUsername());
+ if (configApplication == null || ANY_VALUE.equals(configApplication)
+ || configApplication.equals(currentApplication)) {
+ Set conditionKeys = new HashSet();
+ conditionKeys.add(CATEGORY_KEY);
+ conditionKeys.add(Constants.CHECK_KEY);
+ conditionKeys.add(DYNAMIC_KEY);
+ conditionKeys.add(ENABLED_KEY);
+ conditionKeys.add(GROUP_KEY);
+ conditionKeys.add(VERSION_KEY);
+ conditionKeys.add(APPLICATION_KEY);
+ conditionKeys.add(SIDE_KEY);
+ conditionKeys.add(CONFIG_VERSION_KEY);
+ conditionKeys.add(COMPATIBLE_CONFIG_KEY);
+ conditionKeys.add(INTERFACES);
+ for (Map.Entry entry : configuratorUrl.getParameters().entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ boolean startWithTilde = startWithTilde(key);
+ if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
+ if (startWithTilde) {
+ conditionKeys.add(key);
+ }
+ if (value != null && !ANY_VALUE.equals(value)
+ && !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
+ return url;
+ }
+ }
+ }
+ return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
+ }
+ }
+ }
+ return url;
+ }
+
+ private boolean startWithTilde(String key) {
+ if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) {
+ return true;
+ }
+ return false;
+ }
+
+ protected abstract URL doConfigure(URL currentUrl, URL configUrl);
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
index c81d9b8f1d..cb83b8b854 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
@@ -1,37 +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.dubbo.rpc.cluster.configurator.absent;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
-
-/**
- * AbsentConfigurator
- *
- */
-public class AbsentConfigurator extends AbstractConfigurator {
-
- public AbsentConfigurator(URL url) {
- super(url);
- }
-
- @Override
- public URL doConfigure(URL currentUrl, URL configUrl) {
- return currentUrl.addParametersIfAbsent(configUrl.getParameters());
- }
-
-}
+/*
+ * 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.rpc.cluster.configurator.absent;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
+
+/**
+ * AbsentConfigurator
+ *
+ */
+public class AbsentConfigurator extends AbstractConfigurator {
+
+ public AbsentConfigurator(URL url) {
+ super(url);
+ }
+
+ @Override
+ public URL doConfigure(URL currentUrl, URL configUrl) {
+ return currentUrl.addParametersIfAbsent(configUrl.getParameters());
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
index 86b0e708b4..479eb5082a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
@@ -1,34 +1,34 @@
-/*
- * 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.rpc.cluster.configurator.absent;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Configurator;
-import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
-
-/**
- * AbsentConfiguratorFactory
- *
- */
-public class AbsentConfiguratorFactory implements ConfiguratorFactory {
-
- @Override
- public Configurator getConfigurator(URL url) {
- return new AbsentConfigurator(url);
- }
-
-}
+/*
+ * 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.rpc.cluster.configurator.absent;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+
+/**
+ * AbsentConfiguratorFactory
+ *
+ */
+public class AbsentConfiguratorFactory implements ConfiguratorFactory {
+
+ @Override
+ public Configurator getConfigurator(URL url) {
+ return new AbsentConfigurator(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
index bc9beb4f8b..23f0a8d8c3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
@@ -1,37 +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.dubbo.rpc.cluster.configurator.override;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
-
-/**
- * OverrideConfigurator
- *
- */
-public class OverrideConfigurator extends AbstractConfigurator {
-
- public OverrideConfigurator(URL url) {
- super(url);
- }
-
- @Override
- public URL doConfigure(URL currentUrl, URL configUrl) {
- return currentUrl.addParameters(configUrl.getParameters());
- }
-
-}
+/*
+ * 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.rpc.cluster.configurator.override;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
+
+/**
+ * OverrideConfigurator
+ *
+ */
+public class OverrideConfigurator extends AbstractConfigurator {
+
+ public OverrideConfigurator(URL url) {
+ super(url);
+ }
+
+ @Override
+ public URL doConfigure(URL currentUrl, URL configUrl) {
+ return currentUrl.addParameters(configUrl.getParameters());
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
index a63aa55004..504ae3b5d7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
@@ -1,34 +1,34 @@
-/*
- * 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.rpc.cluster.configurator.override;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Configurator;
-import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
-
-/**
- * OverrideConfiguratorFactory
- *
- */
-public class OverrideConfiguratorFactory implements ConfiguratorFactory {
-
- @Override
- public Configurator getConfigurator(URL url) {
- return new OverrideConfigurator(url);
- }
-
-}
+/*
+ * 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.rpc.cluster.configurator.override;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+
+/**
+ * OverrideConfiguratorFactory
+ *
+ */
+public class OverrideConfiguratorFactory implements ConfiguratorFactory {
+
+ @Override
+ public Configurator getConfigurator(URL url) {
+ return new OverrideConfigurator(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
index 50110aa6ab..2b1a3d70ea 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
@@ -1,114 +1,114 @@
-/*
- * 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.rpc.cluster.directory;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.RouterChain;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * StaticDirectory
- */
-public class StaticDirectory extends AbstractDirectory {
- private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class);
-
- private final List> invokers;
-
- public StaticDirectory(List> invokers) {
- this(null, invokers, null);
- }
-
- public StaticDirectory(List> invokers, RouterChain routerChain) {
- this(null, invokers, routerChain);
- }
-
- public StaticDirectory(URL url, List> invokers) {
- this(url, invokers, null);
- }
-
- public StaticDirectory(URL url, List> invokers, RouterChain routerChain) {
- super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
- if (CollectionUtils.isEmpty(invokers)) {
- throw new IllegalArgumentException("invokers == null");
- }
- this.invokers = invokers;
- }
-
- @Override
- public Class getInterface() {
- return invokers.get(0).getInterface();
- }
-
- @Override
- public List> getAllInvokers() {
- return invokers;
- }
-
- @Override
- public boolean isAvailable() {
- if (isDestroyed()) {
- return false;
- }
- for (Invoker invoker : invokers) {
- if (invoker.isAvailable()) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void destroy() {
- if (isDestroyed()) {
- return;
- }
- super.destroy();
- for (Invoker invoker : invokers) {
- invoker.destroy();
- }
- invokers.clear();
- }
-
- public void buildRouterChain() {
- RouterChain routerChain = RouterChain.buildChain(getUrl());
- routerChain.setInvokers(invokers);
- routerChain.loop(true);
- this.setRouterChain(routerChain);
- }
-
- @Override
- protected List> doList(Invocation invocation) throws RpcException {
- List> finalInvokers = invokers;
- if (routerChain != null) {
- try {
- finalInvokers = routerChain.route(getConsumerUrl(), invocation);
- } catch (Throwable t) {
- logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
- }
- }
- return finalInvokers == null ? Collections.emptyList() : finalInvokers;
- }
-
-}
+/*
+ * 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.rpc.cluster.directory;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.RouterChain;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * StaticDirectory
+ */
+public class StaticDirectory extends AbstractDirectory {
+ private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class);
+
+ private final List> invokers;
+
+ public StaticDirectory(List> invokers) {
+ this(null, invokers, null);
+ }
+
+ public StaticDirectory(List> invokers, RouterChain routerChain) {
+ this(null, invokers, routerChain);
+ }
+
+ public StaticDirectory(URL url, List> invokers) {
+ this(url, invokers, null);
+ }
+
+ public StaticDirectory(URL url, List> invokers, RouterChain routerChain) {
+ super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
+ if (CollectionUtils.isEmpty(invokers)) {
+ throw new IllegalArgumentException("invokers == null");
+ }
+ this.invokers = invokers;
+ }
+
+ @Override
+ public Class getInterface() {
+ return invokers.get(0).getInterface();
+ }
+
+ @Override
+ public List> getAllInvokers() {
+ return invokers;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (isDestroyed()) {
+ return false;
+ }
+ for (Invoker invoker : invokers) {
+ if (invoker.isAvailable()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void destroy() {
+ if (isDestroyed()) {
+ return;
+ }
+ super.destroy();
+ for (Invoker invoker : invokers) {
+ invoker.destroy();
+ }
+ invokers.clear();
+ }
+
+ public void buildRouterChain() {
+ RouterChain routerChain = RouterChain.buildChain(getUrl());
+ routerChain.setInvokers(invokers);
+ routerChain.loop(true);
+ this.setRouterChain(routerChain);
+ }
+
+ @Override
+ protected List> doList(Invocation invocation) throws RpcException {
+ List> finalInvokers = invokers;
+ if (routerChain != null) {
+ try {
+ finalInvokers = routerChain.route(getConsumerUrl(), invocation);
+ } catch (Throwable t) {
+ logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
+ }
+ }
+ return finalInvokers == null ? Collections.emptyList() : finalInvokers;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
index e2c2a6f190..31024be6f3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
@@ -1,99 +1,99 @@
-/*
- * 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.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
-import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH;
-import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;
-import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;
-import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;
-
-/**
- * AbstractLoadBalance
- */
-public abstract class AbstractLoadBalance implements LoadBalance {
- /**
- * Calculate the weight according to the uptime proportion of warmup time
- * the new weight will be within 1(inclusive) to weight(inclusive)
- *
- * @param uptime the uptime in milliseconds
- * @param warmup the warmup time in milliseconds
- * @param weight the weight of an invoker
- * @return weight which takes warmup into account
- */
- static int calculateWarmupWeight(int uptime, int warmup, int weight) {
- int ww = (int) ( uptime / ((float) warmup / weight));
- return ww < 1 ? 1 : (Math.min(ww, weight));
- }
-
- @Override
- public Invoker select(List> invokers, URL url, Invocation invocation) {
- if (CollectionUtils.isEmpty(invokers)) {
- return null;
- }
- if (invokers.size() == 1) {
- return invokers.get(0);
- }
- return doSelect(invokers, url, invocation);
- }
-
- protected abstract Invoker doSelect(List> invokers, URL url, Invocation invocation);
-
-
- /**
- * Get the weight of the invoker's invocation which takes warmup time into account
- * if the uptime is within the warmup time, the weight will be reduce proportionally
- *
- * @param invoker the invoker
- * @param invocation the invocation of this invoker
- * @return weight
- */
- int getWeight(Invoker> invoker, Invocation invocation) {
- int weight;
- URL url = invoker.getUrl();
- // Multiple registry scenario, load balance among multiple registries.
- if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
- weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
- } else {
- weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
- if (weight > 0) {
- long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
- if (timestamp > 0L) {
- long uptime = System.currentTimeMillis() - timestamp;
- if (uptime < 0) {
- return 1;
- }
- int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
- if (uptime > 0 && uptime < warmup) {
- weight = calculateWarmupWeight((int)uptime, warmup, weight);
- }
- }
- }
- }
- return Math.max(weight, 0);
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH;
+import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;
+import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;
+import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;
+
+/**
+ * AbstractLoadBalance
+ */
+public abstract class AbstractLoadBalance implements LoadBalance {
+ /**
+ * Calculate the weight according to the uptime proportion of warmup time
+ * the new weight will be within 1(inclusive) to weight(inclusive)
+ *
+ * @param uptime the uptime in milliseconds
+ * @param warmup the warmup time in milliseconds
+ * @param weight the weight of an invoker
+ * @return weight which takes warmup into account
+ */
+ static int calculateWarmupWeight(int uptime, int warmup, int weight) {
+ int ww = (int) ( uptime / ((float) warmup / weight));
+ return ww < 1 ? 1 : (Math.min(ww, weight));
+ }
+
+ @Override
+ public Invoker select(List> invokers, URL url, Invocation invocation) {
+ if (CollectionUtils.isEmpty(invokers)) {
+ return null;
+ }
+ if (invokers.size() == 1) {
+ return invokers.get(0);
+ }
+ return doSelect(invokers, url, invocation);
+ }
+
+ protected abstract Invoker doSelect(List> invokers, URL url, Invocation invocation);
+
+
+ /**
+ * Get the weight of the invoker's invocation which takes warmup time into account
+ * if the uptime is within the warmup time, the weight will be reduce proportionally
+ *
+ * @param invoker the invoker
+ * @param invocation the invocation of this invoker
+ * @return weight
+ */
+ int getWeight(Invoker> invoker, Invocation invocation) {
+ int weight;
+ URL url = invoker.getUrl();
+ // Multiple registry scenario, load balance among multiple registries.
+ if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
+ weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
+ } else {
+ weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
+ if (weight > 0) {
+ long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
+ if (timestamp > 0L) {
+ long uptime = System.currentTimeMillis() - timestamp;
+ if (uptime < 0) {
+ return 1;
+ }
+ int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
+ if (uptime > 0 && uptime < warmup) {
+ weight = calculateWarmupWeight((int)uptime, warmup, weight);
+ }
+ }
+ }
+ }
+ return Math.max(weight, 0);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
index 4f5859de2d..15c7066e06 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
@@ -1,131 +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.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.io.Bytes;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.support.RpcUtils;
-
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
-
-/**
- * ConsistentHashLoadBalance
- */
-public class ConsistentHashLoadBalance extends AbstractLoadBalance {
- public static final String NAME = "consistenthash";
-
- /**
- * Hash nodes name
- */
- public static final String HASH_NODES = "hash.nodes";
-
- /**
- * Hash arguments name
- */
- public static final String HASH_ARGUMENTS = "hash.arguments";
-
- private final ConcurrentMap> selectors = new ConcurrentHashMap>();
-
- @SuppressWarnings("unchecked")
- @Override
- protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
- String methodName = RpcUtils.getMethodName(invocation);
- String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;
- // using the hashcode of list to compute the hash only pay attention to the elements in the list
- int invokersHashCode = invokers.hashCode();
- ConsistentHashSelector selector = (ConsistentHashSelector) selectors.get(key);
- if (selector == null || selector.identityHashCode != invokersHashCode) {
- selectors.put(key, new ConsistentHashSelector(invokers, methodName, invokersHashCode));
- selector = (ConsistentHashSelector) selectors.get(key);
- }
- return selector.select(invocation);
- }
-
- private static final class ConsistentHashSelector {
-
- private final TreeMap> virtualInvokers;
-
- private final int replicaNumber;
-
- private final int identityHashCode;
-
- private final int[] argumentIndex;
-
- ConsistentHashSelector(List> invokers, String methodName, int identityHashCode) {
- this.virtualInvokers = new TreeMap>();
- this.identityHashCode = identityHashCode;
- URL url = invokers.get(0).getUrl();
- this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);
- String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0"));
- argumentIndex = new int[index.length];
- for (int i = 0; i < index.length; i++) {
- argumentIndex[i] = Integer.parseInt(index[i]);
- }
- for (Invoker invoker : invokers) {
- String address = invoker.getUrl().getAddress();
- for (int i = 0; i < replicaNumber / 4; i++) {
- byte[] digest = Bytes.getMD5(address + i);
- for (int h = 0; h < 4; h++) {
- long m = hash(digest, h);
- virtualInvokers.put(m, invoker);
- }
- }
- }
- }
-
- public Invoker select(Invocation invocation) {
- String key = toKey(invocation.getArguments());
- byte[] digest = Bytes.getMD5(key);
- return selectForKey(hash(digest, 0));
- }
-
- private String toKey(Object[] args) {
- StringBuilder buf = new StringBuilder();
- for (int i : argumentIndex) {
- if (i >= 0 && i < args.length) {
- buf.append(args[i]);
- }
- }
- return buf.toString();
- }
-
- private Invoker selectForKey(long hash) {
- Map.Entry> entry = virtualInvokers.ceilingEntry(hash);
- if (entry == null) {
- entry = virtualInvokers.firstEntry();
- }
- return entry.getValue();
- }
-
- private long hash(byte[] digest, int number) {
- return (((long) (digest[3 + number * 4] & 0xFF) << 24)
- | ((long) (digest[2 + number * 4] & 0xFF) << 16)
- | ((long) (digest[1 + number * 4] & 0xFF) << 8)
- | (digest[number * 4] & 0xFF))
- & 0xFFFFFFFFL;
- }
- }
-
-}
+/*
+ * 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.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.io.Bytes;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.support.RpcUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
+
+/**
+ * ConsistentHashLoadBalance
+ */
+public class ConsistentHashLoadBalance extends AbstractLoadBalance {
+ public static final String NAME = "consistenthash";
+
+ /**
+ * Hash nodes name
+ */
+ public static final String HASH_NODES = "hash.nodes";
+
+ /**
+ * Hash arguments name
+ */
+ public static final String HASH_ARGUMENTS = "hash.arguments";
+
+ private final ConcurrentMap> selectors = new ConcurrentHashMap>();
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
+ String methodName = RpcUtils.getMethodName(invocation);
+ String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;
+ // using the hashcode of list to compute the hash only pay attention to the elements in the list
+ int invokersHashCode = invokers.hashCode();
+ ConsistentHashSelector selector = (ConsistentHashSelector) selectors.get(key);
+ if (selector == null || selector.identityHashCode != invokersHashCode) {
+ selectors.put(key, new ConsistentHashSelector(invokers, methodName, invokersHashCode));
+ selector = (ConsistentHashSelector) selectors.get(key);
+ }
+ return selector.select(invocation);
+ }
+
+ private static final class ConsistentHashSelector {
+
+ private final TreeMap> virtualInvokers;
+
+ private final int replicaNumber;
+
+ private final int identityHashCode;
+
+ private final int[] argumentIndex;
+
+ ConsistentHashSelector(List> invokers, String methodName, int identityHashCode) {
+ this.virtualInvokers = new TreeMap>();
+ this.identityHashCode = identityHashCode;
+ URL url = invokers.get(0).getUrl();
+ this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);
+ String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0"));
+ argumentIndex = new int[index.length];
+ for (int i = 0; i < index.length; i++) {
+ argumentIndex[i] = Integer.parseInt(index[i]);
+ }
+ for (Invoker invoker : invokers) {
+ String address = invoker.getUrl().getAddress();
+ for (int i = 0; i < replicaNumber / 4; i++) {
+ byte[] digest = Bytes.getMD5(address + i);
+ for (int h = 0; h < 4; h++) {
+ long m = hash(digest, h);
+ virtualInvokers.put(m, invoker);
+ }
+ }
+ }
+ }
+
+ public Invoker select(Invocation invocation) {
+ String key = toKey(invocation.getArguments());
+ byte[] digest = Bytes.getMD5(key);
+ return selectForKey(hash(digest, 0));
+ }
+
+ private String toKey(Object[] args) {
+ StringBuilder buf = new StringBuilder();
+ for (int i : argumentIndex) {
+ if (i >= 0 && i < args.length) {
+ buf.append(args[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ private Invoker selectForKey(long hash) {
+ Map.Entry> entry = virtualInvokers.ceilingEntry(hash);
+ if (entry == null) {
+ entry = virtualInvokers.firstEntry();
+ }
+ return entry.getValue();
+ }
+
+ private long hash(byte[] digest, int number) {
+ return (((long) (digest[3 + number * 4] & 0xFF) << 24)
+ | ((long) (digest[2 + number * 4] & 0xFF) << 16)
+ | ((long) (digest[1 + number * 4] & 0xFF) << 8)
+ | (digest[number * 4] & 0xFF))
+ & 0xFFFFFFFFL;
+ }
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
index 6b1ac64b98..41c1bab569 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
@@ -1,115 +1,115 @@
-/*
- * 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.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcStatus;
-
-import java.util.List;
-import java.util.concurrent.ThreadLocalRandom;
-
-/**
- * LeastActiveLoadBalance
- *
- * Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.
- * If there is only one invoker, use the invoker directly;
- * if there are multiple invokers and the weights are not the same, then random according to the total weight;
- * if there are multiple invokers and the same weight, then randomly called.
- */
-public class LeastActiveLoadBalance extends AbstractLoadBalance {
-
- public static final String NAME = "leastactive";
-
- @Override
- protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
- // Number of invokers
- int length = invokers.size();
- // The least active value of all invokers
- int leastActive = -1;
- // The number of invokers having the same least active value (leastActive)
- int leastCount = 0;
- // The index of invokers having the same least active value (leastActive)
- int[] leastIndexes = new int[length];
- // the weight of every invokers
- int[] weights = new int[length];
- // The sum of the warmup weights of all the least active invokers
- int totalWeight = 0;
- // The weight of the first least active invoker
- int firstWeight = 0;
- // Every least active invoker has the same weight value?
- boolean sameWeight = true;
-
-
- // Filter out all the least active invokers
- for (int i = 0; i < length; i++) {
- Invoker invoker = invokers.get(i);
- // Get the active number of the invoker
- int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
- // Get the weight of the invoker's configuration. The default value is 100.
- int afterWarmup = getWeight(invoker, invocation);
- // save for later use
- weights[i] = afterWarmup;
- // If it is the first invoker or the active number of the invoker is less than the current least active number
- if (leastActive == -1 || active < leastActive) {
- // Reset the active number of the current invoker to the least active number
- leastActive = active;
- // Reset the number of least active invokers
- leastCount = 1;
- // Put the first least active invoker first in leastIndexes
- leastIndexes[0] = i;
- // Reset totalWeight
- totalWeight = afterWarmup;
- // Record the weight the first least active invoker
- firstWeight = afterWarmup;
- // Each invoke has the same weight (only one invoker here)
- sameWeight = true;
- // If current invoker's active value equals with leaseActive, then accumulating.
- } else if (active == leastActive) {
- // Record the index of the least active invoker in leastIndexes order
- leastIndexes[leastCount++] = i;
- // Accumulate the total weight of the least active invoker
- totalWeight += afterWarmup;
- // If every invoker has the same weight?
- if (sameWeight && afterWarmup != firstWeight) {
- sameWeight = false;
- }
- }
- }
- // Choose an invoker from all the least active invokers
- if (leastCount == 1) {
- // If we got exactly one invoker having the least active value, return this invoker directly.
- return invokers.get(leastIndexes[0]);
- }
- if (!sameWeight && totalWeight > 0) {
- // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on
- // totalWeight.
- int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
- // Return a invoker based on the random value.
- for (int i = 0; i < leastCount; i++) {
- int leastIndex = leastIndexes[i];
- offsetWeight -= weights[leastIndex];
- if (offsetWeight < 0) {
- return invokers.get(leastIndex);
- }
- }
- }
- // If all invokers have the same weight value or totalWeight=0, return evenly.
- return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
- }
-}
+/*
+ * 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.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcStatus;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * LeastActiveLoadBalance
+ *
+ * Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.
+ * If there is only one invoker, use the invoker directly;
+ * if there are multiple invokers and the weights are not the same, then random according to the total weight;
+ * if there are multiple invokers and the same weight, then randomly called.
+ */
+public class LeastActiveLoadBalance extends AbstractLoadBalance {
+
+ public static final String NAME = "leastactive";
+
+ @Override
+ protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
+ // Number of invokers
+ int length = invokers.size();
+ // The least active value of all invokers
+ int leastActive = -1;
+ // The number of invokers having the same least active value (leastActive)
+ int leastCount = 0;
+ // The index of invokers having the same least active value (leastActive)
+ int[] leastIndexes = new int[length];
+ // the weight of every invokers
+ int[] weights = new int[length];
+ // The sum of the warmup weights of all the least active invokers
+ int totalWeight = 0;
+ // The weight of the first least active invoker
+ int firstWeight = 0;
+ // Every least active invoker has the same weight value?
+ boolean sameWeight = true;
+
+
+ // Filter out all the least active invokers
+ for (int i = 0; i < length; i++) {
+ Invoker invoker = invokers.get(i);
+ // Get the active number of the invoker
+ int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
+ // Get the weight of the invoker's configuration. The default value is 100.
+ int afterWarmup = getWeight(invoker, invocation);
+ // save for later use
+ weights[i] = afterWarmup;
+ // If it is the first invoker or the active number of the invoker is less than the current least active number
+ if (leastActive == -1 || active < leastActive) {
+ // Reset the active number of the current invoker to the least active number
+ leastActive = active;
+ // Reset the number of least active invokers
+ leastCount = 1;
+ // Put the first least active invoker first in leastIndexes
+ leastIndexes[0] = i;
+ // Reset totalWeight
+ totalWeight = afterWarmup;
+ // Record the weight the first least active invoker
+ firstWeight = afterWarmup;
+ // Each invoke has the same weight (only one invoker here)
+ sameWeight = true;
+ // If current invoker's active value equals with leaseActive, then accumulating.
+ } else if (active == leastActive) {
+ // Record the index of the least active invoker in leastIndexes order
+ leastIndexes[leastCount++] = i;
+ // Accumulate the total weight of the least active invoker
+ totalWeight += afterWarmup;
+ // If every invoker has the same weight?
+ if (sameWeight && afterWarmup != firstWeight) {
+ sameWeight = false;
+ }
+ }
+ }
+ // Choose an invoker from all the least active invokers
+ if (leastCount == 1) {
+ // If we got exactly one invoker having the least active value, return this invoker directly.
+ return invokers.get(leastIndexes[0]);
+ }
+ if (!sameWeight && totalWeight > 0) {
+ // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on
+ // totalWeight.
+ int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
+ // Return a invoker based on the random value.
+ for (int i = 0; i < leastCount; i++) {
+ int leastIndex = leastIndexes[i];
+ offsetWeight -= weights[leastIndex];
+ if (offsetWeight < 0) {
+ return invokers.get(leastIndex);
+ }
+ }
+ }
+ // If all invokers have the same weight value or totalWeight=0, return evenly.
+ return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
index ddb87fb473..b3e5adb9e6 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
@@ -1,131 +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.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Round robin load balance.
- */
-public class RoundRobinLoadBalance extends AbstractLoadBalance {
- public static final String NAME = "roundrobin";
-
- private static final int RECYCLE_PERIOD = 60000;
-
- protected static class WeightedRoundRobin {
- private int weight;
- private AtomicLong current = new AtomicLong(0);
- private long lastUpdate;
-
- public int getWeight() {
- return weight;
- }
-
- public void setWeight(int weight) {
- this.weight = weight;
- current.set(0);
- }
-
- public long increaseCurrent() {
- return current.addAndGet(weight);
- }
-
- public void sel(int total) {
- current.addAndGet(-1 * total);
- }
-
- public long getLastUpdate() {
- return lastUpdate;
- }
-
- public void setLastUpdate(long lastUpdate) {
- this.lastUpdate = lastUpdate;
- }
- }
-
- private ConcurrentMap> methodWeightMap = new ConcurrentHashMap>();
-
- /**
- * get invoker addr list cached for specified invocation
- *
- * for unit test only
- *
- * @param invokers
- * @param invocation
- * @return
- */
- protected Collection getInvokerAddrList(List> invokers, Invocation invocation) {
- String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
- Map map = methodWeightMap.get(key);
- if (map != null) {
- return map.keySet();
- }
- return null;
- }
-
- @Override
- protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
- String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
- ConcurrentMap map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());
- int totalWeight = 0;
- long maxCurrent = Long.MIN_VALUE;
- long now = System.currentTimeMillis();
- Invoker selectedInvoker = null;
- WeightedRoundRobin selectedWRR = null;
- for (Invoker invoker : invokers) {
- String identifyString = invoker.getUrl().toIdentityString();
- int weight = getWeight(invoker, invocation);
- WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {
- WeightedRoundRobin wrr = new WeightedRoundRobin();
- wrr.setWeight(weight);
- return wrr;
- });
-
- if (weight != weightedRoundRobin.getWeight()) {
- //weight changed
- weightedRoundRobin.setWeight(weight);
- }
- long cur = weightedRoundRobin.increaseCurrent();
- weightedRoundRobin.setLastUpdate(now);
- if (cur > maxCurrent) {
- maxCurrent = cur;
- selectedInvoker = invoker;
- selectedWRR = weightedRoundRobin;
- }
- totalWeight += weight;
- }
- if (invokers.size() != map.size()) {
- map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
- }
- if (selectedInvoker != null) {
- selectedWRR.sel(totalWeight);
- return selectedInvoker;
- }
- // should not happen here
- return invokers.get(0);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Round robin load balance.
+ */
+public class RoundRobinLoadBalance extends AbstractLoadBalance {
+ public static final String NAME = "roundrobin";
+
+ private static final int RECYCLE_PERIOD = 60000;
+
+ protected static class WeightedRoundRobin {
+ private int weight;
+ private AtomicLong current = new AtomicLong(0);
+ private long lastUpdate;
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ current.set(0);
+ }
+
+ public long increaseCurrent() {
+ return current.addAndGet(weight);
+ }
+
+ public void sel(int total) {
+ current.addAndGet(-1 * total);
+ }
+
+ public long getLastUpdate() {
+ return lastUpdate;
+ }
+
+ public void setLastUpdate(long lastUpdate) {
+ this.lastUpdate = lastUpdate;
+ }
+ }
+
+ private ConcurrentMap> methodWeightMap = new ConcurrentHashMap>();
+
+ /**
+ * get invoker addr list cached for specified invocation
+ *
+ * for unit test only
+ *
+ * @param invokers
+ * @param invocation
+ * @return
+ */
+ protected Collection getInvokerAddrList(List> invokers, Invocation invocation) {
+ String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
+ Map map = methodWeightMap.get(key);
+ if (map != null) {
+ return map.keySet();
+ }
+ return null;
+ }
+
+ @Override
+ protected Invoker doSelect(List> invokers, URL url, Invocation invocation) {
+ String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
+ ConcurrentMap map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());
+ int totalWeight = 0;
+ long maxCurrent = Long.MIN_VALUE;
+ long now = System.currentTimeMillis();
+ Invoker selectedInvoker = null;
+ WeightedRoundRobin selectedWRR = null;
+ for (Invoker invoker : invokers) {
+ String identifyString = invoker.getUrl().toIdentityString();
+ int weight = getWeight(invoker, invocation);
+ WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {
+ WeightedRoundRobin wrr = new WeightedRoundRobin();
+ wrr.setWeight(weight);
+ return wrr;
+ });
+
+ if (weight != weightedRoundRobin.getWeight()) {
+ //weight changed
+ weightedRoundRobin.setWeight(weight);
+ }
+ long cur = weightedRoundRobin.increaseCurrent();
+ weightedRoundRobin.setLastUpdate(now);
+ if (cur > maxCurrent) {
+ maxCurrent = cur;
+ selectedInvoker = invoker;
+ selectedWRR = weightedRoundRobin;
+ }
+ totalWeight += weight;
+ }
+ if (invokers.size() != map.size()) {
+ map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
+ }
+ if (selectedInvoker != null) {
+ selectedWRR.sel(totalWeight);
+ return selectedInvoker;
+ }
+ // should not happen here
+ return invokers.get(0);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
index f6cfec2993..8a3564500e 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
@@ -1,360 +1,360 @@
-/*
- * 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.rpc.cluster.router.condition;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.common.utils.UrlUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Constants;
-import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
-
-/**
- * ConditionRouter
- * It supports the conditional routing configured by "override://", in 2.6.x,
- * refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ .
- * For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter}
- * and {@link org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter}
- * refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ .
- */
-public class ConditionRouter extends AbstractRouter {
- public static final String NAME = "condition";
-
- private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
- protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
- protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
- protected Map whenCondition;
- protected Map thenCondition;
-
- private boolean enabled;
-
- public ConditionRouter(String rule, boolean force, boolean enabled) {
- this.force = force;
- this.enabled = enabled;
- if (enabled) {
- this.init(rule);
- }
- }
-
- public ConditionRouter(URL url) {
- this.url = url;
- this.priority = url.getParameter(PRIORITY_KEY, 0);
- this.force = url.getParameter(FORCE_KEY, false);
- this.enabled = url.getParameter(ENABLED_KEY, true);
- if (enabled) {
- init(url.getParameterAndDecoded(RULE_KEY));
- }
- }
-
- public void init(String rule) {
- try {
- if (rule == null || rule.trim().length() == 0) {
- throw new IllegalArgumentException("Illegal route rule!");
- }
- rule = rule.replace("consumer.", "").replace("provider.", "");
- int i = rule.indexOf("=>");
- String whenRule = i < 0 ? null : rule.substring(0, i).trim();
- String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
- Map when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap() : parseRule(whenRule);
- Map then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
- // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
- this.whenCondition = when;
- this.thenCondition = then;
- } catch (ParseException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- private static Map parseRule(String rule)
- throws ParseException {
- Map condition = new HashMap();
- if (StringUtils.isBlank(rule)) {
- return condition;
- }
- // Key-Value pair, stores both match and mismatch conditions
- MatchPair pair = null;
- // Multiple values
- Set values = null;
- final Matcher matcher = ROUTE_PATTERN.matcher(rule);
- while (matcher.find()) { // Try to match one by one
- String separator = matcher.group(1);
- String content = matcher.group(2);
- // Start part of the condition expression.
- if (StringUtils.isEmpty(separator)) {
- pair = new MatchPair();
- condition.put(content, pair);
- }
- // The KV part of the condition expression
- else if ("&".equals(separator)) {
- if (condition.get(content) == null) {
- pair = new MatchPair();
- condition.put(content, pair);
- } else {
- pair = condition.get(content);
- }
- }
- // The Value in the KV part.
- else if ("=".equals(separator)) {
- if (pair == null) {
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
- }
-
- values = pair.matches;
- values.add(content);
- }
- // The Value in the KV part.
- else if ("!=".equals(separator)) {
- if (pair == null) {
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
- }
-
- values = pair.mismatches;
- values.add(content);
- }
- // The Value in the KV part, if Value have more than one items.
- else if (",".equals(separator)) { // Should be separated by ','
- if (values == null || values.isEmpty()) {
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
- }
- values.add(content);
- } else {
- throw new ParseException("Illegal route rule \"" + rule
- + "\", The error char '" + separator + "' at index "
- + matcher.start() + " before \"" + content + "\".", matcher.start());
- }
- }
- return condition;
- }
-
- @Override
- public List> route(List> invokers, URL url, Invocation invocation)
- throws RpcException {
- if (!enabled) {
- return invokers;
- }
-
- if (CollectionUtils.isEmpty(invokers)) {
- return invokers;
- }
- try {
- if (!matchWhen(url, invocation)) {
- return invokers;
- }
- List> result = new ArrayList>();
- if (thenCondition == null) {
- logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
- return result;
- }
- for (Invoker invoker : invokers) {
- if (matchThen(invoker.getUrl(), url)) {
- result.add(invoker);
- }
- }
- if (!result.isEmpty()) {
- return result;
- } else if (force) {
- logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY));
- return result;
- }
- } catch (Throwable t) {
- logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
- }
- return invokers;
- }
-
- @Override
- public boolean isRuntime() {
- // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
-// return true;
- return this.url.getParameter(RUNTIME_KEY, false);
- }
-
- @Override
- public URL getUrl() {
- return url;
- }
-
- boolean matchWhen(URL url, Invocation invocation) {
- return CollectionUtils.isEmptyMap(whenCondition) || matchCondition(whenCondition, url, null, invocation);
- }
-
- private boolean matchThen(URL url, URL param) {
- return CollectionUtils.isNotEmptyMap(thenCondition) && matchCondition(thenCondition, url, param, null);
- }
-
- private boolean matchCondition(Map condition, URL url, URL param, Invocation invocation) {
- Map sample = url.toMap();
- boolean result = false;
- for (Map.Entry matchPair : condition.entrySet()) {
- String key = matchPair.getKey();
-
- if (key.startsWith(Constants.ARGUMENTS)) {
- if (!matchArguments(matchPair, invocation)) {
- return false;
- } else {
- result = true;
- continue;
- }
- }
-
- String sampleValue;
- //get real invoked method name from invocation
- if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) {
- sampleValue = invocation.getMethodName();
- } else if (ADDRESS_KEY.equals(key)) {
- sampleValue = url.getAddress();
- } else if (HOST_KEY.equals(key)) {
- sampleValue = url.getHost();
- } else {
- sampleValue = sample.get(key);
- if (sampleValue == null) {
- sampleValue = sample.get(key);
- }
- }
- if (sampleValue != null) {
- if (!matchPair.getValue().isMatch(sampleValue, param)) {
- return false;
- } else {
- result = true;
- }
- } else {
- //not pass the condition
- if (!matchPair.getValue().matches.isEmpty()) {
- return false;
- } else {
- result = true;
- }
- }
- }
- return result;
- }
-
- /**
- * analysis the arguments in the rule.
- * Examples would be like this:
- * "arguments[0]=1", whenCondition is that the first argument is equal to '1'.
- * "arguments[1]=a", whenCondition is that the second argument is equal to 'a'.
- * @param matchPair
- * @param invocation
- * @return
- */
- public boolean matchArguments(Map.Entry matchPair, Invocation invocation) {
- try {
- // split the rule
- String key = matchPair.getKey();
- String[] expressArray = key.split("\\.");
- String argumentExpress = expressArray[0];
- final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);
- if (!matcher.find()) {
- return false;
- }
-
- //extract the argument index
- int index = Integer.parseInt(matcher.group(1));
- if (index < 0 || index > invocation.getArguments().length) {
- return false;
- }
-
- //extract the argument value
- Object object = invocation.getArguments()[index];
-
- if (matchPair.getValue().isMatch(String.valueOf(object), null)) {
- return true;
- }
- } catch (Exception e) {
- logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e);
- }
-
- return false;
- }
-
- protected static final class MatchPair {
- final Set matches = new HashSet();
- final Set mismatches = new HashSet();
-
- private boolean isMatch(String value, URL param) {
- if (!matches.isEmpty() && mismatches.isEmpty()) {
- for (String match : matches) {
- if (UrlUtils.isMatchGlobPattern(match, value, param)) {
- return true;
- }
- }
- return false;
- }
-
- if (!mismatches.isEmpty() && matches.isEmpty()) {
- for (String mismatch : mismatches) {
- if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
- return false;
- }
- }
- return true;
- }
-
- if (!matches.isEmpty() && !mismatches.isEmpty()) {
- //when both mismatches and matches contain the same value, then using mismatches first
- for (String mismatch : mismatches) {
- if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
- return false;
- }
- }
- for (String match : matches) {
- if (UrlUtils.isMatchGlobPattern(match, value, param)) {
- return true;
- }
- }
- return false;
- }
- return false;
- }
- }
-}
+/*
+ * 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.rpc.cluster.router.condition;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Constants;
+import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
+
+/**
+ * ConditionRouter
+ * It supports the conditional routing configured by "override://", in 2.6.x,
+ * refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ .
+ * For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter}
+ * and {@link org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter}
+ * refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ .
+ */
+public class ConditionRouter extends AbstractRouter {
+ public static final String NAME = "condition";
+
+ private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
+ protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
+ protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
+ protected Map whenCondition;
+ protected Map thenCondition;
+
+ private boolean enabled;
+
+ public ConditionRouter(String rule, boolean force, boolean enabled) {
+ this.force = force;
+ this.enabled = enabled;
+ if (enabled) {
+ this.init(rule);
+ }
+ }
+
+ public ConditionRouter(URL url) {
+ this.url = url;
+ this.priority = url.getParameter(PRIORITY_KEY, 0);
+ this.force = url.getParameter(FORCE_KEY, false);
+ this.enabled = url.getParameter(ENABLED_KEY, true);
+ if (enabled) {
+ init(url.getParameterAndDecoded(RULE_KEY));
+ }
+ }
+
+ public void init(String rule) {
+ try {
+ if (rule == null || rule.trim().length() == 0) {
+ throw new IllegalArgumentException("Illegal route rule!");
+ }
+ rule = rule.replace("consumer.", "").replace("provider.", "");
+ int i = rule.indexOf("=>");
+ String whenRule = i < 0 ? null : rule.substring(0, i).trim();
+ String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
+ Map when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap() : parseRule(whenRule);
+ Map then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
+ // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
+ this.whenCondition = when;
+ this.thenCondition = then;
+ } catch (ParseException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ private static Map parseRule(String rule)
+ throws ParseException {
+ Map condition = new HashMap();
+ if (StringUtils.isBlank(rule)) {
+ return condition;
+ }
+ // Key-Value pair, stores both match and mismatch conditions
+ MatchPair pair = null;
+ // Multiple values
+ Set values = null;
+ final Matcher matcher = ROUTE_PATTERN.matcher(rule);
+ while (matcher.find()) { // Try to match one by one
+ String separator = matcher.group(1);
+ String content = matcher.group(2);
+ // Start part of the condition expression.
+ if (StringUtils.isEmpty(separator)) {
+ pair = new MatchPair();
+ condition.put(content, pair);
+ }
+ // The KV part of the condition expression
+ else if ("&".equals(separator)) {
+ if (condition.get(content) == null) {
+ pair = new MatchPair();
+ condition.put(content, pair);
+ } else {
+ pair = condition.get(content);
+ }
+ }
+ // The Value in the KV part.
+ else if ("=".equals(separator)) {
+ if (pair == null) {
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+ }
+
+ values = pair.matches;
+ values.add(content);
+ }
+ // The Value in the KV part.
+ else if ("!=".equals(separator)) {
+ if (pair == null) {
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+ }
+
+ values = pair.mismatches;
+ values.add(content);
+ }
+ // The Value in the KV part, if Value have more than one items.
+ else if (",".equals(separator)) { // Should be separated by ','
+ if (values == null || values.isEmpty()) {
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+ }
+ values.add(content);
+ } else {
+ throw new ParseException("Illegal route rule \"" + rule
+ + "\", The error char '" + separator + "' at index "
+ + matcher.start() + " before \"" + content + "\".", matcher.start());
+ }
+ }
+ return condition;
+ }
+
+ @Override
+ public List> route(List> invokers, URL url, Invocation invocation)
+ throws RpcException {
+ if (!enabled) {
+ return invokers;
+ }
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return invokers;
+ }
+ try {
+ if (!matchWhen(url, invocation)) {
+ return invokers;
+ }
+ List> result = new ArrayList>();
+ if (thenCondition == null) {
+ logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
+ return result;
+ }
+ for (Invoker invoker : invokers) {
+ if (matchThen(invoker.getUrl(), url)) {
+ result.add(invoker);
+ }
+ }
+ if (!result.isEmpty()) {
+ return result;
+ } else if (force) {
+ logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY));
+ return result;
+ }
+ } catch (Throwable t) {
+ logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
+ }
+ return invokers;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
+// return true;
+ return this.url.getParameter(RUNTIME_KEY, false);
+ }
+
+ @Override
+ public URL getUrl() {
+ return url;
+ }
+
+ boolean matchWhen(URL url, Invocation invocation) {
+ return CollectionUtils.isEmptyMap(whenCondition) || matchCondition(whenCondition, url, null, invocation);
+ }
+
+ private boolean matchThen(URL url, URL param) {
+ return CollectionUtils.isNotEmptyMap(thenCondition) && matchCondition(thenCondition, url, param, null);
+ }
+
+ private boolean matchCondition(Map condition, URL url, URL param, Invocation invocation) {
+ Map sample = url.toMap();
+ boolean result = false;
+ for (Map.Entry matchPair : condition.entrySet()) {
+ String key = matchPair.getKey();
+
+ if (key.startsWith(Constants.ARGUMENTS)) {
+ if (!matchArguments(matchPair, invocation)) {
+ return false;
+ } else {
+ result = true;
+ continue;
+ }
+ }
+
+ String sampleValue;
+ //get real invoked method name from invocation
+ if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) {
+ sampleValue = invocation.getMethodName();
+ } else if (ADDRESS_KEY.equals(key)) {
+ sampleValue = url.getAddress();
+ } else if (HOST_KEY.equals(key)) {
+ sampleValue = url.getHost();
+ } else {
+ sampleValue = sample.get(key);
+ if (sampleValue == null) {
+ sampleValue = sample.get(key);
+ }
+ }
+ if (sampleValue != null) {
+ if (!matchPair.getValue().isMatch(sampleValue, param)) {
+ return false;
+ } else {
+ result = true;
+ }
+ } else {
+ //not pass the condition
+ if (!matchPair.getValue().matches.isEmpty()) {
+ return false;
+ } else {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * analysis the arguments in the rule.
+ * Examples would be like this:
+ * "arguments[0]=1", whenCondition is that the first argument is equal to '1'.
+ * "arguments[1]=a", whenCondition is that the second argument is equal to 'a'.
+ * @param matchPair
+ * @param invocation
+ * @return
+ */
+ public boolean matchArguments(Map.Entry matchPair, Invocation invocation) {
+ try {
+ // split the rule
+ String key = matchPair.getKey();
+ String[] expressArray = key.split("\\.");
+ String argumentExpress = expressArray[0];
+ final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);
+ if (!matcher.find()) {
+ return false;
+ }
+
+ //extract the argument index
+ int index = Integer.parseInt(matcher.group(1));
+ if (index < 0 || index > invocation.getArguments().length) {
+ return false;
+ }
+
+ //extract the argument value
+ Object object = invocation.getArguments()[index];
+
+ if (matchPair.getValue().isMatch(String.valueOf(object), null)) {
+ return true;
+ }
+ } catch (Exception e) {
+ logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e);
+ }
+
+ return false;
+ }
+
+ protected static final class MatchPair {
+ final Set matches = new HashSet();
+ final Set mismatches = new HashSet();
+
+ private boolean isMatch(String value, URL param) {
+ if (!matches.isEmpty() && mismatches.isEmpty()) {
+ for (String match : matches) {
+ if (UrlUtils.isMatchGlobPattern(match, value, param)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (!mismatches.isEmpty() && matches.isEmpty()) {
+ for (String mismatch : mismatches) {
+ if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (!matches.isEmpty() && !mismatches.isEmpty()) {
+ //when both mismatches and matches contain the same value, then using mismatches first
+ for (String mismatch : mismatches) {
+ if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
+ return false;
+ }
+ }
+ for (String match : matches) {
+ if (UrlUtils.isMatchGlobPattern(match, value, param)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
index 7701c4c62e..71df97c1c6 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
@@ -1,36 +1,36 @@
-/*
- * 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.rpc.cluster.router.condition;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Router;
-import org.apache.dubbo.rpc.cluster.RouterFactory;
-
-/**
- * ConditionRouterFactory
- * Load when "override://" is configured {@link ConditionRouter}
- */
-public class ConditionRouterFactory implements RouterFactory {
-
- public static final String NAME = "condition";
-
- @Override
- public Router getRouter(URL url) {
- return new ConditionRouter(url);
- }
-
-}
+/*
+ * 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.rpc.cluster.router.condition;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+
+/**
+ * ConditionRouterFactory
+ * Load when "override://" is configured {@link ConditionRouter}
+ */
+public class ConditionRouterFactory implements RouterFactory {
+
+ public static final String NAME = "condition";
+
+ @Override
+ public Router getRouter(URL url) {
+ return new ConditionRouter(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
index 4c2759689d..f7b1a6e6f0 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
@@ -1,177 +1,177 @@
-/*
- * 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.rpc.cluster.router.script;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
-
-import javax.script.Bindings;
-import javax.script.Compilable;
-import javax.script.CompiledScript;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.CodeSource;
-import java.security.Permissions;
-import java.security.PrivilegedAction;
-import java.security.ProtectionDomain;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_SCRIPT_TYPE_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
-import static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;
-
-/**
- * ScriptRouter
- */
-public class ScriptRouter extends AbstractRouter {
- public static final String NAME = "SCRIPT_ROUTER";
- private static final int SCRIPT_ROUTER_DEFAULT_PRIORITY = 0;
- private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class);
-
- private static final Map ENGINES = new ConcurrentHashMap<>();
-
- private final ScriptEngine engine;
-
- private final String rule;
-
- private CompiledScript function;
-
- private AccessControlContext accessControlContext;
-
- {
- //Just give permission of reflect to access member.
- Permissions perms = new Permissions();
- perms.add(new RuntimePermission("accessDeclaredMembers"));
- // Cast to Certificate[] required because of ambiguity:
- ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
- accessControlContext = new AccessControlContext(new ProtectionDomain[]{domain});
- }
-
- public ScriptRouter(URL url) {
- this.url = url;
- this.priority = url.getParameter(PRIORITY_KEY, SCRIPT_ROUTER_DEFAULT_PRIORITY);
-
- engine = getEngine(url);
- rule = getRule(url);
- try {
- Compilable compilable = (Compilable) engine;
- function = compilable.compile(rule);
- } catch (ScriptException e) {
- logger.error("route error, rule has been ignored. rule: " + rule +
- ", url: " + RpcContext.getServiceContext().getUrl(), e);
- }
- }
-
- /**
- * get rule from url parameters.
- */
- private String getRule(URL url) {
- String vRule = url.getParameterAndDecoded(RULE_KEY);
- if (StringUtils.isEmpty(vRule)) {
- throw new IllegalStateException("route rule can not be empty.");
- }
- return vRule;
- }
-
- /**
- * create ScriptEngine instance by type from url parameters, then cache it
- */
- private ScriptEngine getEngine(URL url) {
- String type = url.getParameter(TYPE_KEY, DEFAULT_SCRIPT_TYPE_KEY);
-
- return ENGINES.computeIfAbsent(type, t -> {
- ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(type);
- if (scriptEngine == null) {
- throw new IllegalStateException("unsupported route engine type: " + type);
- }
- return scriptEngine;
- });
- }
-
- @Override
- public List> route(List> invokers, URL url, Invocation invocation) throws RpcException {
- if (engine == null || function == null) {
- return invokers;
- }
- Bindings bindings = createBindings(invokers, invocation);
- return getRoutedInvokers(AccessController.doPrivileged((PrivilegedAction