From 0cab2240ce6eeea5f511461b4b038ed9ce2b3750 Mon Sep 17 00:00:00 2001 From: jiangw <39796328+b6688c@users.noreply.github.com> Date: Sat, 11 Nov 2023 09:24:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=A0=91=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E7=BB=93=E6=9E=84=E5=8F=8A=E5=85=B6=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 + .../tree}/BreadthTraversalMode.java | 11 +- .../tree}/DeepTraversalMode.java | 11 +- .../datastructure/tree/DefaultElement.java | 62 +++++++++ .../datastructure/tree/DefaultExpand.java | 15 +++ .../uno/core/datastructure/tree/Element.java | 124 ++++++++++++++++++ .../uno/core/datastructure/tree/Expand.java | 23 ++++ .../tree}/NoneTraversalMode.java | 4 +- .../core/datastructure/tree}/Traversal.java | 2 +- .../datastructure/tree}/TraversalElement.java | 11 +- .../datastructure/tree}/TraversalMode.java | 2 +- .../core/datastructure/tree/TreeSupport.java | 102 ++++++++++++++ .../uno/core/datastructure/tree}/Visitor.java | 2 +- .../cc/allio/uno/core/util/ClassUtils.java | 43 +++--- .../util/template/ExpressionTemplate.java | 28 +--- .../datastructure/tree/TreeSupportTest.java | 29 ++++ .../uno/rule/api/vistor/AttrElement.java | 44 ++++++- .../api/vistor/DefaultCompilationRule.java | 24 ++-- .../cc/allio/uno/rule/api/vistor/Element.java | 77 ----------- .../uno/rule/api/vistor/GroupElement.java | 4 +- .../uno/rule/api/vistor/LiteralElement.java | 20 +++ .../api/vistor/LiteralTraversalElement.java | 6 + .../allio/uno/rule/api/vistor/LogicGroup.java | 93 ++++++++----- .../uno/rule/drools/DroolsRuleManager.java | 4 + .../visitor/DefaultCompilationRuleTest.java | 2 +- 25 files changed, 532 insertions(+), 213 deletions(-) rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/BreadthTraversalMode.java (74%) rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/DeepTraversalMode.java (73%) create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/NoneTraversalMode.java (77%) rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/Traversal.java (84%) rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/TraversalElement.java (73%) rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/TraversalMode.java (96%) create mode 100644 uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java rename {uno-rule/src/main/java/cc/allio/uno/rule/api/vistor => uno-core/src/main/java/cc/allio/uno/core/datastructure/tree}/Visitor.java (84%) create mode 100644 uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java delete mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java create mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java create mode 100644 uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java diff --git a/pom.xml b/pom.xml index da4808a3..d2bc20de 100644 --- a/pom.xml +++ b/pom.xml @@ -10,12 +10,14 @@ 1.1.5.RELEASE 构建大型应用需要的基本能力 --- all in one https://github.com/b6688c/uno + j.x jiangw1027@gmail.com + uno-bom uno-core diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java similarity index 74% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java index a391583f..0f9f10bd 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/BreadthTraversalMode.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/BreadthTraversalMode.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; import cc.allio.uno.core.util.CollectionUtils; @@ -6,7 +6,7 @@ import java.util.Queue; /** - * 广度优先 + * 树广度优先 * * @author jiangwei * @date 2023/4/27 09:17 @@ -14,9 +14,6 @@ */ public class BreadthTraversalMode implements TraversalMode { - BreadthTraversalMode() { - } - @Override public void doTraversal(TraversalElement e, Visitor visitor) { Queue bfsQueue = new LinkedList<>(); @@ -24,8 +21,8 @@ public void doTraversal(TraversalElement e, Visitor visitor) { while (!bfsQueue.isEmpty()) { TraversalElement element = bfsQueue.poll(); element.doAccept(visitor); - if (CollectionUtils.isNotEmpty(element.getChildrens())) { - element.getChildrens().forEach(bfsQueue::offer); + if (CollectionUtils.isNotEmpty(element.getChildren())) { + element.getChildren().forEach(chd -> bfsQueue.offer((TraversalElement) chd)); } } } diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java similarity index 73% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java index dd70bb15..ae431419 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DeepTraversalMode.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DeepTraversalMode.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; import cc.allio.uno.core.util.CollectionUtils; @@ -15,15 +15,12 @@ */ public class DeepTraversalMode implements TraversalMode { - DeepTraversalMode() { - } - @Override public void doTraversal(TraversalElement e, Visitor visitor) { // 深度优先 Deque dfsStack = new ArrayDeque<>(); dfsStack.push(e); - List childrens = e.getChildrens(); + List childrens = e.getChildren(); deepAccept(childrens, dfsStack); while (!dfsStack.isEmpty()) { TraversalElement element = dfsStack.pollLast(); @@ -31,10 +28,10 @@ public void doTraversal(TraversalElement e, Visitor visitor) { } } - private void deepAccept(List childrens, Deque dfsStack) { + private void deepAccept(List childrens, Deque dfsStack) { if (CollectionUtils.isNotEmpty(childrens)) { childrens.forEach(dfsStack::offerLast); - childrens.forEach(e -> deepAccept(e.getChildrens(), dfsStack)); + childrens.forEach(e -> deepAccept(e.getChildren(), dfsStack)); } } diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java new file mode 100644 index 00000000..c4f17b86 --- /dev/null +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultElement.java @@ -0,0 +1,62 @@ +package cc.allio.uno.core.datastructure.tree; + +import com.google.common.collect.Lists; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; + +import java.io.Serializable; +import java.util.List; + +/** + * 默认树结点 + * + * @author j.x + * @date 2023/11/9 11:36 + * @since 1.1.5 + */ +@Getter +public class DefaultElement extends TraversalElement { + + private final Serializable id; + @Setter + private int depth; + + @Setter + private Element parent; + + private final List children; + + public DefaultElement(@NonNull Serializable id) { + this.id = id; + this.children = Lists.newArrayList(); + } + + public DefaultElement(@NonNull Serializable id, int depth) { + this.id = id; + this.depth = depth; + this.children = Lists.newArrayList(); + } + + @Override + public boolean isLeaf() { + return children.isEmpty(); + } + + @Override + public void setChildren(List children) { + clearChildren(); + this.children.addAll(children); + } + + @Override + public void addChildren(Element element) { + children.add(element); + } + + @Override + public void clearChildren() { + children.clear(); + } + +} diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java new file mode 100644 index 00000000..e3b4f334 --- /dev/null +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/DefaultExpand.java @@ -0,0 +1,15 @@ +package cc.allio.uno.core.datastructure.tree; + +import java.io.Serializable; + +public record DefaultExpand(Serializable id, Serializable parentId) implements Expand { + @Override + public Serializable getId() { + return id; + } + + @Override + public Serializable getParentId() { + return parentId; + } +} diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java new file mode 100644 index 00000000..c9f6aca9 --- /dev/null +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Element.java @@ -0,0 +1,124 @@ +package cc.allio.uno.core.datastructure.tree; + +import cc.allio.uno.core.StringPool; + +import java.io.Serializable; +import java.util.List; + +/** + * 节点类型分为两种: + *
    + *
  • group 节点
  • + *
  • attr 节点
  • + *
