/*
* Copyright 2011 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.dubbo.governance.web.governance.module.screen;
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 org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.common.utils.CollectionUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.governance.service.ConsumerService;
import com.alibaba.dubbo.governance.service.OwnerService;
import com.alibaba.dubbo.governance.service.ProviderService;
import com.alibaba.dubbo.governance.service.RouteService;
import com.alibaba.dubbo.governance.web.common.module.screen.Restful;
import com.alibaba.dubbo.registry.common.domain.Consumer;
import com.alibaba.dubbo.registry.common.domain.Provider;
import com.alibaba.dubbo.registry.common.domain.Route;
import com.alibaba.dubbo.registry.common.route.ParseUtils;
import com.alibaba.dubbo.registry.common.route.RouteRule;
import com.alibaba.dubbo.registry.common.route.RouteUtils;
import com.alibaba.dubbo.registry.common.util.Tool;
/**
* Providers.
* URI: /services/$service/routes
*
* @author ding.lid
* @author william.liangf
* @author tony.chenl
*/
public class Routes extends Restful {
private static final int MAX_RULE_LENGTH = 1000;
@Autowired
private RouteService routeService;
@Autowired
private ProviderService providerService;
@Autowired
private ConsumerService consumerService;
static String[][] when_names = {
{"method", "method", "unmethod"},
{"consumer.application", "consumerApplication", "unconsumerApplication"},
{"consumer.cluster", "consumerCluster", "unconsumerCluster"},
{"consumer.host", "consumerHost", "unconsumerHost"},
{"consumer.version", "consumerVersion", "unconsumerVersion"},
{"consumer.group", "consumerGroup", "unconsumerGroup"},
};
static String[][] then_names = {
{"provider.application", "providerApplication", "unproviderApplication"},
{"provider.cluster", "providerCluster", "unproviderCluster"}, // 要校验Cluster是否存在
{"provider.host", "providerHost", "unproviderHost"},
{"provider.protocol", "providerProtocol", "unproviderProtocol"},
{"provider.port", "providerPort", "unproviderPort"},
{"provider.version", "providerVersion", "unproviderVersion"},
{"provider.group", "providerGroup", "unproviderGroup"}
};
/**
* 路由模块首页
* @param context
*/
public void index(Map<String, Object> context) {
String service = (String) context.get("service");
String address = (String) context.get("address");
address = Tool.getIP(address);
List<Route> routes;
if (service != null && service.length() > 0
&& address != null && address.length() > 0) {
routes = routeService.findByServiceAndAddress(service, address);
} else if (service != null && service.length() > 0) {
routes = routeService.findByService(service);
} else if (address != null && address.length() > 0) {
routes = routeService.findByAddress(address);
} else {
routes = routeService.findAll();
}
context.put("routes", routes);
}
/**
* 显示路由详细信息
* @param context
*/
public void show(Map<String, Object> context) {
try {
Route route = routeService.findRoute(Long.parseLong((String)context.get("id")));
if (route == null) {
throw new IllegalArgumentException("The route is not existed.");
}
if(route.getService()!=null && !route.getService().isEmpty()){
context.put("service", route.getService());
}
RouteRule routeRule= RouteRule.parse(route);
@SuppressWarnings("unchecked")
Map<String, RouteRule.MatchPair>[] paramArray = new Map[] {
routeRule.getWhenCondition(), routeRule.getThenCondition()};
String[][][] namesArray = new String[][][] {when_names, then_names };
for(int i=0; i<paramArray.length; ++i) {
Map<String, RouteRule.MatchPair> param = paramArray[i];
String[][] names = namesArray[i];
for(String[] name : names) {
RouteRule.MatchPair matchPair = param.get(name[0]);
if(matchPair == null) {
continue;
}
if(!matchPair.getMatches().isEmpty()) {
String m = RouteRule.join(matchPair.getMatches());
context.put(name[1], m);
}
if(!matchPair.getUnmatches().isEmpty()) {
String u = RouteRule.join(matchPair.getUnmatches());
context.put(name[2], u);
}
}
}
context.put("route", route);
context.put("methods", CollectionUtils.sort(new ArrayList<String>(providerService.findMethodsByService(route.getService()))));
} catch (ParseException e) {
e.printStackTrace();
}
}
/**
* 载入新增路由页面
* @param context
*/
public void add(Map<String, Object> context) {
String service = (String)context.get("service");
if (service != null && service.length() > 0 && !service.contains("*")) {
context.put("service", service);
context.put("methods", CollectionUtils.sort(new ArrayList<String>(providerService.findMethodsByService(service))));
} else {
List<String> serviceList = Tool.sortSimpleName(new ArrayList<String>(providerService.findServices()));
context.put("serviceList", serviceList);
}
if(context.get("input") != null) context.put("input", context.get("input"));
}
/**
* 载入修改路由页面
* @param context
*/
public void edit(Map<String, Object> context) {
add(context);
show(context);
}
static void checkService(String service) {
if(service.contains(",")) throw new IllegalStateException("service(" + service + ") contain illegale ','");
String interfaceName = service;
int gi = interfaceName.indexOf("/");
if(gi != -1) interfaceName = interfaceName.substring(gi + 1);
int vi = interfaceName.indexOf(':');
if(vi != -1) interfaceName = interfaceName.substring(0, vi);
if(interfaceName.indexOf('*') != -1 && interfaceName.indexOf('*') != interfaceName.length() -1) {
throw new IllegalStateException("service(" + service + ") only allow 1 *, and must be last char!");
}
}
/**
* 保存路由信息到数据库中
* @param context
* @return
*/
public boolean create(Map<String, Object> context) {
String name = (String)context.get("name");
String service = (String)context.get("service");
if (StringUtils.isNotEmpty(service)
&& StringUtils.isNotEmpty(name)) {
checkService(service);
Map<String, String> when_name2valueList = new HashMap<String, String>();
Map<String, String> notWhen_name2valueList = new HashMap<String, String>();
for(String[] names : when_names) {
when_name2valueList.put(names[0], (String)context.get(names[1]));
notWhen_name2valueList.put(names[0], (String)context.get(names[2])); // value不为null的情况,这里处理,后面会保证
}
Map<String, String> then_name2valueList = new HashMap<String, String>();
Map<String, String> notThen_name2valueList = new HashMap<String, String>();
for(String[] names : then_names) {
then_name2valueList.put(names[0], (String)context.get(names[1]));
notThen_name2valueList.put(names[0], (String)context.get(names[2]));
}
RouteRule routeRule = RouteRule.createFromNameAndValueListString(
when_name2valueList, notWhen_name2valueList,
then_name2valueList, notThen_name2valueList);
if (routeRule.getThenCondition().isEmpty()) {
context.put("message", getMessage("Add route error! then is empty."));
return false;
}
String matchRule = routeRule.getWhenConditionString();
String filterRule = routeRule.getThenConditionString();
//限制表达式的长度
if (matchRule.length() > MAX_RULE_LENGTH) {
context.put("message", getMessage("When rule is too long!"));
return false;
}
if (filterRule.length() > MAX_RULE_LENGTH) {
context.put("message", getMessage("Then rule is too long!"));
return false;
}
Route route = new Route();
route.setService(service);
route.setName(name);
route.setUsername((String)context.get("operator"));
route.setOperator((String)context.get("operatorAddress"));
route.setRule(routeRule.toString());
if (StringUtils.isNotEmpty((String)context.get("priority"))) {
route.setPriority(Integer.parseInt((String)context.get("priority")));
}
routeService.createRoute(route);
}
return true;
}
/**
* 保存更新数据到数据库中
* @param context
* @return
*/
public boolean update(Map<String, Object> context) {
String idStr = (String)context.get("id");
if (idStr != null && idStr.length() > 0 ) {
String[] blacks = (String[])context.get("black");
boolean black = false;
if(blacks != null && blacks.length > 0){
black = true;
}
Route oldRoute = routeService.findRoute(Long.valueOf(idStr));
if(null == oldRoute) {
context.put("message", getMessage("NoSuchRecord"));
return false;
}
//判断参数,拼凑rule
if (StringUtils.isNotEmpty((String)context.get("name"))) {
String service = oldRoute.getService();
if (context.get("operator") == null) {
context.put("message", getMessage("HaveNoServicePrivilege", service));
return false;
}
Map<String, String> when_name2valueList = new HashMap<String, String>();
Map<String, String> notWhen_name2valueList = new HashMap<String, String>();
for(String[] names : when_names) {
when_name2valueList.put(names[0], (String)context.get(names[1]));
notWhen_name2valueList.put(names[0], (String)context.get(names[2])); // value不为null的情况,这里处理,后面会保证
}
Map<String, String> then_name2valueList = new HashMap<String, String>();
Map<String, String> notThen_name2valueList = new HashMap<String, String>();
for(String[] names : then_names) {
then_name2valueList.put(names[0], (String)context.get(names[1]));
notThen_name2valueList.put(names[0], (String)context.get(names[2]));
}
RouteRule routeRule = RouteRule.createFromNameAndValueListString(
when_name2valueList, notWhen_name2valueList,
then_name2valueList, notThen_name2valueList);
RouteRule result = null;
if(black){
RouteRule.MatchPair matchPair = routeRule.getThenCondition().get("black");
Map<String, RouteRule.MatchPair> then = null;
if(null == matchPair) {
matchPair = new RouteRule.MatchPair();
then = new HashMap<String, RouteRule.MatchPair>();
then.put("black", matchPair);
}else{
matchPair.getMatches().clear();
}
matchPair.getMatches().add(String.valueOf(black));
result = RouteRule.copyWithReplace(routeRule, null, then);
}
if(result == null){
result = routeRule;
}
if (result.getThenCondition().isEmpty()) {
context.put("message", getMessage("Update route error! then is empty."));
return false;
}
String matchRule = result.getWhenConditionString();
String filterRule = result.getThenConditionString();
//限制表达式的长度
if (matchRule.length() > MAX_RULE_LENGTH) {
context.put("message", getMessage("When rule is too long!"));
return false;
}
if (filterRule.length() > MAX_RULE_LENGTH) {
context.put("message", getMessage("Then rule is too long!"));
return false;
}
int priority = 0;
if (StringUtils.isNotEmpty((String)context.get("priority"))) {
priority = Integer.parseInt((String)context.get("priority"));
}
Route route = new Route();
route.setRule(result.toString());
route.setService(service);
route.setPriority(priority);
route.setName((String)context.get("name"));
route.setUsername((String)context.get("operator"));
route.setOperator((String)context.get("operatorAddress"));
route.setId(Long.valueOf(idStr));
route.setPriority(Integer.parseInt((String)context.get("priority")));
route.setEnabled(oldRoute.isEnabled());
routeService.updateRoute(route);
Set<String> usernames = new HashSet<String>();
usernames.add((String)context.get("operator"));
usernames.add(route.getUsername());
//RelateUserUtils.addOwnersOfService(usernames, route.getService(), ownerDAO);
Map<String, Object> params = new HashMap<String, Object>();
params.put("action", "update");
params.put("route", route);
} else {
context.put("message", getMessage("MissRequestParameters", "name"));
}
} else {
context.put("message", getMessage("MissRequestParameters", "id"));
}
return true;
}
/**
* 删除指定ID的route规则
* @param ids
* @return
*/
public boolean delete(Long[] ids, Map<String, Object> context) {
for (Long id : ids) {
routeService.deleteRoute(id);
}
return true;
}
/**
* 启用指定ID的route规则(可以批量处理)
* @param ids
* @return
*/
public boolean enable(Long[] ids, Map<String, Object> context) {
for(Long id : ids){
routeService.enableRoute(id);
}
return true;
}
/**
* 禁用指定ID的route规则(可以批量处理)
* @param ids
* @return
*/
public boolean disable(Long[] ids, Map<String, Object> context) {
for(Long id : ids){
routeService.disableRoute(id);
}
return true;
}
/**
* 选择消费者
* @param context
*/
public void routeselect(Map<String, Object> context){
long rid = Long.valueOf((String)context.get("id"));
context.put("id", rid);
Route route = routeService.findRoute(rid);
if (route == null) {
throw new IllegalStateException("Route(id=" + rid + ") is not existed!");
}
context.put("route", route);
// 获取数据
List<Consumer> consumers = consumerService.findByService(route.getService());
context.put("consumers", consumers);
Map<String, Boolean> matchRoute = new HashMap<String, Boolean>();
for(Consumer c : consumers) {
matchRoute.put(c.getAddress(), RouteUtils.matchRoute(c.getAddress(), null, route, null));
}
context.put("matchRoute", matchRoute);
}
public void preview(Map<String, Object> context) throws Exception {
String rid = (String)context.get("id");
String consumerid = (String)context.get("cid");
if(StringUtils.isEmpty(rid)) {
context.put("message", getMessage("MissRequestParameters", "id"));
}
Map<String, String> serviceUrls = new HashMap<String, String>();
Route route = routeService.findRoute(Long.valueOf(rid));
if(null == route) {
context.put("message", getMessage("NoSuchRecord"));
}
List<Provider> providers = providerService.findByService(route.getService());
if (providers != null) {
for (Provider p : providers) {
serviceUrls.put(p.getUrl(), p.getParameters());
}
}
if(StringUtils.isNotEmpty(consumerid)) {
Consumer consumer = consumerService.findConsumer(Long.valueOf(consumerid));
if(null == consumer) {
context.put("message", getMessage("NoSuchRecord"));
}
Map<String, String> result = RouteUtils.previewRoute(consumer.getService(), consumer.getAddress(), consumer.getParameters(), serviceUrls,
route, null, null);
context.put("route", route);
context.put("consumer", consumer);
context.put("result", result);
}
else {
String address = (String)context.get("address");
String service = (String)context.get("service");
Map<String, String> result = RouteUtils.previewRoute(service, address, null, serviceUrls,
route, null, null);
context.put("route", route);
Consumer consumer = new Consumer();
consumer.setService(service);
consumer.setAddress(address);
context.put("consumer", consumer);
context.put("result", result);
}
}
/**
* 添加与服务相关的Owner
*
* @param usernames 用于添加的用户名
* @param serviceName 不含通配符
*/
public static void addOwnersOfService(Set<String> usernames, String serviceName,
OwnerService ownerDAO) {
List<String> serviceNamePatterns = ownerDAO.findAllServiceNames();
for (String p : serviceNamePatterns) {
if (ParseUtils.isMatchGlobPattern(p, serviceName)) {
List<String> list = ownerDAO.findUsernamesByServiceName(p);
usernames.addAll(list);
}
}
}
/**
* 添加与服务模式相关的Owner
*
* @param usernames 用于添加的用户名
* @param serviceNamePattern 服务模式,Glob模式
*/
public static void addOwnersOfServicePattern(Set<String> usernames, String serviceNamePattern,
OwnerService ownerDAO) {
List<String> serviceNamePatterns = ownerDAO.findAllServiceNames();
for (String p : serviceNamePatterns) {
if (ParseUtils.hasIntersection(p, serviceNamePattern)) {
List<String> list = ownerDAO.findUsernamesByServiceName(p);
usernames.addAll(list);
}
}
}
}