| /* |
| * 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.admin.common.util; |
| |
| import org.apache.dubbo.admin.model.domain.Route; |
| import org.apache.dubbo.admin.model.dto.AccessDTO; |
| import org.apache.dubbo.admin.model.dto.ConditionRouteDTO; |
| import org.apache.dubbo.admin.model.dto.TagRouteDTO; |
| import org.apache.dubbo.admin.model.store.RoutingRule; |
| import org.apache.dubbo.admin.model.store.TagRoute; |
| import org.apache.dubbo.common.utils.StringUtils; |
| |
| import java.text.ParseException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| /** |
| * Router rule can be divided into two parts, When Condition and Then Condition <br> |
| * When/Then Confition is expressed in a style of (KV) pair, the V part of the condition pair can contain multiple values (a list) <br> |
| * The meaning of Rule: If a request matches When Condition, then use Then Condition to filter providers (only providers match Then Condition will be returned). <br> |
| * The process of using Conditions to match consumers and providers is called `Filter`. |
| * When Condition are used to filter ConsumersController, while Then Condition are used to filter ProvidersController. |
| * RouteUtils performs like this: If a Consumer matches When Condition, then only return the ProvidersController matches Then Condition. This means RouteUtils should be applied to current Consumer and the providers returned are filtered by RouteUtils.<br> |
| * |
| * An example of ConditionRoute Rule:<code> |
| * key1 = value11,value12 & key2 = value21 & key2 != value22 => key3 = value3 & key4 = value41,vlaue42 & key5 !=value51 |
| * </code>。 |
| * The part before <code>=></code> is called When Condition, it's a KV pair; the follower part is Then Condition, also a KV pair. V part in KV can have more than one value, separated by ','<br><br> |
| * |
| * Value object, thread safe. |
| * |
| */ |
| public class RouteUtils { |
| @SuppressWarnings("unchecked") |
| static RouteUtils EMPTY = new RouteUtils(Collections.EMPTY_MAP, Collections.EMPTY_MAP); |
| private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); |
| private static Pattern CONDITION_SEPERATOR = Pattern.compile("(.*)=>(.*)"); |
| private static Pattern VALUE_LIST_SEPARATOR = Pattern.compile("\\s*,\\s*"); |
| final Map<String, MatchPair> whenCondition; |
| final Map<String, MatchPair> thenCondition; |
| private volatile String tostring = null; |
| |
| // FIXME |
| private RouteUtils(Map<String, MatchPair> when, Map<String, MatchPair> then) { |
| for (Map.Entry<String, MatchPair> entry : when.entrySet()) { |
| entry.getValue().freeze(); |
| } |
| for (Map.Entry<String, MatchPair> entry : then.entrySet()) { |
| entry.getValue().freeze(); |
| } |
| |
| // NOTE: Both When Condition and Then Condition can be null |
| this.whenCondition = when; |
| this.thenCondition = then; |
| } |
| |
| public static Map<String, MatchPair> parseRule(String rule) |
| throws ParseException { |
| Map<String, MatchPair> condition = new HashMap<String, MatchPair>(); |
| if (StringUtils.isBlank(rule)) { |
| return condition; |
| } |
| // K-V pair, contains matches part and mismatches part |
| MatchPair pair = null; |
| // V part has multiple values |
| Set<String> values = null; |
| final Matcher matcher = ROUTE_PATTERN.matcher(rule); |
| while (matcher.find()) { // match one by one |
| String separator = matcher.group(1); |
| String content = matcher.group(2); |
| // The expression starts |
| if (separator == null || separator.length() == 0) { |
| pair = new MatchPair(); |
| condition.put(content, pair); |
| } |
| // The KV starts |
| else if ("&".equals(separator)) { |
| if (condition.get(content) == null) { |
| pair = new MatchPair(); |
| condition.put(content, pair); |
| } else { |
| condition.put(content, pair); |
| } |
| |
| } |
| // The Value part of KV starts |
| else if ("=".equals(separator)) { |
| if (pair == null) |
| throw new ParseException("Illegal route rule \"" |
| + rule + "\", The error char '" + separator |
| + "' at index " + matcher.start() + " before \"" |
| + content + "\".", matcher.start()); |
| |
| values = pair.matches; |
| values.add(content); |
| } |
| // The Value part of KV starts |
| 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.unmatches; |
| values.add(content); |
| } |
| // The Value part of KV has multiple values, separated by ',' |
| else if (",".equals(separator)) { // separated by ',' |
| 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; |
| } |
| |
| /** |
| * Parse the RouteUtils as a string into an object. |
| * |
| * @throws ParseException RouteUtils string format is wrong. The following input conditions, RouteUtils are illegal. |
| * <ul> <li> input is <code>null</code>。 |
| * <li> input is "" or " "。 |
| * <li> input Rule doesn't have a When Condition |
| * <li> input Rule doesn't have a Then Condition |
| * </ul> |
| */ |
| public static RouteUtils parse(Route conditionRoute) throws ParseException { |
| if (conditionRoute == null) |
| throw new ParseException("null conditionRoute!", 0); |
| |
| if (conditionRoute.getMatchRule() == null && conditionRoute.getFilterRule() == null) { |
| return parse(conditionRoute.getRule()); |
| } |
| |
| return parse(conditionRoute == null ? null : conditionRoute.getMatchRule(), conditionRoute == null ? null : conditionRoute.getFilterRule()); |
| } |
| |
| public static RouteUtils parse(String whenRule, String thenRule) throws ParseException { |
| /*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()); |
| return new RouteUtils(when, then); |
| } |
| |
| public static RouteUtils parse(String rule) throws ParseException { |
| if (StringUtils.isBlank(rule)) { |
| throw new ParseException("Illegal blank route rule", 0); |
| } |
| |
| final Matcher matcher = CONDITION_SEPERATOR.matcher(rule); |
| if (!matcher.matches()) throw new ParseException("condition seperator => not found!", 0); |
| |
| return parse(matcher.group(1), matcher.group(2)); |
| } |
| |
| /** |
| * @see #parse(String) |
| * @throws RuntimeException This is an wrapper exception for the {@link ParseException} thrown by the {@link #parse (String)} method. |
| */ |
| public static RouteUtils parseQuitely(Route conditionRoute) { |
| try { |
| return parse(conditionRoute); |
| } catch (ParseException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static TagRoute convertTagroutetoStore(TagRouteDTO tagRoute) { |
| TagRoute store = new TagRoute(); |
| store.setKey(tagRoute.getApplication()); |
| store.setEnabled(tagRoute.isEnabled()); |
| store.setForce(tagRoute.isForce()); |
| store.setPriority(tagRoute.getPriority()); |
| store.setRuntime(tagRoute.isRuntime()); |
| store.setTags(tagRoute.getTags()); |
| return store; |
| } |
| |
| public static TagRouteDTO convertTagroutetoDisplay(TagRoute tagRoute) { |
| TagRouteDTO tagRouteDTO = new TagRouteDTO(); |
| tagRouteDTO.setApplication(tagRoute.getKey()); |
| tagRouteDTO.setRuntime(tagRoute.isRuntime()); |
| tagRouteDTO.setPriority(tagRoute.getPriority()); |
| tagRouteDTO.setTags(tagRoute.getTags()); |
| tagRouteDTO.setForce(tagRoute.isForce()); |
| tagRouteDTO.setEnabled(tagRoute.isEnabled()); |
| return tagRouteDTO; |
| } |
| |
| public static RoutingRule insertConditionRule(RoutingRule existRule, ConditionRouteDTO conditionRoute) { |
| if (existRule == null) { |
| existRule = new RoutingRule(); |
| if (StringUtils.isNotEmpty(conditionRoute.getApplication())) { |
| existRule.setKey(conditionRoute.getApplication()); |
| existRule.setScope(Constants.APPLICATION); |
| } else { |
| existRule.setKey(conditionRoute.getService().replace("/", "*")); |
| existRule.setScope(Constants.SERVICE); |
| } |
| } |
| existRule.setConditions(conditionRoute.getConditions()); |
| existRule.setEnabled(conditionRoute.isEnabled()); |
| existRule.setForce(conditionRoute.isForce()); |
| existRule.setRuntime(conditionRoute.isRuntime()); |
| existRule.setPriority(conditionRoute.getPriority()); |
| return existRule; |
| } |
| public static List<String> convertToBlackWhiteList(AccessDTO accessDTO) { |
| if (accessDTO == null) { |
| return null; |
| } |
| |
| Set<String> whiteList = accessDTO.getWhitelist(); |
| Set<String> blackList = accessDTO.getBlacklist(); |
| List<String> conditions = new ArrayList<>(); |
| if (whiteList != null && whiteList.size() > 0) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("host != "); |
| for (String white : whiteList) { |
| sb.append(white).append(","); |
| } |
| sb.deleteCharAt(sb.length() - 1); |
| sb.append(" =>"); |
| conditions.add(sb.toString()); |
| } |
| if (blackList != null && blackList.size() > 0) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("host = "); |
| for (String black : blackList) { |
| sb.append(black).append(","); |
| } |
| sb.deleteCharAt(sb.length() - 1); |
| sb.append(" =>"); |
| conditions.add(sb.toString()); |
| } |
| return conditions; |
| } |
| |
| public static List<String> filterBlackWhiteListFromConditions(List<String> conditions) { |
| List<String> result = new ArrayList<>(); |
| if (conditions == null || conditions.isEmpty()) { |
| return result; |
| } |
| for (String condition : conditions) { |
| if (isBlackList(condition)) { |
| result.add(condition); |
| } else if (isWhiteList(condition)) { |
| result.add(condition); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * the function of "black white" is part of the function of condition route |
| * @param conditions |
| * @return |
| */ |
| public static List<String> filterConditionsExcludeBlackWhiteList(List<String> conditions) { |
| List<String> result = new ArrayList<>(); |
| if (conditions == null || conditions.isEmpty()) { |
| return result; |
| } |
| for (String condition : conditions) { |
| if (!isBlackList(condition) && !isWhiteList(condition)) { |
| result.add(condition); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * the function of "black white" is part of the function of condition route |
| * @param conditions |
| * @return |
| */ |
| public static List<String> filterConditionRuleFromConditions(List<String> conditions) { |
| List<String> result = new ArrayList<>(); |
| if (conditions == null || conditions.isEmpty()) { |
| return result; |
| } |
| for (String condition : conditions) { |
| result.add(condition); |
| } |
| return result; |
| } |
| |
| public static List<String> removeBlackWhiteListRuleFromConditions(List<String> conditions) { |
| List<String> result = new ArrayList<>(); |
| if (conditions == null || conditions.isEmpty()) { |
| return result; |
| } |
| for (String condition : conditions) { |
| if (!isBlackList(condition) && !isWhiteList(condition)) { |
| result.add(condition); |
| } |
| } |
| return result; |
| } |
| |
| public static AccessDTO convertToAccessDTO(List<String> blackWhiteList, String scope, String key) { |
| if (blackWhiteList == null) { |
| return null; |
| } |
| AccessDTO accessDTO = new AccessDTO(); |
| if (scope.equals(Constants.APPLICATION)) { |
| accessDTO.setApplication(key); |
| } else { |
| accessDTO.setService(key); |
| } |
| if (blackWhiteList != null) { |
| for (String condition : blackWhiteList) { |
| if (condition.contains("host != ")) { |
| //white list |
| condition = org.apache.commons.lang3.StringUtils.substringBetween(condition, "host !=", " =>").trim(); |
| accessDTO.setWhitelist(new HashSet<>(Arrays.asList(condition.split(",")))); |
| } |
| if (condition.contains("host = ")) { |
| //black list |
| condition = org.apache.commons.lang3.StringUtils.substringBetween(condition, "host =", " =>").trim(); |
| accessDTO.setBlacklist(new HashSet<>(Arrays.asList(condition.split(",")))); |
| } |
| } |
| } |
| return accessDTO; |
| } |
| |
| public static Route convertAccessDTOtoRoute(AccessDTO accessDTO) { |
| Route route = new Route(); |
| route.setService(accessDTO.getService()); |
| route.setForce(true); |
| route.setFilterRule("false"); |
| route.setEnabled(true); |
| |
| Map<String, RouteUtils.MatchPair> when = new HashMap<>(); |
| RouteUtils.MatchPair matchPair = new RouteUtils.MatchPair(new HashSet<>(), new HashSet<>()); |
| when.put(Route.KEY_CONSUMER_HOST, matchPair); |
| |
| if (accessDTO.getWhitelist() != null) { |
| matchPair.getUnmatches().addAll(accessDTO.getWhitelist()); |
| } |
| if (accessDTO.getBlacklist() != null) { |
| matchPair.getMatches().addAll(accessDTO.getBlacklist()); |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| RouteUtils.contidionToString(sb, when); |
| route.setMatchRule(sb.toString()); |
| return route; |
| } |
| |
| public static ConditionRouteDTO createConditionRouteFromRule(RoutingRule routingRule) { |
| ConditionRouteDTO conditionRouteDTO = new ConditionRouteDTO(); |
| if (Constants.SERVICE.equals(routingRule.getScope())) { |
| conditionRouteDTO.setService(routingRule.getKey()); |
| } else { |
| conditionRouteDTO.setApplication(routingRule.getKey()); |
| } |
| conditionRouteDTO.setConditions(RouteUtils.filterConditionRuleFromConditions(routingRule.getConditions())); |
| conditionRouteDTO.setPriority(routingRule.getPriority()); |
| conditionRouteDTO.setEnabled(routingRule.isEnabled()); |
| conditionRouteDTO.setForce(routingRule.isForce()); |
| conditionRouteDTO.setRuntime(routingRule.isRuntime()); |
| return conditionRouteDTO; |
| } |
| |
| public static Route convertBlackWhiteListtoRoute(List<String> blackWhiteList, String scope, String key) { |
| AccessDTO accessDTO = convertToAccessDTO(blackWhiteList, scope, key); |
| return convertAccessDTOtoRoute(accessDTO); |
| } |
| |
| static Map<String, MatchPair> parseNameAndValueListString2Condition(Map<String, String> params, Map<String, String> notParams) { |
| Map<String, MatchPair> condition = new HashMap<String, MatchPair>(); |
| |
| for (Entry<String, String> entry : params.entrySet()) { |
| String valueListString = entry.getValue(); |
| if (StringUtils.isBlank(valueListString)) { |
| continue; |
| } |
| String[] list = VALUE_LIST_SEPARATOR.split(valueListString); |
| Set<String> set = new HashSet<String>(); |
| for (String item : list) { |
| if (StringUtils.isBlank(item)) { |
| continue; |
| } |
| set.add(item.trim()); |
| } |
| if (set.isEmpty()) { |
| continue; |
| } |
| |
| String key = entry.getKey(); |
| MatchPair matchPair = condition.get(key); |
| if (null == matchPair) { |
| matchPair = new MatchPair(); |
| condition.put(key, matchPair); |
| } |
| |
| matchPair.matches = set; |
| } |
| for (Entry<String, String> entry : notParams.entrySet()) { |
| String valueListString = entry.getValue(); |
| if (StringUtils.isBlank(valueListString)) { |
| continue; |
| } |
| String[] list = VALUE_LIST_SEPARATOR.split(valueListString); |
| Set<String> set = new HashSet<String>(); |
| for (String item : list) { |
| if (StringUtils.isBlank(item)) { |
| continue; |
| } |
| set.add(item.trim()); |
| } |
| if (set.isEmpty()) { |
| continue; |
| } |
| |
| String key = entry.getKey(); |
| MatchPair matchPair = condition.get(key); |
| if (null == matchPair) { |
| matchPair = new MatchPair(); |
| condition.put(key, matchPair); |
| } |
| |
| matchPair.unmatches = set; |
| } |
| |
| return condition; |
| } |
| |
| public static RouteUtils createFromNameAndValueListString(Map<String, String> whenParams, Map<String, String> notWhenParams, |
| Map<String, String> thenParams, Map<String, String> notThenParams) { |
| Map<String, MatchPair> when = parseNameAndValueListString2Condition(whenParams, notWhenParams); |
| Map<String, MatchPair> then = parseNameAndValueListString2Condition(thenParams, notThenParams); |
| |
| return new RouteUtils(when, then); |
| } |
| |
| public static RouteUtils createFromCondition(Map<String, MatchPair> whenCondition, Map<String, MatchPair> thenCondition) { |
| return new RouteUtils(whenCondition, thenCondition); |
| } |
| |
| public static RouteUtils copyWithRemove(RouteUtils copy, Set<String> whenParams, Set<String> thenParams) { |
| Map<String, MatchPair> when = new HashMap<String, MatchPair>(); |
| for (Entry<String, MatchPair> entry : copy.getWhenCondition().entrySet()) { |
| if (whenParams == null || !whenParams.contains(entry.getKey())) { |
| when.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| Map<String, MatchPair> then = new HashMap<String, MatchPair>(); |
| for (Entry<String, MatchPair> entry : copy.getThenCondition().entrySet()) { |
| if (thenParams == null || !thenParams.contains(entry.getKey())) { |
| then.put(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| return new RouteUtils(when, then); |
| } |
| |
| /** |
| * Replace with the new condition value. |
| * |
| * @param copy Replace Base |
| * @param whenCondition WhenCondition to replace, if Base does not have an item, insert it directly. |
| * @param thenCondition ThenCondition to replace, if Base has no items, then insert directly. |
| * @return RouteUtils after replacement |
| */ |
| public static RouteUtils copyWithReplace(RouteUtils copy, Map<String, MatchPair> whenCondition, Map<String, MatchPair> thenCondition) { |
| if (null == copy) { |
| throw new NullPointerException("Argument copy is null!"); |
| } |
| |
| Map<String, MatchPair> when = new HashMap<String, MatchPair>(); |
| when.putAll(copy.getWhenCondition()); |
| if (whenCondition != null) { |
| when.putAll(whenCondition); |
| } |
| |
| Map<String, MatchPair> then = new HashMap<String, MatchPair>(); |
| then.putAll(copy.getThenCondition()); |
| if (thenCondition != null) { |
| then.putAll(thenCondition); |
| } |
| |
| return new RouteUtils(when, then); |
| } |
| |
| // TODO ToString out of the current list is out of order, should we sort? |
| static void join(StringBuilder sb, Set<String> valueSet) { |
| boolean isFirst = true; |
| for (String s : valueSet) { |
| if (isFirst) { |
| isFirst = false; |
| } else { |
| sb.append(","); |
| } |
| |
| sb.append(s); |
| } |
| } |
| |
| /** |
| * Whether the sample passed the conditions. |
| * <p> |
| * If there is a Key in the KV for the sample, there is a corresponding MatchPair, and Value does not pass through MatchPair; {@code false} is returned; otherwise, {@code true} is returned. |
| * |
| * @see MatchPair#pass(String) |
| */ |
| public static boolean matchCondition(Map<String, String> sample, |
| Map<String, MatchPair> condition) { |
| for (Map.Entry<String, String> entry : sample.entrySet()) { |
| String key = entry.getKey(); |
| |
| MatchPair pair = condition.get(key); |
| if (pair != null && !pair.pass(entry.getValue())) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| // FIXME Remove such method calls |
| public static String join(Set<String> valueSet) { |
| StringBuilder sb = new StringBuilder(128); |
| join(sb, valueSet); |
| return sb.toString(); |
| } |
| |
| // TODO At present, the multiple Key of Condition is in disorder. Should we sort it? |
| public static void contidionToString(StringBuilder sb, Map<String, MatchPair> condition) { |
| boolean isFirst = true; |
| for (Entry<String, MatchPair> entry : condition.entrySet()) { |
| String keyName = entry.getKey(); |
| MatchPair p = entry.getValue(); |
| |
| @SuppressWarnings("unchecked") |
| Set<String>[] setArray = new Set[]{p.matches, p.unmatches}; |
| String[] opArray = {" = ", " != "}; |
| |
| for (int i = 0; i < setArray.length; ++i) { |
| if (setArray[i].isEmpty()) { |
| continue; |
| } |
| if (isFirst) { |
| isFirst = false; |
| } else { |
| sb.append(" & "); |
| } |
| |
| sb.append(keyName); |
| sb.append(opArray[i]); |
| join(sb, setArray[i]); |
| } |
| } |
| } |
| |
| |
| public boolean isWhenContainValue(String key, String value) { |
| MatchPair matchPair = whenCondition.get(key); |
| if (null == matchPair) { |
| return false; |
| } |
| |
| return matchPair.containeValue(value); |
| } |
| |
| public boolean isThenContainValue(String key, String value) { |
| MatchPair matchPair = thenCondition.get(key); |
| if (null == matchPair) { |
| return false; |
| } |
| |
| return matchPair.containeValue(value); |
| } |
| |
| public boolean isContainValue(String key, String value) { |
| return isWhenContainValue(key, value) || isThenContainValue(key, value); |
| } |
| |
| public Map<String, MatchPair> getWhenCondition() { |
| return whenCondition; |
| } |
| |
| public Map<String, MatchPair> getThenCondition() { |
| return thenCondition; |
| } |
| |
| public String getWhenConditionString() { |
| StringBuilder sb = new StringBuilder(512); |
| contidionToString(sb, whenCondition); |
| return sb.toString(); |
| } |
| |
| public String getThenConditionString() { |
| StringBuilder sb = new StringBuilder(512); |
| contidionToString(sb, thenCondition); |
| return sb.toString(); |
| } |
| |
| private static boolean isBlackList(String address) { |
| return (address.startsWith("host = ") && address.endsWith(" =>")); |
| } |
| |
| private static boolean isWhiteList(String address) { |
| return (address.startsWith("host != ") && address.endsWith(" =>")); |
| } |
| |
| @Override |
| public String toString() { |
| if (tostring != null) |
| return tostring; |
| StringBuilder sb = new StringBuilder(512); |
| contidionToString(sb, whenCondition); |
| sb.append(" => "); |
| contidionToString(sb, thenCondition); |
| return tostring = sb.toString(); |
| } |
| |
| // Automatic generation with Eclipse |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((thenCondition == null) ? 0 : thenCondition.hashCode()); |
| result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode()); |
| return result; |
| } |
| |
| // Automatic generation with Eclipse |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| RouteUtils other = (RouteUtils) obj; |
| if (thenCondition == null) { |
| if (other.thenCondition != null) |
| return false; |
| } else if (!thenCondition.equals(other.thenCondition)) |
| return false; |
| if (whenCondition == null) { |
| if (other.whenCondition != null) |
| return false; |
| } else if (!whenCondition.equals(other.whenCondition)) |
| return false; |
| return true; |
| } |
| |
| public static class MatchPair { |
| Set<String> matches = new HashSet<String>(); |
| Set<String> unmatches = new HashSet<String>(); |
| private volatile boolean freezed = false; |
| |
| public MatchPair() { |
| } |
| |
| public MatchPair(Set<String> matches, Set<String> unmatches) { |
| if (matches == null || unmatches == null) { |
| throw new IllegalArgumentException("argument of MatchPair is null!"); |
| } |
| |
| this.matches = matches; |
| this.unmatches = unmatches; |
| } |
| |
| public Set<String> getMatches() { |
| return matches; |
| } |
| |
| public Set<String> getUnmatches() { |
| return unmatches; |
| } |
| |
| public MatchPair copy() { |
| MatchPair ret = new MatchPair(); |
| ret.matches.addAll(matches); |
| ret.unmatches.addAll(unmatches); |
| return ret; |
| } |
| |
| void freeze() { |
| if (freezed) return; |
| synchronized (this) { |
| if (freezed) return; |
| matches = Collections.unmodifiableSet(matches); |
| unmatches = Collections.unmodifiableSet(unmatches); |
| } |
| } |
| |
| public boolean containeValue(String value) { |
| return matches.contains(value) || unmatches.contains(value); |
| } |
| |
| /** |
| * Whether a given value is matched by the {@link MatchPair}. |
| * return {@code false}, if |
| * <ol> |
| * <li>value is in unmatches |
| * <li>matches is not null, but value is not in matches. |
| * </ol> |
| * otherwise, return<code>true</code>。 |
| */ |
| public boolean pass(String sample) { |
| if (unmatches.contains(sample)) return false; |
| if (matches.isEmpty()) return true; |
| return matches.contains(sample); |
| } |
| |
| @Override |
| public String toString() { |
| return String.format("{matches=%s,unmatches=%s}", matches.toString(), unmatches.toString()); |
| } |
| |
| // Automatic generation with Eclipse |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((matches == null) ? 0 : matches.hashCode()); |
| result = prime * result + ((unmatches == null) ? 0 : unmatches.hashCode()); |
| return result; |
| } |
| |
| // Automatic generation with Eclipse |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| MatchPair other = (MatchPair) obj; |
| if (matches == null) { |
| if (other.matches != null) |
| return false; |
| } else if (!matches.equals(other.matches)) |
| return false; |
| if (unmatches == null) { |
| if (other.unmatches != null) |
| return false; |
| } else if (!unmatches.equals(other.unmatches)) |
| return false; |
| return true; |
| } |
| } |
| } |