diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml
index 42941d4db6..d987afb2bf 100644
--- a/dubbo-cluster/pom.xml
+++ b/dubbo-cluster/pom.xml
@@ -34,5 +34,10 @@
dubbo-rpc-api
${project.parent.version}
+
+ org.apache.dubbo
+ dubbo-config-dynamic
+ ${project.parent.version}
+
\ No newline at end of file
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 47aa2515a3..43410b79ae 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
@@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import java.util.List;
+import java.util.Map;
/**
* Router. (SPI, Prototype, ThreadSafe)
@@ -32,7 +33,6 @@ import java.util.List;
* @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation)
*/
public interface Router extends Comparable {
-
/**
* get the router url.
*
@@ -51,4 +51,20 @@ public interface Router extends Comparable {
*/
List> route(List> invokers, URL url, Invocation invocation) throws RpcException;
+ default Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ return null;
+ }
+
+ default boolean isRuntime() {
+ return true;
+ }
+
+ default String getKey() {
+ return "";
+ }
+
+ default boolean isForce() {
+ return false;
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
new file mode 100644
index 0000000000..dda01954e8
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterChain.java
@@ -0,0 +1,107 @@
+/*
+ * 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 org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.cluster.router.InvokerTreeCache;
+import org.apache.dubbo.rpc.cluster.router.TreeNode;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+public class RouterChain {
+
+ List> fullInvokers;
+
+ private InvokerTreeCache treeCache;
+
+ List routers;
+
+ public static RouterChain buildChain(DynamicConfiguration dynamicConfiguration) {
+ List extensionFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class).getActivateExtension(dynamicConfiguration.getUrl(), (String[]) null);
+ List routers = extensionFactories.stream().map(factory -> factory.getRouter(dynamicConfiguration)).collect(Collectors.toList());
+ return new RouterChain<>(routers);
+ }
+
+ public RouterChain(List routers) {
+ this.routers = routers;
+ }
+
+
+ public void addRouter(Router router) {
+ this.routers.add(router);
+ }
+
+ public void sort() {
+
+ }
+
+ /**
+ * @param methodInvokers
+ * @param url
+ * @param invocation TODO has no been used yet
+ */
+ public void preRoute(Map>> methodInvokers, URL url, Invocation invocation) {
+ if (CollectionUtils.isEmpty(routers)) {
+ return;
+ }
+ TreeNode root = treeCache.buildTree();
+ Router router = routers.get(0);
+ methodInvokers.forEach((method, invokers) -> {
+ TreeNode node = new TreeNode<>("method", method, invokers, true);
+ root.addChild(node);
+ Invocation invocation1 = new RpcInvocation(method, new Class>[0], new Object[0]);
+ routeeee(router, 1, root, router.preRoute(invokers, url, invocation1), url, invocation1);
+ });
+ }
+
+ private void routeeee(Router router, int i, TreeNode parentNode, Map>> invokers, URL url, Invocation invocation) {
+ invokers.forEach((routerValue, list) -> {
+ TreeNode node = new TreeNode<>(router.getKey(), routerValue, list, router.isForce());
+ parentNode.addChild(node);
+ Router nextRouter = routers.get(i);
+ if (CollectionUtils.isNotEmpty(list)) {
+ routeeee(nextRouter, i + 1, node, nextRouter.preRoute(list, url, invocation), url, invocation);
+ }
+ });
+ }
+
+ public List> route(List> invokers, URL url, Invocation invocation) {
+ // TODO will calculate every time
+ List> finalInvokers = treeCache.getInvokers(treeCache.getTree(), url, invocation);
+ for (Router router : routers) {
+ if (router.isRuntime()) {
+ finalInvokers = router.route(finalInvokers, url, invocation);
+ }
+ }
+ return finalInvokers;
+ }
+
+ public void notifyFullInvokers(Map>> invokers, URL url) {
+ preRoute(invokers, url, null);
+ }
+}
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 679b9fe589..287ec7153a 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
@@ -19,6 +19,7 @@ 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.config.dynamic.DynamicConfiguration;
import org.apache.dubbo.rpc.Invocation;
/**
@@ -41,4 +42,7 @@ public interface RouterFactory {
@Adaptive("protocol")
Router getRouter(URL url);
+ default Router getRouter(DynamicConfiguration dynamicConfiguration) {
+ return null;
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
index 085094df22..9bbdcf24cd 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java
@@ -16,9 +16,7 @@
*/
package org.apache.dubbo.rpc.cluster.directory;
-import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.Invocation;
@@ -26,11 +24,9 @@ import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.Router;
-import org.apache.dubbo.rpc.cluster.RouterFactory;
-import org.apache.dubbo.rpc.cluster.router.MockInvokersSelector;
+import org.apache.dubbo.rpc.cluster.RouterChain;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
@@ -48,22 +44,22 @@ public abstract class AbstractDirectory implements Directory {
private volatile URL consumerUrl;
- private volatile List routers;
+ protected RouterChain routerChain;
public AbstractDirectory(URL url) {
this(url, null);
}
- public AbstractDirectory(URL url, List routers) {
- this(url, url, routers);
+ public AbstractDirectory(URL url, RouterChain routerChain) {
+ this(url, url, routerChain);
}
- public AbstractDirectory(URL url, URL consumerUrl, List routers) {
+ public AbstractDirectory(URL url, URL consumerUrl, RouterChain routerChain) {
if (url == null)
throw new IllegalArgumentException("url == null");
this.url = url;
this.consumerUrl = consumerUrl;
- setRouters(routers);
+ setRouterChain(routerChain);
}
@Override
@@ -71,19 +67,16 @@ public abstract class AbstractDirectory implements Directory {
if (destroyed) {
throw new RpcException("Directory already destroyed .url: " + getUrl());
}
+
List> invokers = doList(invocation);
- List localRouters = this.routers; // local reference
- if (localRouters != null && !localRouters.isEmpty()) {
- for (Router router : localRouters) {
- try {
- if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, false)) {
- invokers = router.route(invokers, getConsumerUrl(), invocation);
- }
- } catch (Throwable t) {
- logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
- }
- }
+
+ try {
+ // runtime routers will be executed.
+ routerChain.route(invokers, getConsumerUrl(), invocation);
+ } catch (Throwable t) {
+ logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
}
+
return invokers;
}
@@ -92,23 +85,24 @@ public abstract class AbstractDirectory implements Directory {
return url;
}
- public List getRouters() {
- return routers;
+ public RouterChain getRouterChain() {
+ return routerChain;
}
- protected void setRouters(List routers) {
+ public void setRouterChain(RouterChain routerChain) {
+ this.routerChain = routerChain;
+ }
+
+ protected void addRouters(List routers) {
// copy list
- routers = routers == null ? new ArrayList() : new ArrayList(routers);
- // append url router
- String routerkey = url.getParameter(Constants.ROUTER_KEY);
- if (routerkey != null && routerkey.length() > 0) {
- RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey);
- routers.add(routerFactory.getRouter(url));
- }
- // append mock invoker selector
- routers.add(new MockInvokersSelector());
- Collections.sort(routers);
- this.routers = routers;
+ routers = routers == null ? new ArrayList<>() : new ArrayList<>(routers);
+ routers.forEach(this::addRouter);
+ }
+
+ protected void addRouter(Router router) {
+ routerChain.addRouter(router);
+ // FIXME append mock invoker selector
+// routerChain.add(new MockInvokersSelector());
}
public URL getConsumerUrl() {
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 47a0d12bc7..9367bdf75f 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
@@ -20,13 +20,15 @@ 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 org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterChain;
import java.util.List;
/**
* StaticDirectory
*
+ * FIXME We should add separate router rules for StaticDirectory, not use RouterChain in AbstractDirectory. For example, machineRoom rule only. Ask LVS team for help.
+ *
*/
public class StaticDirectory extends AbstractDirectory {
@@ -36,16 +38,16 @@ public class StaticDirectory extends AbstractDirectory {
this(null, invokers, null);
}
- public StaticDirectory(List> invokers, List routers) {
- this(null, invokers, routers);
+ 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, List routers) {
- super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routers);
+ public StaticDirectory(URL url, List> invokers, RouterChain routerChain) {
+ super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routerChain);
if (invokers == null || invokers.isEmpty())
throw new IllegalArgumentException("invokers == null");
this.invokers = invokers;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java
new file mode 100644
index 0000000000..784dca94b0
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/InvokerTreeCache.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ *
+ */
+public class InvokerTreeCache {
+
+ TreeNode tree;
+
+ public TreeNode buildTree() {
+ tree = new TreeNode<>();
+ return tree;
+ }
+
+ public List> getInvokers(TreeNode node, URL url, Invocation invocation) {
+ if (node.getChildren() == null) {
+ return node.getInvokers();
+ }
+
+ if (tree.getChildren().size() == 1) {
+ return getInvokers(tree.getChildren().get(0), url, invocation);
+ }
+
+ TreeNode failoverNode = null;
+ for (TreeNode n : tree.getChildren()) {
+ String key = n.getConditionKey();
+ if (TreeNode.FAILOVER_KEY.equals(key)) {
+ failoverNode = n;
+ continue;
+ }
+ if (n.getConditionValue().equals(invocation.getAttachment(key, url.getParameter(key)))) {
+ if (n.getInvokers() != null || (n.getInvokers() == null && n.isForce()))
+ return getInvokers(n, url, invocation);
+ }
+ }
+
+ if (failoverNode != null) {
+ return getInvokers(failoverNode, url, invocation);
+ }
+ return Collections.emptyList();
+ }
+
+
+ public TreeNode getTree() {
+ return tree;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
index 0ca2a4997d..f775f899b2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
@@ -18,13 +18,16 @@ package org.apache.dubbo.rpc.cluster.router;
import org.apache.dubbo.common.Constants;
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 org.apache.dubbo.rpc.cluster.Router;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* A specific Router designed to realize mock feature.
@@ -49,6 +52,36 @@ public class MockInvokersSelector implements Router {
return invokers;
}
+ @Override
+ public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ Map>> map = new HashMap<>();
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return map;
+ }
+
+ if (isRuntime()) {
+ map.put(TreeNode.FAILOVER_KEY, invokers);
+ return map;
+ }
+ return map;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ return true;
+ }
+
+ @Override
+ public String getKey() {
+ return TreeNode.FAILOVER_KEY;
+ }
+
+ @Override
+ public boolean isForce() {
+ return false;
+ }
+
private List> getMockedInvokers(final List> invokers) {
if (!hasMockProviders(invokers)) {
return null;
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java
new file mode 100644
index 0000000000..813a0c29f9
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/TreeNode.java
@@ -0,0 +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.router;
+
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class TreeNode {
+ public static final String FAILOVER_KEY = "failover";
+
+ private String conditionKey;
+ private String conditionValue;
+ private boolean force;
+ private List> invokers;
+ private List> children;
+
+ public TreeNode() {
+ this.children = new ArrayList<>();
+ }
+
+ public TreeNode(String conditionKey, String conditionValue, List> invokers, boolean force) {
+ this.conditionKey = conditionKey;
+ this.conditionValue = conditionValue;
+ this.invokers = invokers;
+ this.force = force;
+ this.children = new ArrayList<>();
+ }
+
+ public void traverse() {
+
+ }
+
+ public void addChild(TreeNode child) {
+ children.add(child);
+ }
+
+ public boolean isLeaf() {
+ if (CollectionUtils.isEmpty(children)) {
+ return true;
+ }
+ return false;
+ }
+
+ public String getConditionKey() {
+ return conditionKey;
+ }
+
+ public void setConditionKey(String conditionKey) {
+ this.conditionKey = conditionKey;
+ }
+
+ public String getConditionValue() {
+ return conditionValue;
+ }
+
+ public void setConditionValue(String conditionValue) {
+ this.conditionValue = conditionValue;
+ }
+
+ public List> getInvokers() {
+ return invokers;
+ }
+
+ public void setInvokers(List> invokers) {
+ this.invokers = invokers;
+ }
+
+ public List> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List> children) {
+ this.children = children;
+ }
+
+ public boolean isForce() {
+ return force;
+ }
+
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+}
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 af36757028..a2de676a1f 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
@@ -20,6 +20,7 @@ import org.apache.dubbo.common.Constants;
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;
@@ -27,6 +28,7 @@ import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.router.TreeNode;
import java.text.ParseException;
import java.util.ArrayList;
@@ -45,19 +47,26 @@ import java.util.regex.Pattern;
public class ConditionRouter implements Router, Comparable {
private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
- private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
- private final URL url;
- private final int priority;
- private final boolean force;
- private final Map whenCondition;
- private final Map thenCondition;
+ protected static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
+ protected URL url;
+ protected int priority;
+ protected boolean force;
+ protected Map whenCondition;
+ protected Map thenCondition;
+
+ protected ConditionRouter() {
+
+ }
public ConditionRouter(URL url) {
this.url = url;
this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
this.force = url.getParameter(Constants.FORCE_KEY, false);
+ init(url.getParameterAndDecoded(Constants.RULE_KEY));
+ }
+
+ protected void init(String rule) {
try {
- String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
if (rule == null || rule.trim().length() == 0) {
throw new IllegalArgumentException("Illegal route rule!");
}
@@ -174,6 +183,37 @@ public class ConditionRouter implements Router, Comparable {
return invokers;
}
+ @Override
+ public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ Map>> map = new HashMap<>();
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return map;
+ }
+
+ if (isRuntime()) {
+ map.put(TreeNode.FAILOVER_KEY, invokers);
+ return map;
+ }
+ return map;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ // We always return true for previously defined Router, don't support cache.
+ return this.url.getParameter(Constants.RUNTIME_KEY, false);
+ }
+
+ @Override
+ public String getKey() {
+ return TreeNode.FAILOVER_KEY;
+ }
+
+ @Override
+ public boolean isForce() {
+ return force;
+ }
+
@Override
public URL getUrl() {
return url;
@@ -229,7 +269,7 @@ public class ConditionRouter implements Router, Comparable {
return result;
}
- private static final class MatchPair {
+ protected static final class MatchPair {
final Set matches = new HashSet();
final Set mismatches = new HashSet();
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java
new file mode 100644
index 0000000000..886468f92e
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRouterRule.java
@@ -0,0 +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.router.condition.config;
+
+/**
+ *
+ */
+public class ConditionRouterRule {
+ private String ruleBody;
+ private boolean runtime;
+ private boolean force;
+
+ public String getRuleBody() {
+ return ruleBody;
+ }
+
+ public void setRuleBody(String ruleBody) {
+ this.ruleBody = ruleBody;
+ }
+
+ public boolean isRuntime() {
+ return runtime;
+ }
+
+ public void setRuntime(boolean runtime) {
+ this.runtime = runtime;
+ }
+
+ public boolean isForce() {
+ return force;
+ }
+
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java
new file mode 100644
index 0000000000..db90cc7152
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConditionRuleParser.java
@@ -0,0 +1,30 @@
+/*
+ * 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.config;
+
+/**
+ *
+ */
+public class ConditionRuleParser {
+
+ public static ConditionRouterRule parse(String rawRule) {
+ ConditionRouterRule conditionRouterRule = new ConditionRouterRule();
+ conditionRouterRule.setRuleBody("host!=10.20.153.10,10.20.153.11=>");
+ return conditionRouterRule;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java
new file mode 100644
index 0000000000..846e560698
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouter.java
@@ -0,0 +1,102 @@
+/*
+ * 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.config;
+
+import org.apache.dubbo.common.Constants;
+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.config.dynamic.ConfigChangeEvent;
+import org.apache.dubbo.config.dynamic.ConfigurationListener;
+import org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.router.TreeNode;
+import org.apache.dubbo.rpc.cluster.router.condition.ConditionRouter;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class ConfigConditionRouter extends ConditionRouter implements ConfigurationListener {
+ private static final Logger logger = LoggerFactory.getLogger(ConfigConditionRouter.class);
+ private DynamicConfiguration configuration;
+ private ConditionRouterRule routerRule;
+
+ public ConfigConditionRouter(URL url) {
+ super(url);
+ }
+
+ public ConfigConditionRouter(DynamicConfiguration configuration) {
+ this.configuration = configuration;
+ this.priority = -2;
+ this.force = false;
+ try {
+ String app = configuration.getUrl().getParameter(Constants.APPLICATION_KEY);
+ String rawRule = configuration.getConfig(app + Constants.ROUTERS_SUFFIX, "dubbo", this);
+ ConditionRouterRule routerRule = ConditionRuleParser.parse(rawRule);
+ init(routerRule.getRuleBody());
+ } catch (Exception e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public void process(ConfigChangeEvent event) {
+ String rawRule = event.getNewValue();
+ ConditionRouterRule routerRule = ConditionRuleParser.parse(rawRule);
+ init(routerRule.getRuleBody());
+ }
+
+ @Override
+ public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ Map>> map = new HashMap<>();
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return map;
+ }
+
+ if (isRuntime()) {
+ map.put(TreeNode.FAILOVER_KEY, invokers);
+ return map;
+ }
+
+ map.put(TreeNode.FAILOVER_KEY, route(invokers, url, invocation));
+
+ return map;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ return routerRule.isRuntime();
+ }
+
+ @Override
+ public String getKey() {
+ return "";
+ }
+
+ @Override
+ public boolean isForce() {
+ return routerRule.isForce();
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java
new file mode 100644
index 0000000000..396b10b242
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ConfigConditionRouterFactory.java
@@ -0,0 +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.router.condition.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+
+/**
+ *
+ */
+@Activate
+public class ConfigConditionRouterFactory implements RouterFactory {
+ @Override
+ public Router getRouter(URL url) {
+ return null;
+ }
+
+ @Override
+ public Router getRouter(DynamicConfiguration dynamicConfiguration) {
+ return new ConfigConditionRouter(dynamicConfiguration);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java
new file mode 100644
index 0000000000..8508f176dc
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouter.java
@@ -0,0 +1,153 @@
+/*
+ * 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.group;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+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.StringUtils;
+import org.apache.dubbo.config.dynamic.ConfigChangeEvent;
+import org.apache.dubbo.config.dynamic.ConfigurationListener;
+import org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.config.dynamic.DynamicConfigurationFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.router.TreeNode;
+import org.apache.dubbo.rpc.cluster.router.group.model.GroupRouterRule;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+public class GroupRouter implements Router, Comparable, ConfigurationListener {
+ private static final Logger logger = LoggerFactory.getLogger(GroupRouter.class);
+ private static final String GROUPRULE_DATAID = "global.routers";
+ private static final String ROUTE_GROUP = "route.group";
+ private static final String ROUTE_FAILOVER = "route.failover";
+ private int priority;
+ private URL url;
+ private DynamicConfiguration configuration;
+ private GroupRouterRule groupRouterRule;
+
+ public GroupRouter(URL url) {
+ this(ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getAdaptiveExtension().getDynamicConfiguration(url));
+ this.url = url;
+ }
+
+ public GroupRouter(DynamicConfiguration configuration) {
+ this.priority = -1;
+ this.configuration = configuration;
+ init();
+ }
+
+ public void init() {
+ String rawRule = configuration.getConfig(GROUPRULE_DATAID, "dubbo", this);
+ this.groupRouterRule = GroupRuleParser.parse(rawRule);
+ }
+
+ @Override
+ public void process(ConfigChangeEvent event) {
+ String rawRule = event.getNewValue();
+ // remove, set groupRouterRule to null
+ // change, update groupRouterRule
+ }
+
+ @Override
+ public URL getUrl() {
+ return url;
+ }
+
+ @Override
+ public List> route(List> invokers, URL url, Invocation invocation) throws RpcException {
+ if (CollectionUtils.isEmpty(invokers)) {
+ return invokers;
+ }
+ List> result = invokers;
+ String routeGroup = StringUtils.isEmpty(invocation.getAttachment(ROUTE_GROUP)) ? url.getParameter(ROUTE_GROUP) : invocation.getAttachment(ROUTE_GROUP);
+ if (StringUtils.isNotEmpty(routeGroup)) {
+ String providerApp = invokers.get(0).getUrl().getParameter(Constants.APPLICATION_KEY);
+ List ips = groupRouterRule.filter(routeGroup, providerApp);
+ if (CollectionUtils.isNotEmpty(ips)) {
+ result = filterInvoker(invokers, invoker -> ipMatches(invoker.getUrl(), ips));
+ } else {
+ result = filterInvoker(invokers, invoker -> invoker.getUrl().getParameter(ROUTE_GROUP).equals(routeGroup));
+ }
+ }
+ if (StringUtils.isEmpty(routeGroup) || (CollectionUtils.isEmpty(result) && url.getParameter(ROUTE_FAILOVER, true))) {
+ result = filterInvoker(invokers, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(ROUTE_GROUP)));
+ }
+ return result;
+ }
+
+ @Override
+ public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ Map>> map = new HashMap<>();
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return map;
+ }
+
+ if (isRuntime()) {
+ map.put(TreeNode.FAILOVER_KEY, invokers);
+ return map;
+ }
+
+ // FIXME Consider groupRouterRule
+ invokers.forEach(invoker -> {
+ String routeGroup = invoker.getUrl().getParameter(ROUTE_GROUP);
+ List> subInvokers = map.computeIfAbsent(routeGroup, k -> new ArrayList<>());
+ subInvokers.add(invoker);
+ });
+
+ return map;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ return false;
+ }
+
+ public boolean isRuntime(Invocation invocation) {
+ return true;
+ }
+
+ private List> filterInvoker(List> invokers, Predicate> predicate) {
+ return invokers.stream()
+ .filter(predicate)
+ .collect(Collectors.toList());
+ }
+
+ private boolean ipMatches(URL url, List ips) {
+ return ips.contains(url.getHost());
+ }
+
+ @Override
+ public int compareTo(Router o) {
+ return 0;
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java
new file mode 100644
index 0000000000..761d02e922
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRouterFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.group;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.config.dynamic.DynamicConfiguration;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+
+/**
+ *
+ */
+@Activate
+public class GroupRouterFactory implements RouterFactory {
+
+ public static final String NAME = "group";
+
+ @Override
+ public Router getRouter(URL url) {
+ return new GroupRouter(url);
+ }
+
+ public Router getRouter(DynamicConfiguration dynamicConfiguration) {
+ return new GroupRouter(dynamicConfiguration);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java
new file mode 100644
index 0000000000..86569565ed
--- /dev/null
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/GroupRuleParser.java
@@ -0,0 +1,29 @@
+/*
+ * 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.group;
+
+import org.apache.dubbo.rpc.cluster.router.group.model.GroupRouterRule;
+
+/**
+ *
+ */
+public class GroupRuleParser {
+
+ public static GroupRouterRule parse(String rawRule) {
+ return null;
+ }
+}
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java
similarity index 80%
rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java
rename to dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java
index 20621fa9d1..687a3fb945 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/RouterRule.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/group/model/GroupRouterRule.java
@@ -14,11 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.dynamic.parser.model;
+package org.apache.dubbo.rpc.cluster.router.group.model;
+
+import java.util.List;
/**
*
*/
-public class RouterRule {
-
+public class GroupRouterRule {
+ public List filter(String routeGroup, String app) {
+ return null;
+ }
}
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 616432254a..c3f98155f3 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
@@ -20,11 +20,13 @@ import org.apache.dubbo.common.Constants;
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.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.router.TreeNode;
import javax.script.Bindings;
import javax.script.Compilable;
@@ -34,6 +36,7 @@ import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -114,6 +117,37 @@ public class ScriptRouter implements Router {
}
}
+ @Override
+ public Map>> preRoute(List> invokers, URL url, Invocation invocation) throws RpcException {
+ Map>> map = new HashMap<>();
+
+ if (CollectionUtils.isEmpty(invokers)) {
+ return map;
+ }
+
+ if (isRuntime()) {
+ map.put(TreeNode.FAILOVER_KEY, invokers);
+ return map;
+ }
+ return map;
+ }
+
+ @Override
+ public boolean isRuntime() {
+ // ignore config in url
+ return true;
+ }
+
+ @Override
+ public String getKey() {
+ return TreeNode.FAILOVER_KEY;
+ }
+
+ @Override
+ public boolean isForce() {
+ return url.getParameter(Constants.FORCE_KEY, false);
+ }
+
@Override
public int compareTo(Router o) {
if (o == null || o.getClass() != ScriptRouter.class) {
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
index 0ada9c3be9..f8bd6990b5 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
@@ -1,3 +1,5 @@
file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
-condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
\ No newline at end of file
+condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
+configcondition=org.apache.dubbo.rpc.cluster.router.condition.config.ConfigConditionRouterFactory
+group=org.apache.dubbo.rpc.cluster.router.group.GroupRouterFactory
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java
index 941e80cdd1..e596c74b05 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/file/FileRouterEngineTest.java
@@ -27,10 +27,10 @@ import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.RpcResult;
import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance;
+import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.RouterFactory;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
-
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -159,7 +159,8 @@ public class FileRouterEngineTest {
}
private void initDic(URL url) {
- dic = new StaticDirectory(url, invokers, Arrays.asList(routerFactory.getRouter(url)));
+ RouterChain routerChain = new RouterChain(Arrays.asList(routerFactory.getRouter(url)));
+ dic = new StaticDirectory(url, invokers, routerChain);
}
static class MockClusterInvoker extends AbstractClusterInvoker {
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
index 7ddc123eee..8da068df94 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java
@@ -29,14 +29,13 @@ import org.apache.dubbo.config.dynamic.ConfigChangeType;
import org.apache.dubbo.config.dynamic.ConfigType;
import org.apache.dubbo.config.dynamic.ConfigurationListener;
import org.apache.dubbo.config.dynamic.DynamicConfiguration;
-import org.apache.dubbo.config.dynamic.parser.ConfigParser;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.integration.parser.ConfigParser;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
@@ -215,13 +214,10 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
List configuratorUrls = new ArrayList<>();
List dynamicConfiguratorUrls = new ArrayList<>();
List appDynamicConfiguratorUrls = new ArrayList<>();
- List dynamicRouterUrls = new ArrayList<>();
for (URL url : urls) {
String protocol = url.getProtocol();
String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
- if (Constants.DYNAMIC_ROUTERS_CATEGORY.equals(category)) {
- dynamicRouterUrls.add(url);
- } else if (Constants.ROUTERS_CATEGORY.equals(category)
+ if (Constants.ROUTERS_CATEGORY.equals(category)
|| Constants.ROUTE_PROTOCOL.equals(protocol)) {
routerUrls.add(url);
} else if (Constants.DYNAMIC_CONFIGURATORS_CATEGORY.equals(category)) {
@@ -252,9 +248,7 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
// routers
if (!routerUrls.isEmpty()) {
List routers = toRouters(routerUrls);
- if (routers != null) { // null - do nothing
- setRouters(routers);
- }
+ addRouters(routers);
}
List localConfigurators = this.configurators; // local reference
// merge override parameters
@@ -311,6 +305,8 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
}
this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
this.urlInvokerMap = newUrlInvokerMap;
+ // Route and build cache
+ routerChain.notifyFullInvokers(methodInvokerMap, getConsumerUrl());
try {
destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker
} catch (Exception e) {
@@ -511,19 +507,6 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
return providerUrl;
}
- private List> route(List> invokers, String method) {
- Invocation invocation = new RpcInvocation(method, new Class>[0], new Object[0]);
- List routers = getRouters();
- if (routers != null) {
- for (Router router : routers) {
- if (router.getUrl() != null) {
- invokers = router.route(invokers, getConsumerUrl(), invocation);
- }
- }
- }
- return invokers;
- }
-
/**
* Transform the invokers list into a mapping relationship with a method
*
@@ -556,17 +539,7 @@ public class RegistryDirectory extends AbstractDirectory implements Notify
invokersList.add(invoker);
}
}
- List> newInvokersList = route(invokersList, null);
- newMethodInvokerMap.put(Constants.ANY_VALUE, newInvokersList);
- if (serviceMethods != null && serviceMethods.length > 0) {
- for (String method : serviceMethods) {
- List> methodInvokers = newMethodInvokerMap.get(method);
- if (methodInvokers == null || methodInvokers.isEmpty()) {
- methodInvokers = newInvokersList;
- }
- newMethodInvokerMap.put(method, route(methodInvokers, method));
- }
- }
+ newMethodInvokerMap.put(Constants.ANY_VALUE, invokersList);
// sort and unmodifiable
for (String method : new HashSet(newMethodInvokerMap.keySet())) {
List> methodInvokers = newMethodInvokerMap.get(method);
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index 5fe7a27102..8bd469f8b1 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -31,11 +31,11 @@ import org.apache.dubbo.config.dynamic.ConfigType;
import org.apache.dubbo.config.dynamic.ConfigurationListener;
import org.apache.dubbo.config.dynamic.DynamicConfiguration;
import org.apache.dubbo.config.dynamic.DynamicConfigurationFactory;
-import org.apache.dubbo.config.dynamic.parser.ConfigParser;
import org.apache.dubbo.registry.NotifyListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.registry.RegistryFactory;
import org.apache.dubbo.registry.RegistryService;
+import org.apache.dubbo.registry.integration.parser.ConfigParser;
import org.apache.dubbo.registry.support.ProviderConsumerRegTable;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
@@ -44,6 +44,7 @@ import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.protocol.InvokerWrapper;
import java.util.ArrayList;
@@ -350,6 +351,7 @@ public class RegistryProtocol implements Protocol {
directory.setRegistry(registry);
directory.setProtocol(protocol);
directory.setDynamicConfiguration(dynamicConfiguration);
+ directory.setRouterChain(RouterChain.buildChain(dynamicConfiguration));
// all attributes of REFER_KEY
Map parameters = new HashMap(directory.getUrl().getParameters());
URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java
similarity index 96%
rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java
index c8d3246dab..147f45400e 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/ConfigParser.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/ConfigParser.java
@@ -14,14 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.dynamic.parser;
+package org.apache.dubbo.registry.integration.parser;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.config.dynamic.parser.model.ConfigItem;
-import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorConfig;
-import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorRule;
+import org.apache.dubbo.registry.integration.parser.model.ConfigItem;
+import org.apache.dubbo.registry.integration.parser.model.ConfiguratorConfig;
+import org.apache.dubbo.registry.integration.parser.model.ConfiguratorRule;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java
similarity index 96%
rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java
index d65fa1bfb1..71d93c965e 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfigItem.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfigItem.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.dynamic.parser.model;
+package org.apache.dubbo.registry.integration.parser.model;
import java.util.List;
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java
similarity index 96%
rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java
index 18d0ddfac4..db7aab76e1 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorConfig.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorConfig.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.dynamic.parser.model;
+package org.apache.dubbo.registry.integration.parser.model;
import java.util.List;
diff --git a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java
similarity index 96%
rename from dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java
rename to dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java
index a1b540b786..7fbdb87e2c 100644
--- a/dubbo-config/dubbo-config-dynamic/src/main/java/org/apache/dubbo/config/dynamic/parser/model/ConfiguratorRule.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/parser/model/ConfiguratorRule.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config.dynamic.parser.model;
+package org.apache.dubbo.registry.integration.parser.model;
import java.util.Map;
diff --git a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java
similarity index 96%
rename from dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java
rename to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java
index 1962999da2..bb90b9d8a1 100644
--- a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ConfigParserTest.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ConfigParserTest.java
@@ -14,13 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config;
+package org.apache.dubbo.registry;
import org.apache.dubbo.common.Constants;
import org.apache.dubbo.common.URL;
-import org.apache.dubbo.config.dynamic.parser.ConfigParser;
-import org.apache.dubbo.config.dynamic.parser.model.ConfigItem;
-import org.apache.dubbo.config.dynamic.parser.model.ConfiguratorConfig;
+import org.apache.dubbo.registry.integration.parser.ConfigParser;
+import org.apache.dubbo.registry.integration.parser.model.ConfigItem;
+import org.apache.dubbo.registry.integration.parser.model.ConfiguratorConfig;
import org.junit.Assert;
import org.junit.Test;
import org.yaml.snakeyaml.TypeDescription;
diff --git a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
similarity index 99%
rename from dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java
rename to dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
index fa29aba80b..5042068a25 100644
--- a/dubbo-config/dubbo-config-dynamic/src/test/java/org/apache/dubbo/config/ZKTools.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.dubbo.config;
+package org.apache.dubbo.registry;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;