Skip to content

Commit

Permalink
增加决策矩阵的单元测试。Excel导入规则时支持复杂对象结构
Browse files Browse the repository at this point in the history
  • Loading branch information
entropy-cloud committed Sep 6, 2023
1 parent ba7aeab commit baa6a94
Show file tree
Hide file tree
Showing 33 changed files with 703 additions and 116 deletions.
26 changes: 25 additions & 1 deletion nop-commons/src/main/java/io/nop/commons/util/StringHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3223,14 +3223,38 @@ private static boolean matchWildcard(CharSequence string, CharSequence pattern,
* @return
*/
@Deterministic
public static String trimSuffix(String str, String suffix) {
public static String removeEnd(String str, String suffix) {
if (str.endsWith(suffix)) {
return str.substring(0, str.length() - suffix.length());
} else {
return str;
}
}

@Deterministic
public static String removeStart(String str, String prefix) {
if (str.startsWith(prefix)) {
return str.substring(prefix.length());
} else {
return str;
}
}

@Deterministic
public static String chompStartChars(String str, String chars) {
if (str == null || str.isEmpty())
return str;
char c = str.charAt(0);
if (chars.indexOf(c) < 0)
return str;
int i = 0;
for (int n = str.length(); i < n; i++) {
if (chars.indexOf(str.charAt(i)) < 0)
break;
}
return str.substring(i);
}

/**
* 将复合属性名a.b.c编码为 a$b$c, 便于前台数据绑定框架使用
*/
Expand Down
7 changes: 7 additions & 0 deletions nop-core/src/main/java/io/nop/core/lang/utils/Underscore.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import io.nop.api.core.annotations.lang.Deterministic;
import io.nop.api.core.convert.ConvertHelper;
import io.nop.api.core.util.Guard;
import io.nop.commons.collections.IKeyedList;
import io.nop.commons.collections.KeyedList;
import io.nop.commons.collections.SafeOrderedComparator;
import io.nop.commons.util.CollectionHelper;
import io.nop.commons.util.MathHelper;
Expand Down Expand Up @@ -725,4 +727,9 @@ public static Map<String, Object> mergeMap(Map<String, Object> mapA, Map<String,
mapA.putAll(mapB);
return mapA;
}

@Deterministic
public static <T> IKeyedList<T> toKeyedList(Collection<T> c, String keyProp){
return KeyedList.fromList(CollectionHelper.toList(c),item-> getFieldValue(item,keyProp));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36256,6 +36256,16 @@
"name": "io.nop.rule.api.beans.RuleKeyBean",
"unsafeAllocated": false
},
{
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
"allPublicConstructors": true,
"allPublicMethods": true,
"fields": [],
"methods": [],
"name": "io.nop.rule.api.beans.RuleLogMessageBean",
"unsafeAllocated": false
},
{
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
Expand Down Expand Up @@ -36317,6 +36327,57 @@
"name": "io.nop.rule.api.beans._gen._RuleKeyBean",
"unsafeAllocated": false
},
{
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
"allPublicConstructors": true,
"allPublicMethods": true,
"fields": [],
"methods": [
{
"name": "getLogTime",
"parameterTypes": []
},
{
"name": "getMessage",
"parameterTypes": []
},
{
"name": "getRuleNodeId",
"parameterTypes": []
},
{
"name": "getRuleNodeLabel",
"parameterTypes": []
},
{
"name": "setLogTime",
"parameterTypes": [
"java.sql.Timestamp"
]
},
{
"name": "setMessage",
"parameterTypes": [
"java.lang.String"
]
},
{
"name": "setRuleNodeId",
"parameterTypes": [
"java.lang.String"
]
},
{
"name": "setRuleNodeLabel",
"parameterTypes": [
"java.lang.String"
]
}
],
"name": "io.nop.rule.api.beans._gen._RuleLogMessageBean",
"unsafeAllocated": false
},
{
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
Expand Down Expand Up @@ -36436,6 +36497,10 @@
"allPublicMethods": true,
"fields": [],
"methods": [
{
"name": "getLogMessages",
"parameterTypes": []
},
{
"name": "getOutputs",
"parameterTypes": []
Expand All @@ -36452,6 +36517,12 @@
"name": "getRuleVersion",
"parameterTypes": []
},
{
"name": "setLogMessages",
"parameterTypes": [
"java.util.List"
]
},
{
"name": "setOutputs",
"parameterTypes": [
Expand Down Expand Up @@ -37144,11 +37215,23 @@
"io.nop.core.context.IServiceContext"
]
},
{
"name": "setLogMessageSaver",
"parameterTypes": [
"io.nop.rule.core.service.IRuleLogMessageSaver"
]
},
{
"name": "setRuleManager",
"parameterTypes": [
"io.nop.rule.core.IRuleManager"
]
},
{
"name": "setSaveLogMessage",
"parameterTypes": [
"boolean"
]
}
],
"name": "io.nop.rule.core.service.impl.RuleServiceImpl",
Expand Down Expand Up @@ -49162,6 +49245,10 @@
"name": "getLayoutMode",
"parameterTypes": []
},
{
"name": "getMessages",
"parameterTypes": []
},
{
"name": "getObjMeta",
"parameterTypes": []
Expand Down Expand Up @@ -49282,6 +49369,10 @@
"name": "hasInitAsyncApi",
"parameterTypes": []
},
{
"name": "hasMessages",
"parameterTypes": []
},
{
"name": "hasRule",
"parameterTypes": [
Expand Down Expand Up @@ -49444,6 +49535,12 @@
"java.lang.String"
]
},
{
"name": "setMessages",
"parameterTypes": [
"java.util.Map"
]
},
{
"name": "setObjMeta",
"parameterTypes": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,12 @@
/nop/rule/model/NopRuleRole/_NopRuleRole.xbiz
/nop/rule/model/NopRuleRole/_NopRuleRole.xmeta
/nop/rule/model/RuleService/RuleKeyBean.xmeta
/nop/rule/model/RuleService/RuleLogMessageBean.xmeta
/nop/rule/model/RuleService/RuleMetaBean.xmeta
/nop/rule/model/RuleService/RuleRequestBean.xmeta
/nop/rule/model/RuleService/RuleResultBean.xmeta
/nop/rule/model/RuleService/_RuleKeyBean.xmeta
/nop/rule/model/RuleService/_RuleLogMessageBean.xmeta
/nop/rule/model/RuleService/_RuleMetaBean.xmeta
/nop/rule/model/RuleService/_RuleRequestBean.xmeta
/nop/rule/model/RuleService/_RuleResultBean.xmeta
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package io.nop.rule.core;

import io.nop.commons.cache.ICache;
import io.nop.core.lang.eval.IEvalScope;
import io.nop.rule.core.model.RuleModel;

import java.util.Map;

public interface IRuleManager {

IRuleRuntime newRuntime(IEvalScope scope);
IRuleRuntime newRuntime(ICache<Object,Object> cache, IEvalScope scope);

default IRuleRuntime newRuntime() {
return newRuntime(null);
}
IRuleRuntime newRuntime();

IExecutableRule getRule(String ruleName, Integer ruleVersion);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package io.nop.rule.core;

import io.nop.api.core.util.Guard;
import io.nop.commons.cache.ICache;
import io.nop.core.context.IEvalContext;
import io.nop.core.lang.eval.IEvalScope;
import io.nop.rule.api.beans.RuleLogMessageBean;
Expand Down Expand Up @@ -66,6 +67,12 @@ default List<Object> getOutputList(String name) {

void setCollectLogMessage(boolean collectLogMessage);

Throwable getException();

void setException(Throwable exception);

ICache<Object,Object> getCache();

static IRuleRuntime fromEvalContext(IEvalContext context) {
if (context instanceof IRuleRuntime)
return (IRuleRuntime) context;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package io.nop.rule.core.execute;

import io.nop.api.core.exceptions.NopException;
import io.nop.core.lang.eval.IEvalAction;
import io.nop.rule.core.IExecutableRule;
import io.nop.rule.core.IRuleRuntime;
import io.nop.rule.core.RuleConstants;

public class DecoratedExecutableRule implements IExecutableRule {
private final IEvalAction beforeExecute;
Expand All @@ -20,13 +20,18 @@ public DecoratedExecutableRule(IEvalAction beforeExecute,

@Override
public boolean execute(IRuleRuntime ruleRt) {
if (beforeExecute != null)
beforeExecute.invoke(ruleRt);
boolean b = rule.execute(ruleRt);
if (afterExecute != null) {
ruleRt.getEvalScope().setLocalValue(RuleConstants.VAR_RULE_MATCH, b);
afterExecute.invoke(ruleRt);
try {
if (beforeExecute != null)
beforeExecute.invoke(ruleRt);
boolean b = rule.execute(ruleRt);
ruleRt.setRuleMatch(b);
return b;
} catch (Exception e) {
ruleRt.setException(e);
if (afterExecute != null) {
afterExecute.invoke(ruleRt);
}
throw NopException.adapt(e);
}
return b;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.nop.rule.core.execute;

import io.nop.api.core.exceptions.NopException;
import io.nop.api.core.util.Guard;
import io.nop.commons.util.StringHelper;
import io.nop.core.reflect.bean.BeanTool;
import io.nop.core.type.IGenericType;
import io.nop.rule.core.IExecutableRule;
import io.nop.rule.core.IRuleRuntime;
import io.nop.rule.core.model.RuleInputDefineModel;

import java.util.List;

import static io.nop.rule.core.RuleErrors.ARG_DISPLAY_NAME;
import static io.nop.rule.core.RuleErrors.ARG_VAR_NAME;
import static io.nop.rule.core.RuleErrors.ERR_RULE_INPUT_VAR_NOT_ALLOW_EMPTY;

public class NormalizeInputExecutableRule implements IExecutableRule {
private final List<RuleInputDefineModel> inputDefines;
private final IExecutableRule rule;

public NormalizeInputExecutableRule(List<RuleInputDefineModel> inputDefines, IExecutableRule rule) {
this.inputDefines = Guard.notEmpty(inputDefines, "inputDefines");
this.rule = rule;
}

@Override
public boolean execute(IRuleRuntime ruleRt) {
for (RuleInputDefineModel inputDefine : inputDefines) {
String name = inputDefine.getName();
Object value = ruleRt.getInput(name);

if (inputDefine.isComputed()) {
// 计算表达式
value = inputDefine.getDefaultExpr() == null ? null : inputDefine.getDefaultExpr().invoke(ruleRt);
} else if (value == null) {
if (inputDefine.getDefaultExpr() != null) {
value = inputDefine.getDefaultExpr().invoke(ruleRt);
}
}

if (inputDefine.isMandatory()) {
if (StringHelper.isEmptyObject(value))
throw new NopException(ERR_RULE_INPUT_VAR_NOT_ALLOW_EMPTY)
.source(inputDefine)
.param(ARG_VAR_NAME, name)
.param(ARG_DISPLAY_NAME, inputDefine.getDisplayName());
}

IGenericType type = inputDefine.getType();
if (type != null && value != null) {
value = BeanTool.castBeanToType(value, type);
}
ruleRt.getEvalScope().setLocalValue(name, value);
}
return rule.execute(ruleRt);
}
}
Loading

0 comments on commit baa6a94

Please sign in to comment.