/* * 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); } } } }