+ * + * @author jiangwei + * @date 2023/4/26 11:31 + * @since 1.1.4 + */ +public interface Element extends Serializable { + + Element ROOT_SENTINEL = new DefaultElement(-1, -1); + + /** + * 定义根节点 + */ + int ROOT_NODE = 0; + + /** + * 获取树的标识 + */ + Serializable getId(); + + /** + * 获取节点所在的深度 + * + * @return level + */ + int getDepth(); + + /** + * 设置树的层级 + */ + void setDepth(int depth); + + /** + * 获取当前树的路径 + * + * @return a.b.c以'.'来切分路径标识 + */ + default String getPath() { + return getParent() != null ? getParent().getPath() + StringPool.ORIGIN_DOT + getId() : String.valueOf(getId()); + } + + /** + * 获取父节点 + * + * @return Element + */ + T getParent(); + + /** + * 设置父节点 + * + * @param parent parent node + */ + void setParent(T parent); + + /** + * 是否为根节点 + * + * @return true 是 false 否 + */ + default boolean isRoot() { + return getDepth() == ROOT_NODE; + } + + /** + * 是否为叶子节点 + * + * @return true 是 false 否 + */ + boolean isLeaf(); + + /** + * 获取子节点 + * + * @return element list + */ + List getChildren(); + + /** + * 添加子结点 + */ + void addChildren(T element); + + /** + * 覆盖并设置子结点 + * + * @param children children + */ + void setChildren(List children); + + /** + * 清除children数据 + */ + void clearChildren(); + + /** + * 访问器模式访问每一个节点。默认实现为深度优先原则 + * + * @param visitor visitor + */ + default void accept(Visitor visitor) { + accept(visitor, Traversal.NONE); + } + + /** + * 访问器模式访问每一个节点。默认实现为深度优先原则 + * + * @param visitor visitor + * @param traversal 遍历原则 + */ + void accept(Visitor visitor, Traversal traversal); +} diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java new file mode 100644 index 00000000..2f2c8eb0 --- /dev/null +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Expand.java @@ -0,0 +1,23 @@ +package cc.allio.uno.core.datastructure.tree; + +import java.io.Serializable; + +/** + * 树平展结点 + * + * @author j.x + * @date 2023/11/9 11:32 + * @since 1.1.5 + */ +public interface Expand { + + /** + * 获取当前结点的标识 + */ + Serializable getId(); + + /** + * 获取父节点标识 + */ + Serializable getParentId(); +} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java similarity index 77% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java index c95988d7..5cbe5ae3 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/NoneTraversalMode.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/NoneTraversalMode.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; /** * 优先访问枝干 @@ -14,7 +14,7 @@ public class NoneTraversalMode implements TraversalMode { @Override public void doTraversal(TraversalElement e, Visitor visitor) { e.doAccept(visitor); - e.getChildrens().forEach(c -> c.accept(visitor, getMode())); + e.getChildren().forEach(c -> c.accept(visitor, getMode())); } @Override diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java similarity index 84% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java index 8736863b..a6cec248 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Traversal.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Traversal.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; /** * 规则树遍历方式 diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java similarity index 73% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java index 025681ed..c489d14c 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalElement.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalElement.java @@ -1,6 +1,4 @@ -package cc.allio.uno.rule.api.vistor; - -import java.util.*; +package cc.allio.uno.core.datastructure.tree; /** * 遍历元素原则实现.{@link Traversal} @@ -16,13 +14,6 @@ public void accept(Visitor visitor, Traversal traversal) { TraversalMode.get(traversal).doTraversal(this, visitor); } - /** - * 获取子节点 - * - * @return element list - */ - protected abstract List getChildrens(); - /** * 子类可以继承实现,默认调用访问访问当前元数据 * diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java similarity index 96% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java index 2d2f70fe..36a218e4 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/TraversalMode.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TraversalMode.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; import cc.allio.uno.core.exception.Exceptions; diff --git a/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java new file mode 100644 index 00000000..9b9385bd --- /dev/null +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/TreeSupport.java @@ -0,0 +1,102 @@ +package cc.allio.uno.core.datastructure.tree; + +import com.google.common.collect.Lists; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 提供树相关操作 + * + * @author j.x + * @date 2023/11/9 11:34 + * @since 1.1.5 + */ +public class TreeSupport { + + + /** + * @see #treeify(List, Function) + */ + public static List treeify(List expandTrees) { + return (List) treeify(expandTrees, e -> new DefaultElement(e.getId())); + } + + /** + * 把平展的树转换为具有层次性的树。 + *

算法明细如下:

+ *
    + *
  1. 构建已{@link Element#getId()}为key的散列表结构
  2. + *
  3. 循环{@link Expand}列表,每一次循环根据散列表结构找到对应父与当前{@link Element}的结构,然后进行添加
  4. + *
+ *

时间复杂度将会是O(n)

+ * + * @param expandTrees 平展的树 + * @param treeFunc 平展结构转换为树结构 + * @param 继承于{@link Expand}的泛型 + * @param 继承于{@link Element}的泛型 + * @return hierarchy filter expand tree depth == 0的结点 + */ + public static List treeify(List expandTrees, Function treeFunc) { + // transfer expand id must not null + Map idElement = + expandTrees.stream() + .map(treeFunc) + .collect(Collectors.toMap(Element::getId, e -> e)); + + // 已散列表为基础循环设置添加子结点 + for (T e : expandTrees) { + Serializable parentId = e.getParentId(); + R parent = idElement.get(parentId); + if (parent != null) { + Serializable id = e.getId(); + R children = idElement.get(id); + children.setDepth(parent.getDepth() + 1); + parent.addChildren(children); + } + } + + // 返回根结点数据 + return idElement.values() + .stream() + .filter(e -> e.getDepth() == Element.ROOT_NODE) + .toList(); + } + + + /** + * @see #expand(List, Function) + */ + public static List expand(List forest) { + return (List) expand(forest, (r) -> new DefaultExpand(r.getId(), r.getParent() != null ? r.getParent().getId() : null)); + } + + /** + * 把树结构进行平展化。 + *

采取树访问者模式

+ * + * @param forest 树 + * @param expandFunc 树结构展缓为平展结构 + * @param 继承于{@link Expand}的泛型 + * @param 继承于{@link Element}的泛型 + * @return expand + */ + public static List expand(List forest, Function expandFunc) { + List expands = Lists.newArrayList(); + try { + Element.ROOT_SENTINEL.setChildren(forest); + Element.ROOT_SENTINEL.accept(e -> { + // 忽略哨兵结点 + if (!Element.ROOT_SENTINEL.equals(e)) { + expands.add(expandFunc.apply((R) e)); + } + }); + } finally { + Element.ROOT_SENTINEL.clearChildren(); + } + return expands; + } +} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java similarity index 84% rename from uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java rename to uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java index 27a2bea3..7e34a8b2 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Visitor.java +++ b/uno-core/src/main/java/cc/allio/uno/core/datastructure/tree/Visitor.java @@ -1,4 +1,4 @@ -package cc.allio.uno.rule.api.vistor; +package cc.allio.uno.core.datastructure.tree; /** * 树节点访问器 diff --git a/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java b/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java index 62483a6b..1b81ea4a 100644 --- a/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java +++ b/uno-core/src/main/java/cc/allio/uno/core/util/ClassUtils.java @@ -1,6 +1,7 @@ package cc.allio.uno.core.util; import cc.allio.uno.core.StringPool; +import cc.allio.uno.core.exception.Exceptions; import com.google.common.collect.Lists; import lombok.NonNull; import org.springframework.core.annotation.AnnotatedElementUtils; @@ -13,7 +14,6 @@ import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.Collectors; import java.util.stream.Stream; /** @@ -24,10 +24,6 @@ */ public class ClassUtils extends org.springframework.util.ClassUtils { - private ClassUtils() { - - } - /** * 获取class对象只有一个的泛型全限定类名 * @@ -36,13 +32,10 @@ private ClassUtils() { * @return 返回一个泛型对象或者空字符串 * @throws NullPointerException 当class对象没有泛型时抛出异常 */ - public static String getSingleGenericClassName(Class clazz) { - if (clazz == null) { - return ""; - } + public static String getSingleGenericClassName(@NonNull Class clazz) { Type type = clazz.getGenericSuperclass(); - if (type instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); + if (type instanceof ParameterizedType pt) { + Type[] typeArguments = pt.getActualTypeArguments(); if (typeArguments.length == 0) { throw new NullPointerException(String.format("Target %s can't find generic", clazz.getName())); } @@ -62,8 +55,8 @@ public static String[] getMultiGenericClassName(Class clazz) { return new String[0]; } Type type = clazz.getGenericSuperclass(); - if (type instanceof ParameterizedType) { - Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); + if (type instanceof ParameterizedType pt) { + Type[] typeArguments = pt.getActualTypeArguments(); if (typeArguments.length == 0) { throw new NullPointerException(String.format("Target %s can't find generic", clazz.getName())); } @@ -114,8 +107,8 @@ public static Class getSingleActualGenericType(Class clazz) throws ClassNo return e; } }); - if (exceptType instanceof ClassNotFoundException) { - throw new ClassNotFoundException(((ClassNotFoundException) exceptType).getMessage()); + if (exceptType instanceof ClassNotFoundException notfound) { + throw new ClassNotFoundException(notfound.getMessage()); } return (Class) exceptType; } @@ -137,8 +130,8 @@ public static Class[] getMultiActualGenericType(Class clazz) throws ClassN return e; } }); - if (exceptType instanceof ClassNotFoundException) { - throw new ClassNotFoundException(((ClassNotFoundException) exceptType).getMessage()); + if (exceptType instanceof ClassNotFoundException notfound) { + throw new ClassNotFoundException(notfound.getMessage()); } actualTypes.add((Class) exceptType); } @@ -169,7 +162,7 @@ public static Type[] getFieldGenericType(Field field) { public static Class[] objectToClass(Object... args) { return Arrays.stream(args) .map(Object::getClass) - .collect(Collectors.toList()) + .toList() .toArray(new Class[]{}); } @@ -202,16 +195,17 @@ public static Method getMethod(Class clazz, String targetMethodName, Class try { method = clazz.getDeclaredMethod(targetMethodName, argsClass); } catch (NoSuchMethodException e2) { - e2.printStackTrace(); + throw Exceptions.unchecked(e2); } } if (method == null) { Set allMethods = new HashSet<>(); allMethods.addAll(Arrays.asList(clazz.getMethods())); allMethods.addAll(Arrays.asList(clazz.getDeclaredMethods())); - List targetMethods = allMethods.stream() - .filter(m -> targetMethodName.equals(m.getName()) && argsClass.length == m.getParameterCount()) - .collect(Collectors.toList()); + List targetMethods = + allMethods.stream() + .filter(m -> targetMethodName.equals(m.getName()) && argsClass.length == m.getParameterCount()) + .toList(); if (CollectionUtils.isNotEmpty(targetMethods)) { method = targetMethods.get(0); } @@ -285,7 +279,7 @@ public static void setAccessible(Field field, boolean flag) { * @return true 存在 false 不存在 * @deprecated 1.1.4版本后删除,使用{@link AnnotatedElementUtils#hasAnnotation(AnnotatedElement, Class)} */ - @Deprecated + @Deprecated(since = "1.1.4", forRemoval = true) public static boolean containsAnnotation(Class instanceClass, Class annotationType) { try { getAnnotation(instanceClass, annotationType); @@ -425,9 +419,6 @@ public static class InstantiationBuilder { private Supplier ifErrorDefaultValue; private boolean isExcludeNull; - InstantiationBuilder() { - } - /** * 添加一个待实例化的Class对象 * diff --git a/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java b/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java index cc960aa8..5c6181f0 100644 --- a/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java +++ b/uno-core/src/main/java/cc/allio/uno/core/util/template/ExpressionTemplate.java @@ -14,7 +14,7 @@ import java.net.URL; import java.util.Collections; import java.util.Map; - + /** * Express模版。基于模版文件解析内容
* @@ -82,32 +82,6 @@ default String parseTemplate(String template, String k1, Object v1, String k2, O return parseTemplate(template, Tuples.of(k1, v1, k2, v2, k3, v3)); } - - /** - * 解析模板。需要指定模板中占位符包含'T1'、'T2'的标识 - * - * @param template 模板 - * @param v1 模板变量v1 - * @param v2 模板变量v2 - * @return 解析完成的字符串 - */ - default String parseTemplate(String template, Object v1, Object v2) { - return parseTemplate(template, Tuples.of("T1", v1, "T2", v2)); - } - - /** - * 解析模板。需要指定模板中占位符包含'T1'、'T2'、'T3'的标识 - * - * @param template 模板 - * @param v1 模板变量v1 - * @param v2 模板变量v2 - * @param v3 模板变量v3 - * @return 解析完成的字符串 - */ - default String parseTemplate(String template, Object v1, Object v2, Object v3) { - return parseTemplate(template, Tuples.of("T1", v1, "T2", v2, "T3", v3)); - } - /** * 解析模板 * diff --git a/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java b/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java new file mode 100644 index 00000000..d6f68795 --- /dev/null +++ b/uno-core/src/test/java/cc/allio/uno/core/datastructure/tree/TreeSupportTest.java @@ -0,0 +1,29 @@ +package cc.allio.uno.core.datastructure.tree; + +import cc.allio.uno.core.BaseTestCase; +import com.google.common.collect.Lists; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class TreeSupportTest extends BaseTestCase { + + static List testData = Lists.newArrayList( + new DefaultExpand(1, 0), + new DefaultExpand(2, 0), + new DefaultExpand(3, 0), + new DefaultExpand(4, 1), + new DefaultExpand(5, 2) + ); + + @Test + void testTreeifyAndExpand() { + List treeify = TreeSupport.treeify(testData); + + assertEquals(3, treeify.size()); + + List expands = TreeSupport.expand(treeify); + + assertEquals(testData.size(), expands.size()); + } +} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java index 76be8f72..4d82edf4 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/AttrElement.java @@ -1,9 +1,13 @@ package cc.allio.uno.rule.api.vistor; +import cc.allio.uno.core.datastructure.tree.Element; +import cc.allio.uno.core.exception.Exceptions; +import cc.allio.uno.core.util.id.IdGenerator; import cc.allio.uno.rule.api.RuleAttr; import lombok.Getter; import lombok.Setter; +import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -15,10 +19,12 @@ * @date 2023/4/26 11:53 * @since 1.1.4 */ -public class AttrElement extends TraversalElement implements Element { +public class AttrElement extends LiteralTraversalElement implements LiteralElement { + + private final Serializable id; @Getter - private final GroupElement parent; + private GroupElement parent; @Getter private final RuleAttr ruleAttr; @@ -27,19 +33,25 @@ public class AttrElement extends TraversalElement implements Element { */ @Setter @Getter - private int level; + private int depth; public AttrElement(GroupElement parent, RuleAttr ruleAttr) { this.parent = parent; this.ruleAttr = ruleAttr; if (parent != null) { - this.level = parent.getLevel() + 1; + this.depth = parent.getDepth() + 1; } + this.id = IdGenerator.defaultGenerator().toHex(); } @Override - public List getChildrens() { - return Collections.emptyList(); + public Serializable getId() { + return id; + } + + @Override + public void setParent(T parent) { + this.parent = (GroupElement) parent; } @Override @@ -47,6 +59,26 @@ public boolean isLeaf() { return true; } + @Override + public List getChildren() { + return Collections.emptyList(); + } + + @Override + public void addChildren(T element) { + Exceptions.eee("AttrElement is leaf element, cannot addChildren", UnsupportedOperationException.class); + } + + @Override + public void setChildren(List children) { + Exceptions.eee("AttrElement is leaf element, cannot setChildren", UnsupportedOperationException.class); + } + + @Override + public void clearChildren() { + Exceptions.eee("AttrElement is leaf element, cannot clearChildren", UnsupportedOperationException.class); + } + @Override public String getLiteral() { return ruleAttr.getIndexExpr(); diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java index 48c87251..0a2dcdd9 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/DefaultCompilationRule.java @@ -1,5 +1,7 @@ package cc.allio.uno.rule.api.vistor; +import cc.allio.uno.core.datastructure.tree.Element; +import cc.allio.uno.core.datastructure.tree.Traversal; import cc.allio.uno.rule.api.LogicPredicate; import cc.allio.uno.rule.api.RuleAttr; import com.google.common.collect.Lists; @@ -15,15 +17,11 @@ */ public class DefaultCompilationRule implements CompilationRule { - DefaultCompilationRule() { - - } - @Override public GroupElement treeifyBin(List ruleItems) { // 根节点为 AND group LogicGroup root = new LogicGroup(null, LogicPredicate.AND); - root.setLevel(Element.ROOT_NODE); + root.setDepth(Element.ROOT_NODE); // 获取第一个节点创建遍历表达式 LogicGroup p = null; for (RuleAttr item : ruleItems) { @@ -46,7 +44,7 @@ public GroupElement treeifyBin(List ruleItems) { } else if (p.getLogic() == LogicPredicate.OR) { if (item.getLogic() == LogicPredicate.AND) { // 放入 and group 中 - List attrElement = p.getAttrElement(); + List attrElement = p.getAttrElement(); p.clearAttrElement(); // 规则项重组为and节点 LogicGroup n = new LogicGroup(p, LogicPredicate.AND); @@ -72,12 +70,12 @@ private void buildTreeLevel(GroupElement root) { int level = Element.ROOT_NODE; Element parent = e.getParent(); if (parent != null) { - level = parent.getLevel() + 1; + level = parent.getDepth() + 1; } - if (e instanceof AttrElement) { - ((AttrElement) e).setLevel(level); - } else if (e instanceof LogicGroup) { - ((LogicGroup) e).setLevel(level); + if (e instanceof AttrElement attr) { + attr.setDepth(level); + } else if (e instanceof LogicGroup logicGroup) { + logicGroup.setDepth(level); } }); } @@ -87,8 +85,8 @@ public List expand(GroupElement tree) { List ruleAttrs = Lists.newArrayList(); tree.accept( e -> { - if (e instanceof AttrElement) { - RuleAttr ruleAttr = ((AttrElement) e).getRuleAttr(); + if (e instanceof AttrElement attr) { + RuleAttr ruleAttr = attr.getRuleAttr(); ruleAttrs.add(ruleAttr); } }, diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java deleted file mode 100644 index 78e3006c..00000000 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/Element.java +++ /dev/null @@ -1,77 +0,0 @@ -package cc.allio.uno.rule.api.vistor; - -import java.io.Serializable; - -/** - * 定义规则树的节点。 - * 节点类型分为两种: - *
    - *
  • group 节点
  • - *
  • attr 节点
  • - *
- * - * @author jiangwei - * @date 2023/4/26 11:31 - * @since 1.1.4 - */ -public interface Element extends Serializable { - - /** - * 定义根节点 - */ - int ROOT_NODE = 0; - - /** - * 获取节点所在的高度 - * - * @return level - */ - int getLevel(); - - /** - * 获取父节点 - * - * @return Element - */ - Element getParent(); - - /** - * 是否为根节点 - * - * @return true 是 false 否 - */ - default boolean isRoot() { - return getLevel() == ROOT_NODE; - } - - /** - * 是否为叶子节点 - * - * @return true 是 false 否 - */ - boolean isLeaf(); - - /** - * 平展开当前规则group 节点规则表达式。 - * - * @return a == '5' && b == '5'... - */ - String getLiteral(); - - /** - * 访问器模式访问每一个节点。默认实现为深度优先原则 - * - * @param visitor visitor - */ - default void accept(Visitor visitor) { - accept(visitor, Traversal.NONE); - } - - /** - * 访问器模式访问每一个节点。默认实现为深度优先原则 - * - * @param visitor visitor - * @param traversal 遍历原则 - */ - void accept(Visitor visitor, Traversal traversal); -} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java index 448ff17f..02ddffd6 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/GroupElement.java @@ -1,5 +1,7 @@ package cc.allio.uno.rule.api.vistor; +import cc.allio.uno.core.datastructure.tree.Element; + import java.util.List; /** @@ -9,7 +11,7 @@ * @date 2023/4/26 12:04 * @since 1.1.4 */ -public interface GroupElement extends Element { +public interface GroupElement extends LiteralElement { /** * 添加子节点元素 diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java new file mode 100644 index 00000000..6c402128 --- /dev/null +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralElement.java @@ -0,0 +1,20 @@ +package cc.allio.uno.rule.api.vistor; + +import cc.allio.uno.core.datastructure.tree.Element; + +/** + * 包含规则表达式的结点 + * + * @author j.x + * @date 2023/11/9 11:07 + * @since 1.1.5 + */ +public interface LiteralElement extends Element { + + /** + * 平展开当前规则group 节点规则表达式。 + * + * @return a == '5' && b == '5'... + */ + String getLiteral(); +} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java new file mode 100644 index 00000000..348bb545 --- /dev/null +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LiteralTraversalElement.java @@ -0,0 +1,6 @@ +package cc.allio.uno.rule.api.vistor; + +import cc.allio.uno.core.datastructure.tree.TraversalElement; + +public abstract class LiteralTraversalElement extends TraversalElement implements LiteralElement { +} diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java index ff8d64c9..ed4f9944 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java +++ b/uno-rule/src/main/java/cc/allio/uno/rule/api/vistor/LogicGroup.java @@ -1,14 +1,16 @@ package cc.allio.uno.rule.api.vistor; import cc.allio.uno.core.StringPool; +import cc.allio.uno.core.datastructure.tree.Element; import cc.allio.uno.core.util.CollectionUtils; +import cc.allio.uno.core.util.id.IdGenerator; import cc.allio.uno.rule.api.LogicPredicate; import com.google.common.collect.Lists; import lombok.Getter; import lombok.Setter; +import java.io.Serializable; import java.util.List; -import java.util.stream.Collectors; /** * logic @@ -17,93 +19,118 @@ * @date 2023/4/26 11:53 * @since 1.1.4 */ -public class LogicGroup extends TraversalElement implements GroupElement { +public class LogicGroup extends LiteralTraversalElement implements GroupElement { + + @Getter + private final Serializable id; @Getter private final LogicPredicate logic; - @Setter + @Getter - private GroupElement parent; - private final List childrens; + private GroupElement parent; + private List children; @Setter @Getter - private int level; + private int depth; - public LogicGroup(GroupElement parent, LogicPredicate logic) { + public LogicGroup(GroupElement parent, LogicPredicate logic) { this.parent = parent; this.logic = logic; - this.childrens = Lists.newArrayList(); + this.children = Lists.newArrayList(); if (parent != null) { - this.level = parent.getLevel() + 1; + this.depth = parent.getDepth() + 1; } + this.id = IdGenerator.defaultGenerator().toHex(); } @Override - public List getChildrens() { - return childrens; + public void setParent(T parent) { + this.parent = (GroupElement) parent; } @Override public boolean isLeaf() { - return childrens.isEmpty(); + return children.isEmpty(); + } + + @Override + public List getChildren() { + return (List) children; + } + + @Override + public void addChildren(T element) { + addElement((LiteralTraversalElement) element); + } + + @Override + public void setChildren(List children) { + clearChildren(); + this.children.addAll(children); + } + + @Override + public void clearChildren() { + children.clear(); } @Override - public boolean addElement(TraversalElement element) { - return childrens.add(element); + public boolean addElement(LiteralTraversalElement element) { + return children.add(element); } @Override - public boolean addElements(List elements) { - return childrens.addAll(elements); + public boolean addElements(List elements) { + return children.addAll(elements); } @Override - public boolean removeElement(TraversalElement element) { - return childrens.remove(element); + public boolean removeElement(LiteralTraversalElement element) { + return children.remove(element); } @Override - public List getGroupElement() { - return childrens.stream() + public List getGroupElement() { + return children.stream() .filter(e -> GroupElement.class.isAssignableFrom(e.getClass())) - .map(TraversalElement.class::cast) - .collect(Collectors.toList()); + .map(LiteralTraversalElement.class::cast) + .toList(); } @Override - public List getAttrElement() { - return childrens.stream() + public List getAttrElement() { + return children.stream() .filter(e -> AttrElement.class.isAssignableFrom(e.getClass())) - .map(AttrElement.class::cast) - .collect(Collectors.toList()); + .map(LiteralTraversalElement.class::cast) + .toList(); } @Override public void clearAttrElement() { - childrens.removeIf(AttrElement.class::isInstance); + children.removeIf(AttrElement.class::isInstance); } @Override public String getLiteral() { - if (isRoot() && CollectionUtils.isNotEmpty(childrens)) { + if (isRoot() && CollectionUtils.isNotEmpty(children)) { // root 节点第一个元素一定时OR - LogicGroup element = (LogicGroup) childrens.get(0); + LogicGroup element = (LogicGroup) children.get(0); return element.getLiteral(); } StringBuilder literalExpr = new StringBuilder(); - for (int i = 0; i < childrens.size(); i++) { - TraversalElement children = childrens.get(i); + for (int i = 0; i < children.size(); i++) { + LiteralTraversalElement children = (LiteralTraversalElement) this.children.get(i); String literal = children.getLiteral(); // 构建 a = xxx && xxx 或者 a = xx && (b = xx) literalExpr.append(literal).append(StringPool.SPACE); - if (i != childrens.size() - 1) { + if (i != this.children.size() - 1) { literalExpr.append(logic.getSm()).append(StringPool.SPACE); } } // 如果只有一个children 则不进行,否则添加 '(' ')' - if (childrens.size() == 1) { + if (children.size() == 1) { return literalExpr.toString(); } literalExpr.insert(0, StringPool.LEFT_BRACKET); diff --git a/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java b/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java index a2e966eb..425968cb 100644 --- a/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java +++ b/uno-rule/src/main/java/cc/allio/uno/rule/drools/DroolsRuleManager.java @@ -1,5 +1,9 @@ package cc.allio.uno.rule.drools; +import cc.allio.uno.core.datastructure.tree.Element; +import cc.allio.uno.rule.api.vistor.GroupElement; +import cc.allio.uno.core.datastructure.tree.Traversal; +import cc.allio.uno.core.datastructure.tree.Visitor; import cc.allio.uno.rule.api.*; import cc.allio.uno.rule.api.event.RuleContext; import cc.allio.uno.rule.api.vistor.*; diff --git a/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java b/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java index bd08c999..3262a89d 100644 --- a/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java +++ b/uno-rule/src/test/java/cc/allio/uno/rule/api/visitor/DefaultCompilationRuleTest.java @@ -2,7 +2,7 @@ import cc.allio.uno.rule.api.vistor.CompilationRule; import cc.allio.uno.rule.api.vistor.GroupElement; -import cc.allio.uno.rule.api.vistor.Traversal; +import cc.allio.uno.core.datastructure.tree.Traversal; import cc.allio.uno.rule.api.LogicPredicate; import cc.allio.uno.rule.api.OP; import cc.allio.uno.rule.api.RuleAttr;