Skip to content

Commit

Permalink
DUBBO-970 修改本地路由
Browse files Browse the repository at this point in the history
git-svn-id: http://code.alibabatech.com/svn/dubbo/trunk@1596 1a56cb94-b969-4eaa-88fa-be21384802f2
  • Loading branch information
william.liangf committed Apr 24, 2012
1 parent b8be8dd commit 645e3ce
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 1,427 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ public List<Invoker<T>> list(Invocation invocation) throws RpcException {
List<Router> localRouters = this.routers; // local reference
if (localRouters != null && localRouters.size() > 0) {
for (Router router: localRouters){
try {
invokers = router.route(invokers, getUrl(), invocation);
try {
if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, true)) {
invokers = router.route(invokers, getUrl(), invocation);
}
} catch (Throwable t) {
logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,22 @@
*/
package com.alibaba.dubbo.rpc.cluster.router.condition;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
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 com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.common.utils.UrlUtils;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcException;
Expand All @@ -41,60 +47,180 @@ public class ConditionRouter implements Router, Comparable<Router> {

private final int priority;

private final String rule;

private final URL url;

public URL getUrl() {
return url;
}
private final Map<String, MatchPair> whenCondition;

private final Map<String, MatchPair> thenCondition;

public ConditionRouter(URL url) {
this.url = url;
this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
String r = url.getParameterAndDecoded(Constants.RULE_KEY, "");
this.rule = "service=" + url.getPath() + (r.trim().startsWith("=>") ? "" : "&") + r;
try {
String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
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 : rule.substring(i + 2).trim();
/*if (whenRule == null || whenRule.trim().length() == 0) {
throw new ParseException("Illegal route rule without when express", 0);
}*/
if (thenRule == null || thenRule.trim().length() == 0) {
throw new ParseException("Illegal route rule without then express", 0);
}
Map<String, MatchPair> when = parseRule(whenRule.trim());
Map<String, MatchPair> then = parseRule(thenRule.trim());
// NOTE: When条件是允许为空的,外部业务来保证类似的约束条件
this.whenCondition = when;
this.thenCondition = then;
} catch (ParseException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}

public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation)
throws RpcException {
if (invokers == null || invokers.size() == 0) {
return invokers;
}
Map<String, String> urls = new HashMap<String, String>();
Map<String, Invoker<T>> urlInvokers = new HashMap<String, Invoker<T>>();
for (Invoker<T> invoker : invokers) {
String key = invoker.getUrl().toIdentityString();
String value = invoker.getUrl().toParameterString();
urls.put(key, value);
urlInvokers.put(key, invoker);
}
try {
Map<String, String> routedUrls = RouteUtils.route(null, url.getServiceKey(), url.getAddress(), url.toParameterString(), urls, Arrays.asList(rule), null);
if (routedUrls != null) {
List<Invoker<T>> result = new ArrayList<Invoker<T>>();
for (Map.Entry<String, String> entry : routedUrls.entrySet()) {
Invoker<T> invoker = urlInvokers.get(entry.getKey());
if (invoker != null) {
result.add(invoker);
}
}
if (result.size() > 0) {
return result;
if (! matchWhen(url)) {
return invokers;
}
List<Invoker<T>> result = new ArrayList<Invoker<T>>();
for (Invoker<T> invoker : invokers) {
if (matchThen(invoker.getUrl())) {
result.add(invoker);
}
}
if (result.size() > 0) {
return result;
}
} catch (Throwable t) {
logger.error("Failed to execute condition router rule: " + getUrl() + ", urls: " + urlInvokers.keySet() + ", cause: " + t.getMessage(), t);
logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
}
return invokers;
}

public URL getUrl() {
return url;
}

public int compareTo(Router o) {
if (o == null || o.getClass() != ConditionRouter.class) {
return 1;
}
ConditionRouter c = (ConditionRouter) o;
return this.priority == c.priority ? rule.compareTo(c.rule) : (this.priority > c.priority ? 1 : -1);
return this.priority == c.priority ? url.toFullString().compareTo(c.url.toFullString()) : (this.priority > c.priority ? 1 : -1);
}

}
public boolean matchWhen(URL url) {
return matchCondition(url, whenCondition);
}

public boolean matchThen(URL url) {
return matchCondition(url, thenCondition);
}

private boolean matchCondition(URL url, Map<String, MatchPair> condition) {
Map<String, String> sample = url.toMap();
for (Map.Entry<String, String> entry : sample.entrySet()) {
String key = entry.getKey();
MatchPair pair = condition.get(key);
if (pair != null && ! pair.isMatch(entry.getValue())) {
return false;
}
}
return true;
}

private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");

private static Map<String, MatchPair> parseRule(String rule)
throws ParseException {
Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
if(StringUtils.isBlank(rule)) {
return condition;
}
// 匹配或不匹配Key-Value对
MatchPair pair = null;
// 多个Value值
Set<String> values = null;
final Matcher matcher = ROUTE_PATTERN.matcher(rule);
while (matcher.find()) { // 逐个匹配
String separator = matcher.group(1);
String content = matcher.group(2);
// 表达式开始
if (separator == null || separator.length() == 0) {
pair = new MatchPair();
condition.put(content, pair);
}
// KV开始
else if ("&".equals(separator)) {
if (condition.get(content) == null) {
pair = new MatchPair();
condition.put(content, pair);
} else {
condition.put(content, pair);
}
}
// KV的Value部分开始
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);
}
// KV的Value部分开始
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);
}
// KV的Value部分的多个条目
else if (",".equals(separator)) { // 如果为逗号表示
if (values == null || values.size() == 0)
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;
}

private static final class MatchPair {
final Set<String> matches = new HashSet<String>();
final Set<String> mismatches = new HashSet<String>();
public boolean isMatch(String value) {
for (String match : matches) {
if (! UrlUtils.isMatchGlobPattern(match, value)) {
return false;
}
}
for (String mismatch : mismatches) {
if (UrlUtils.isMatchGlobPattern(mismatch, value)) {
return false;
}
}
return true;
}
}
}
Loading

0 comments on commit 645e3ce

Please sign in to comment.