diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/RuleDO.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/RuleDO.java index 22042173a8c1..9c5ea3e939bd 100644 --- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/RuleDO.java +++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/RuleDO.java @@ -24,6 +24,7 @@ import org.apache.shenyu.common.utils.UUIDUtils; import java.sql.Timestamp; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -259,9 +260,10 @@ public static RuleDO buildRuleDO(final RuleDTO ruleDTO) { * @param ruleDO the rule do * @param pluginName the plugin name * @param conditionDataList the condition data list + * @param beforeConditionDataList the before condition data list * @return the rule data */ - public static RuleData transFrom(final RuleDO ruleDO, final String pluginName, final List conditionDataList) { + public static RuleData transFrom(final RuleDO ruleDO, final String pluginName, final List conditionDataList, final List beforeConditionDataList) { return RuleData.builder() .id(ruleDO.getId()) .name(ruleDO.getName()) @@ -273,9 +275,23 @@ public static RuleData transFrom(final RuleDO ruleDO, final String pluginName, f .loged(ruleDO.getLoged()) .handle(ruleDO.getHandle()) .conditionDataList(conditionDataList) + .beforeConditionDataList(beforeConditionDataList) .build(); } + /** + * Trans from rule data. + * + * @param ruleDO the rule do + * @param pluginName the plugin name + * @param conditionDataList the condition data list + * + * @return ruleData + */ + public static RuleData transFrom(final RuleDO ruleDO, final String pluginName, final List conditionDataList) { + return transFrom(ruleDO, pluginName, conditionDataList, Collections.emptyList()); + } + @Override public boolean equals(final Object o) { if (this == o) { diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java index 0c20995e7683..6a01c9a46395 100644 --- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java +++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/RuleServiceImpl.java @@ -152,11 +152,17 @@ public int update(final RuleDTO ruleDTO) { Assert.notNull(before, "the updated rule is not found"); RuleDO ruleDO = RuleDO.buildRuleDO(ruleDTO); final int ruleCount = ruleMapper.updateSelective(ruleDO); + + // need old data for cleaning + final List beforeRuleCondition = ruleConditionMapper.selectByQuery(new RuleConditionQuery(ruleDO.getId())); + //delete rule condition then add ruleConditionMapper.deleteByQuery(new RuleConditionQuery(ruleDO.getId())); + + // insert new condition addCondition(ruleDO, ruleDTO.getRuleConditions()); if (ruleCount > 0) { - ruleEventPublisher.onUpdated(ruleDO, before, ruleDTO.getRuleConditions()); + ruleEventPublisher.onUpdated(ruleDO, before, ruleDTO.getRuleConditions(), beforeRuleCondition); } return ruleCount; } diff --git a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RuleEventPublisher.java b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RuleEventPublisher.java index d163780dcd08..d0ce0ec4a9fe 100644 --- a/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RuleEventPublisher.java +++ b/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/publish/RuleEventPublisher.java @@ -99,12 +99,24 @@ public void onCreated(final RuleDO rule, final List condition) * @param rule rule * @param before before rule * @param condition condition + * @param beforeCondition beforeCondition */ - public void onUpdated(final RuleDO rule, final RuleDO before, final List condition) { + public void onUpdated(final RuleDO rule, final RuleDO before, final List condition, final List beforeCondition) { publish(new RuleUpdatedEvent(rule, before, SessionUtil.visitorName())); - publishEvent(rule, condition); + publishEvent(rule, condition, beforeCondition); } - + + /** + * on rule updated. + * + * @param rule rule + * @param before before rule + * @param condition condition + */ + public void onUpdated(final RuleDO rule, final RuleDO before, final List condition) { + onUpdated(rule, before, condition, Collections.emptyList()); + } + /** * on rule updated. * @@ -176,7 +188,7 @@ public void onRegister(final RuleDO rule, final List condition public void publish(final AdminDataModelChangedEvent event) { publisher.publishEvent(event); } - + private void publishEvent(final RuleDO ruleDO, final List condition) { // publish change event. final RuleData rule = RuleDO.transFrom(ruleDO, @@ -184,4 +196,14 @@ private void publishEvent(final RuleDO ruleDO, final List cond map(condition, ConditionTransfer.INSTANCE::mapToRuleDTO)); publisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, DataEventTypeEnum.UPDATE, Collections.singletonList(rule))); } + + private void publishEvent(final RuleDO ruleDO, final List condition, final List beforeCondition) { + // publish change event. + final RuleData rule = RuleDO.transFrom(ruleDO, + ruleMapper.getPluginNameBySelectorId(ruleDO.getSelectorId()), + map(condition, ConditionTransfer.INSTANCE::mapToRuleDTO), + map(beforeCondition, ConditionTransfer.INSTANCE::mapToRuleDO) + ); + publisher.publishEvent(new DataChangedEvent(ConfigGroupEnum.RULE, DataEventTypeEnum.UPDATE, Collections.singletonList(rule))); + } } diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java index fac2aa053ddf..b6f0391b466f 100644 --- a/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java +++ b/shenyu-common/src/main/java/org/apache/shenyu/common/dto/RuleData.java @@ -53,6 +53,8 @@ public class RuleData { private List conditionDataList; + private List beforeConditionDataList; + /** * no args constructor. */ @@ -75,6 +77,7 @@ private RuleData(final Builder builder) { this.loged = builder.loged; this.handle = builder.handle; this.conditionDataList = builder.conditionDataList; + this.beforeConditionDataList = builder.beforeConditionDataList; } /** @@ -286,6 +289,24 @@ public RuleData setConditionDataList(final List conditionDataList return this; } + /** + * get beforeConditionDataList. + * + * @return beforeConditionDataList + */ + public List getBeforeConditionDataList() { + return beforeConditionDataList; + } + + /** + * set beforeConditionDataList. + * + * @param beforeConditionDataList beforeConditionDataList + */ + public void setBeforeConditionDataList(final List beforeConditionDataList) { + this.beforeConditionDataList = beforeConditionDataList; + } + @Override public boolean equals(final Object o) { if (this == o) { @@ -294,16 +315,23 @@ public boolean equals(final Object o) { if (o == null || getClass() != o.getClass()) { return false; } - RuleData ruleData = (RuleData) o; - return Objects.equals(id, ruleData.id) && Objects.equals(name, ruleData.name) && Objects.equals(pluginName, ruleData.pluginName) - && Objects.equals(selectorId, ruleData.selectorId) && Objects.equals(matchMode, ruleData.matchMode) - && Objects.equals(sort, ruleData.sort) && Objects.equals(enabled, ruleData.enabled) && Objects.equals(loged, ruleData.loged) - && Objects.equals(handle, ruleData.handle) && Objects.equals(conditionDataList, ruleData.conditionDataList); + final RuleData ruleData = (RuleData) o; + return Objects.equals(id, ruleData.id) + && Objects.equals(name, ruleData.name) + && Objects.equals(pluginName, ruleData.pluginName) + && Objects.equals(selectorId, ruleData.selectorId) + && Objects.equals(matchMode, ruleData.matchMode) + && Objects.equals(sort, ruleData.sort) + && Objects.equals(enabled, ruleData.enabled) + && Objects.equals(loged, ruleData.loged) + && Objects.equals(handle, ruleData.handle) + && Objects.equals(conditionDataList, ruleData.conditionDataList) + && Objects.equals(beforeConditionDataList, ruleData.beforeConditionDataList); } @Override public int hashCode() { - return Objects.hash(id, name, pluginName, selectorId, matchMode, sort, enabled, loged, handle, conditionDataList); + return Objects.hash(id, name, pluginName, selectorId, matchMode, sort, enabled, loged, handle, conditionDataList, beforeConditionDataList); } @Override @@ -362,6 +390,9 @@ public static final class Builder { private List conditionDataList; + private List beforeConditionDataList; + + /** * no args constructor. */ @@ -486,5 +517,16 @@ public Builder conditionDataList(final List conditionDataList) { this.conditionDataList = conditionDataList; return this; } + + /** + * build conditionDataList. + * + * @param beforeConditionDataList beforeConditionDataList + * @return this + */ + public Builder beforeConditionDataList(final List beforeConditionDataList) { + this.beforeConditionDataList = beforeConditionDataList; + return this; + } } } diff --git a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RuleTrieEventEnum.java b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RuleTrieEventEnum.java index 3ebc22f38377..81896c1784fa 100644 --- a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RuleTrieEventEnum.java +++ b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/RuleTrieEventEnum.java @@ -27,6 +27,11 @@ public enum RuleTrieEventEnum { */ INSERT, + /** + * Shenyu Trie update event. + */ + UPDATE, + /** * Shenyu Trie remove event. */ diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java index 408a3c432da0..b14f9d0b9e30 100644 --- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java +++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/cache/CommonPluginDataSubscriber.java @@ -205,7 +205,12 @@ private void updateCacheData(@NonNull final T data) { BaseDataCache.getInstance().cacheRuleData(ruleData); Optional.ofNullable(handlerMap.get(ruleData.getPluginName())) .ifPresent(handler -> handler.handlerRule(ruleData)); - eventPublisher.publishEvent(new RuleTrieEvent(RuleTrieEventEnum.INSERT, ruleData)); + if (CollectionUtils.isEmpty(ruleData.getBeforeConditionDataList())) { + eventPublisher.publishEvent(new RuleTrieEvent(RuleTrieEventEnum.INSERT, ruleData)); + } else { + // if has before condition, use upodate + eventPublisher.publishEvent(new RuleTrieEvent(RuleTrieEventEnum.UPDATE, ruleData)); + } } } diff --git a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java index eebbab55449a..591688627b20 100644 --- a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java +++ b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/trie/ShenyuTrieRuleListener.java @@ -38,18 +38,33 @@ public class ShenyuTrieRuleListener implements ApplicationListener conditionDataList = ruleData.getConditionDataList(); List filterConditions = conditionDataList.stream() .filter(conditionData -> ParamTypeEnum.URI.getName().equals(conditionData.getParamType())) .collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(filterConditions)) { List uriPaths = filterConditions.stream().map(ConditionData::getParamValue).collect(Collectors.toList()); + final ShenyuTrie shenyuTrie = SpringBeanUtils.getInstance().getBean(ShenyuTrie.class); switch (eventEnum) { case INSERT: - uriPaths.forEach(path -> SpringBeanUtils.getInstance().getBean(ShenyuTrie.class).putNode(path, ruleData, null)); + uriPaths.forEach(path -> shenyuTrie.putNode(path, ruleData, null)); + break; + case UPDATE: + final List beforeConditionDataList = ruleData.getBeforeConditionDataList(); + List beforeFilterConditions = beforeConditionDataList.stream() + .filter(conditionData -> ParamTypeEnum.URI.getName().equals(conditionData.getParamType())) + .collect(Collectors.toList()); + List beforeUriPaths = beforeFilterConditions.stream().map(ConditionData::getParamValue).collect(Collectors.toList()); + + // old condition remove + beforeUriPaths.forEach(path -> shenyuTrie.remove(path, ruleData.getSelectorId(), ruleData.getId())); + // new condition insert + uriPaths.forEach(path -> shenyuTrie.putNode(path, ruleData, null)); break; case REMOVE: - uriPaths.forEach(path -> SpringBeanUtils.getInstance().getBean(ShenyuTrie.class).remove(path, ruleData.getSelectorId(), ruleData.getId())); + uriPaths.forEach(path -> shenyuTrie.remove(path, ruleData.getSelectorId(), ruleData.getId())); break; default: throw new IllegalStateException("Unexpected value: " + event.getRuleTrieEvent());