Merge remote-tracking branch 'origin/dev' into dev
# Conflicts: # liteflow-rule-plugin/pom.xml # liteflow-testcase-el/pom.xml
This commit is contained in:
commit
73084b8da3
|
@ -1,5 +1,6 @@
|
|||
package com.yomahub.liteflow.annotation;
|
||||
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
@ -11,4 +12,14 @@ import java.lang.annotation.*;
|
|||
public @interface LiteflowMethod {
|
||||
|
||||
LiteFlowMethodEnum value();
|
||||
|
||||
// 节点ID,用于区分节点
|
||||
// 默认为空 则按照Spring模式下BeanName为准。
|
||||
String nodeId() default "";
|
||||
|
||||
/**
|
||||
* CMP类型定义
|
||||
* @return AnnotationNodeTypeEnum
|
||||
*/
|
||||
AnnotationNodeTypeEnum nodeType() default AnnotationNodeTypeEnum.COMMON;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.lang.annotation.*;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Target({ElementType.TYPE,ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
|
|
|
@ -122,7 +122,7 @@ public class LiteFlowNodeBuilder {
|
|||
FlowBus.addIfScriptNode(this.node.getId(), this.node.getName(), this.node.getScript());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String errMsg = StrUtil.format("An exception occurred while building the node[{}]", this.node.getId());
|
||||
String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(),e.getMessage());
|
||||
LOG.error(errMsg, e);
|
||||
throw new NodeBuildException(errMsg);
|
||||
}
|
||||
|
|
|
@ -6,21 +6,22 @@ import com.ql.util.express.DefaultContext;
|
|||
import com.ql.util.express.ExpressRunner;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.*;
|
||||
import com.yomahub.liteflow.exception.DataNofFoundException;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
import com.yomahub.liteflow.exception.FlowSystemException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import com.yomahub.liteflow.flow.element.condition.FinallyCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.PreCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Chain基于代码形式的组装器
|
||||
* EL表达式规则专属组装器
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
|
@ -41,7 +42,7 @@ public class LiteFlowChainELBuilder {
|
|||
private final List<Condition> finallyConditionList;
|
||||
|
||||
//EL解析引擎
|
||||
private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();;
|
||||
private final static ExpressRunner EXPRESS_RUNNER = new ExpressRunner();
|
||||
|
||||
static {
|
||||
//初始化QLExpress的Runner
|
||||
|
@ -86,13 +87,13 @@ public class LiteFlowChainELBuilder {
|
|||
}
|
||||
|
||||
public LiteFlowChainELBuilder setEL(String elStr) {
|
||||
if (StrUtil.isBlank(elStr)){
|
||||
if (StrUtil.isBlank(elStr)) {
|
||||
String errMsg = StrUtil.format("no conditionList in this chain[{}]", chain.getChainName());
|
||||
throw new FlowSystemException(errMsg);
|
||||
}
|
||||
|
||||
List<String> errorList = new ArrayList<>();
|
||||
try{
|
||||
try {
|
||||
DefaultContext<String, Object> context = new DefaultContext<>();
|
||||
|
||||
//这里一定要先放chain,再放node,因为node优先于chain,所以当重名时,node会覆盖掉chain
|
||||
|
@ -111,8 +112,8 @@ public class LiteFlowChainELBuilder {
|
|||
//为什么只寻找第一层,而不往下寻找了呢?
|
||||
//因为这是一个规范,如果在后面的层级中出现pre和finally,语义上也不好理解,所以pre和finally只能定义在第一层
|
||||
//如果硬是要在后面定义,则执行的时候会忽略,相关代码已做了判断
|
||||
for (Executable executable : condition.getExecutableList()){
|
||||
if (executable instanceof PreCondition){
|
||||
for (Executable executable : condition.getExecutableList()) {
|
||||
if (executable instanceof PreCondition) {
|
||||
this.preConditionList.add((PreCondition) executable);
|
||||
} else if (executable instanceof FinallyCondition) {
|
||||
this.finallyConditionList.add((FinallyCondition) executable);
|
||||
|
@ -122,9 +123,13 @@ public class LiteFlowChainELBuilder {
|
|||
//把主要的condition加入
|
||||
this.conditionList.add(condition);
|
||||
return this;
|
||||
}catch (QLException e){
|
||||
} catch (QLException e) {
|
||||
// EL 底层会包装异常,这里是曲线处理
|
||||
if (Objects.equals(e.getCause().getMessage(), DataNofFoundException.MSG)) {
|
||||
throw new ELParseException(String.format("[node/chain is not exist or node/chain not register]elStr=%s", elStr));
|
||||
}
|
||||
throw new ELParseException(e.getCause().getMessage());
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
throw new ELParseException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class AnyOperator extends BaseOperator {
|
||||
public class AnyOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
|
|
|
@ -15,10 +15,10 @@ import com.yomahub.liteflow.flow.element.condition.IfCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.5
|
||||
*/
|
||||
public class ElifOperator extends BaseOperator {
|
||||
public class ElifOperator extends BaseOperator<IfCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public IfCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqThree(objects);
|
||||
|
||||
//解析caller
|
||||
|
|
|
@ -11,10 +11,10 @@ import com.yomahub.liteflow.flow.element.condition.IfCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.5
|
||||
*/
|
||||
public class ElseOperator extends BaseOperator {
|
||||
public class ElseOperator extends BaseOperator<IfCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public IfCondition build(Object[] objects) throws Exception {
|
||||
// 参数只能是1个,但这里为什么是2个呢?第一个是caller,第二个才是参数
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
|
|
|
@ -12,10 +12,10 @@ import com.yomahub.liteflow.flow.element.condition.FinallyCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class FinallyOperator extends BaseOperator {
|
||||
public class FinallyOperator extends BaseOperator<FinallyCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public FinallyCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
FinallyCondition finallyCondition = new FinallyCondition();
|
||||
|
|
|
@ -13,12 +13,12 @@ import org.slf4j.LoggerFactory;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class IdOperator extends BaseOperator {
|
||||
public class IdOperator extends BaseOperator<Condition> {
|
||||
|
||||
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
Condition condition = OperatorHelper.convert(objects[0], Condition.class);
|
||||
|
|
|
@ -15,10 +15,10 @@ import com.yomahub.liteflow.flow.element.condition.IfCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.5
|
||||
*/
|
||||
public class IfOperator extends BaseOperator {
|
||||
public class IfOperator extends BaseOperator<IfCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public IfCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEq(objects, 2, 3);
|
||||
|
||||
//解析第一个参数
|
||||
|
|
|
@ -11,10 +11,10 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class IgnoreErrorOperator extends BaseOperator {
|
||||
public class IgnoreErrorOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
WhenCondition condition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
|
|
|
@ -16,10 +16,10 @@ import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.3
|
||||
*/
|
||||
public class NodeOperator extends BaseOperator {
|
||||
public class NodeOperator extends BaseOperator<Node> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public Node build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeNeqOne(objects);
|
||||
|
||||
String nodeId;
|
||||
|
|
|
@ -12,10 +12,10 @@ import com.yomahub.liteflow.flow.element.condition.PreCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class PreOperator extends BaseOperator {
|
||||
public class PreOperator extends BaseOperator<PreCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public PreCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
PreCondition preCondition = new PreCondition();
|
||||
|
|
|
@ -14,10 +14,10 @@ import com.yomahub.liteflow.flow.element.condition.SwitchCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class SwitchOperator extends BaseOperator {
|
||||
public class SwitchOperator extends BaseOperator<SwitchCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public SwitchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeNeqOne(objects);
|
||||
|
||||
Node switchNode;
|
||||
|
|
|
@ -12,10 +12,10 @@ import com.yomahub.liteflow.flow.element.Node;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class TagOperator extends BaseOperator {
|
||||
public class TagOperator extends BaseOperator<Node> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public Node build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
Node node = OperatorHelper.convert(objects[0], Node.class);
|
||||
|
|
|
@ -12,10 +12,10 @@ import com.yomahub.liteflow.flow.element.condition.ThenCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class ThenOperator extends BaseOperator {
|
||||
public class ThenOperator extends BaseOperator<ThenCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public ThenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
ThenCondition thenCondition = new ThenCondition();
|
||||
|
|
|
@ -11,10 +11,10 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class ThreadPoolOperator extends BaseOperator {
|
||||
public class ThreadPoolOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
WhenCondition whenCondition = OperatorHelper.convert(objects[0], WhenCondition.class);
|
||||
|
|
|
@ -12,10 +12,10 @@ import com.yomahub.liteflow.flow.element.condition.SwitchCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class ToOperator extends BaseOperator {
|
||||
public class ToOperator extends BaseOperator<SwitchCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public SwitchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtTwo(objects);
|
||||
|
||||
SwitchCondition switchCondition = OperatorHelper.convert(objects[0], SwitchCondition.class);
|
||||
|
|
|
@ -11,10 +11,10 @@ import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
|||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public class WhenOperator extends BaseOperator {
|
||||
public class WhenOperator extends BaseOperator<WhenCondition> {
|
||||
|
||||
@Override
|
||||
public Object buildCondition(Object[] objects) throws Exception {
|
||||
public WhenCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGtZero(objects);
|
||||
|
||||
WhenCondition whenCondition = new WhenCondition();
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.yomahub.liteflow.builder.el.operator.base;
|
|||
import com.ql.util.express.Operator;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
|
||||
/**
|
||||
* BaseOperator 为了强化 executeInner 方法,会捕获抛出的 QLException 错误,输出友好的错误提示
|
||||
|
@ -10,25 +11,27 @@ import com.yomahub.liteflow.exception.ELParseException;
|
|||
* @author gaibu
|
||||
* @since 2.8.6
|
||||
*/
|
||||
public abstract class BaseOperator extends Operator {
|
||||
public abstract class BaseOperator<T extends Executable> extends Operator {
|
||||
|
||||
@Override
|
||||
public Object executeInner(Object[] objects) throws Exception {
|
||||
try {
|
||||
return buildCondition(objects);
|
||||
} catch (QLException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new ELParseException("errors occurred in EL parsing");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public T executeInner(Object[] objects) throws Exception {
|
||||
try {
|
||||
// 检查 node 和 chain 是否已经注册
|
||||
OperatorHelper.checkNodeAndChainExist(objects);
|
||||
return build(objects);
|
||||
} catch (QLException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new ELParseException("errors occurred in EL parsing");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 EL 条件
|
||||
*
|
||||
* @param objects objects
|
||||
* @return Condition
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
public abstract Object buildCondition(Object[] objects) throws Exception;
|
||||
/**
|
||||
* 构建 EL 条件
|
||||
*
|
||||
* @param objects objects
|
||||
* @return Condition
|
||||
* @throws Exception Exception
|
||||
*/
|
||||
public abstract T build(Object[] objects) throws Exception;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package com.yomahub.liteflow.builder.el.operator.base;
|
||||
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.exception.DataNofFoundException;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Operator 常用工具类
|
||||
|
@ -9,121 +12,134 @@ import com.ql.util.express.exception.QLException;
|
|||
*/
|
||||
public class OperatorHelper {
|
||||
|
||||
/**
|
||||
* 检查参数数量,不等于1
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeNeqOne(Object[] objects) throws QLException {
|
||||
checkObjectSizeNeq(objects, 1);
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,不等于1
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeNeqOne(Object[] objects) throws QLException {
|
||||
checkObjectSizeNeq(objects, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,不等于 size
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size 参数数量
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeNeq(Object[] objects, int size) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
if (objects.length != size) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,不等于 size
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size 参数数量
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeNeq(Object[] objects, int size) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
if (objects.length != size) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,大于 0
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeGtZero(Object[] objects) throws QLException {
|
||||
if (objects.length == 0) {
|
||||
throw new QLException("parameter is empty");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,大于 0
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeGtZero(Object[] objects) throws QLException {
|
||||
if (objects.length == 0) {
|
||||
throw new QLException("parameter is empty");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,大于 2
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeGtTwo(Object[] objects) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
if (objects.length <= 1) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,大于 2
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeGtTwo(Object[] objects) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
if (objects.length <= 1) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,等于 2
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEqTwo(Object[] objects) throws QLException {
|
||||
checkObjectSizeEq(objects, 2);
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,等于 2
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEqTwo(Object[] objects) throws QLException {
|
||||
checkObjectSizeEq(objects, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,等于 3
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEqThree(Object[] objects) throws QLException {
|
||||
checkObjectSizeEq(objects, 3);
|
||||
}
|
||||
/**
|
||||
* 检查参数数量,等于 3
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEqThree(Object[] objects) throws QLException {
|
||||
checkObjectSizeEq(objects, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,等于 size
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size 参数数量
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEq(Object[] objects, int size) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
/**
|
||||
* 检查参数数量,等于 size
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size 参数数量
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEq(Object[] objects, int size) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
|
||||
if (objects.length != size) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
if (objects.length != size) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查参数数量,等于 size1 或 size2
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size1 参数数量1
|
||||
* @param size2 参数数量2
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEq(Object[] objects, int size1, int size2) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
/**
|
||||
* 检查参数数量,等于 size1 或 size2
|
||||
*
|
||||
* @param objects objects
|
||||
* @param size1 参数数量1
|
||||
* @param size2 参数数量2
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkObjectSizeEq(Object[] objects, int size1, int size2) throws QLException {
|
||||
checkObjectSizeGtZero(objects);
|
||||
|
||||
if (objects.length != size1 && objects.length != size2) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
if (objects.length != size1 && objects.length != size2) {
|
||||
throw new QLException("parameter error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换 object 为指定的类型
|
||||
*
|
||||
* @param object object
|
||||
* @param tClass 指定类型
|
||||
* @param <T> 返回类型
|
||||
* @return T
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static <T> T convert(Object object, Class<T> tClass) throws QLException {
|
||||
if (tClass.isInstance(object)) {
|
||||
return (T) object;
|
||||
}
|
||||
/**
|
||||
* 转换 object 为指定的类型
|
||||
*
|
||||
* @param object object
|
||||
* @param tClass 指定类型
|
||||
* @param <T> 返回类型
|
||||
* @return T
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static <T> T convert(Object object, Class<T> tClass) throws QLException {
|
||||
if (tClass.isInstance(object)) {
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
throw new QLException("The caller must be " + tClass.getName() + " item");
|
||||
}
|
||||
throw new QLException("The caller must be " + tClass.getName() + " item");
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 node 和 chain 是否已经注册
|
||||
*
|
||||
* @param objects objects
|
||||
* @throws QLException QLException
|
||||
*/
|
||||
public static void checkNodeAndChainExist(Object[] objects) throws QLException {
|
||||
for (Object object : objects) {
|
||||
if (Objects.isNull(object)) {
|
||||
throw new QLException(DataNofFoundException.MSG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
package com.yomahub.liteflow.core.proxy;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.annotation.LiteflowRetry;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.exception.ComponentMethodDefineErrorException;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
||||
import com.yomahub.liteflow.util.SerialsUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
|
@ -12,13 +20,16 @@ import net.bytebuddy.implementation.InvocationHandlerAdapter;
|
|||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
@ -42,7 +53,7 @@ public class ComponentProxy {
|
|||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
public Object getProxy() throws Exception{
|
||||
public List<NodeComponent> getProxyList() throws Exception{
|
||||
//这里要判断bean是否是spring代理过的bean,如果是代理过的bean需要取到原class对象
|
||||
Class<?> beanClazz;
|
||||
if (LiteFlowProxyUtil.isCglibProxyClass(bean.getClass())){
|
||||
|
@ -50,31 +61,104 @@ public class ComponentProxy {
|
|||
}else{
|
||||
beanClazz = bean.getClass();
|
||||
}
|
||||
|
||||
//得到当前bean里所覆盖的组件方法(一定是被@LiteFlowMethod修饰的),自己定义的不算
|
||||
List<String> methodStrList = Arrays.stream(beanClazz.getDeclaredMethods()).filter(
|
||||
//得到当前bean里所覆盖的LiteflowMethod(一定是被@LiteFlowMethod修饰的),自己定义的不算
|
||||
Map<String, List<Method>> methodListMap = Arrays.stream(beanClazz.getDeclaredMethods()).filter(
|
||||
m -> m.getAnnotation(LiteflowMethod.class) != null
|
||||
).map(m -> {
|
||||
LiteflowMethod liteflowMethod = m.getAnnotation(LiteflowMethod.class);
|
||||
return liteflowMethod.value().getMethodName();
|
||||
}).collect(Collectors.toList());
|
||||
).collect(Collectors.groupingBy(
|
||||
m -> m.getAnnotation(LiteflowMethod.class).nodeId()
|
||||
));
|
||||
|
||||
//创建对象
|
||||
//这里package进行了重设,放到了被代理对象的所在目录
|
||||
//生成的对象也加了上被代理对象拥有的注解
|
||||
//被拦截的对象也根据被代理对象根据@LiteFlowMethod所标注的进行了动态判断
|
||||
return new ByteBuddy().subclass(clazz)
|
||||
.name(StrUtil.format("{}.ByteBuddy${}${}",
|
||||
ClassUtil.getPackage(bean.getClass()),
|
||||
nodeId,
|
||||
SerialsUtil.generateShortUUID()))
|
||||
.method(ElementMatchers.namedOneOf(methodStrList.toArray(new String[]{})))
|
||||
.intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean)))
|
||||
.annotateType(bean.getClass().getAnnotations())
|
||||
.make()
|
||||
.load(ComponentProxy.class.getClassLoader())
|
||||
.getLoaded()
|
||||
.newInstance();
|
||||
return methodListMap.entrySet().stream().map(entry -> {
|
||||
// 获取当前节点的原有注解,如:LiteFlowRetry 之类的规则注解
|
||||
Annotation[] beanClassAnnotation = bean.getClass().getAnnotations();
|
||||
// 如果entry的key为空字符串,则是为了兼容老版本的写法,即:没有指定nodeId的情况
|
||||
// 判断是否是方法级创造节点
|
||||
boolean isMethodCreate = !StrUtil.isEmpty(entry.getKey());
|
||||
// 获取当前bean 真实的nodeId
|
||||
String activeNodeId = isMethodCreate ? entry.getKey() : nodeId;
|
||||
// 获取当前节点所有的@LiteflowRetry @LiteflowMethod注解对
|
||||
List<Tuple> tupleList = entry.getValue().stream().map(m ->
|
||||
new Tuple(m.getAnnotation(LiteflowRetry.class), m.getAnnotation(LiteflowMethod.class))
|
||||
).collect(Collectors.toList());
|
||||
// 获取当前节点的所有LiteFlowMethod注解
|
||||
List<LiteflowMethod> methodList = tupleList.stream().map(tuple -> ((LiteflowMethod)tuple.get(1)))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// nodeType去重
|
||||
List<? extends Class<? extends NodeComponent>> classes = methodList.stream()
|
||||
.map(LiteflowMethod::nodeType)
|
||||
.map(AnnotationNodeTypeEnum::getCmpClass)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
// 相同nodeId里只能定义同一种的类型的NodeComponent
|
||||
boolean legal = classes.size() == 1;
|
||||
if (!legal){
|
||||
throw new LiteFlowException("The cmpClass of the same nodeId must be the same,you declared nodeId:" + activeNodeId + ",cmpClass:" + classes);
|
||||
}
|
||||
// 当前节点实际LiteflowRetry注解
|
||||
AtomicReference<LiteflowRetry> liteflowRetryAtomicReference = new AtomicReference<>(null);
|
||||
// 相同nodeId只能有一个LiteflowRetry定义方法,且必须再Process方法上
|
||||
boolean illegal = tupleList.stream().anyMatch(
|
||||
tuple -> {
|
||||
LiteflowRetry liteflowRetry = tuple.get(0);
|
||||
LiteflowMethod liteflowMethod = tuple.get(1);
|
||||
boolean existRetry = liteflowRetry != null;
|
||||
boolean isProcess = liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS)
|
||||
|| liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_IF)
|
||||
|| liteflowMethod.value().equals(LiteFlowMethodEnum.PROCESS_SWITCH);
|
||||
// 如果是再Process方法上的liteflowRetry注解,则默认为真实节点。
|
||||
if (isProcess && existRetry) {
|
||||
liteflowRetryAtomicReference.set(liteflowRetry);
|
||||
}
|
||||
// 如果存在existRetry注解,但是不是在Process方法上,则为非法
|
||||
return existRetry && !isProcess;
|
||||
}
|
||||
);
|
||||
if (illegal){
|
||||
throw new LiteFlowException("the retry annotation (@LiteflowRetry) must be declared on the PROCESS method");
|
||||
}
|
||||
// 生成nodeCmp的类型,默认为全局定义的clazz
|
||||
Class<?> cmpClazz;
|
||||
cmpClazz = clazz;
|
||||
// 判断是否是方法声明的组件
|
||||
if (isMethodCreate){
|
||||
cmpClazz = methodList.iterator().next().nodeType().getCmpClass();
|
||||
LiteflowRetry liteflowRetry;
|
||||
if ((liteflowRetry = liteflowRetryAtomicReference.get()) != null){
|
||||
// 增加LiteFlowRetry注解到注解数组里
|
||||
List<Annotation> annotations = Arrays.stream(beanClassAnnotation)
|
||||
.filter(a -> !a.annotationType().equals(LiteflowRetry.class))
|
||||
.collect(Collectors.toList());
|
||||
annotations.add(liteflowRetry);
|
||||
beanClassAnnotation = new Annotation[annotations.size()];
|
||||
annotations.toArray(beanClassAnnotation);
|
||||
}
|
||||
}
|
||||
try {
|
||||
//创建对象
|
||||
//这里package进行了重设,放到了被代理对象的所在目录
|
||||
//生成的对象也加了上被代理对象拥有的注解
|
||||
//被拦截的对象也根据被代理对象根据@LiteFlowMethod所标注的进行了动态判断
|
||||
Object instance = new ByteBuddy().subclass(cmpClazz)
|
||||
.name(StrUtil.format("{}.ByteBuddy${}${}",
|
||||
ClassUtil.getPackage(bean.getClass()),
|
||||
activeNodeId,
|
||||
SerialsUtil.generateShortUUID()))
|
||||
.method(ElementMatchers.namedOneOf(methodList.stream().map(m -> m.value().getMethodName()).toArray(String[]::new)))
|
||||
.intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean)))
|
||||
.annotateType(beanClassAnnotation)
|
||||
.make()
|
||||
.load(ComponentProxy.class.getClassLoader())
|
||||
.getLoaded()
|
||||
.newInstance();
|
||||
NodeComponent nodeComponent = (NodeComponent) instance;
|
||||
// 重设nodeId
|
||||
nodeComponent.setNodeId(activeNodeId);
|
||||
return nodeComponent;
|
||||
} catch (Exception e) {
|
||||
throw new LiteFlowException(e);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public class AopInvocationHandler implements InvocationHandler {
|
||||
|
@ -93,6 +177,10 @@ public class ComponentProxy {
|
|||
List<LiteFlowMethodBean> liteFlowMethodBeanList = Arrays.stream(ReflectUtil.getMethods(bean.getClass())).filter(m -> {
|
||||
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
|
||||
return ObjectUtil.isNotNull(liteFlowMethod);
|
||||
}).filter(m -> {
|
||||
// 过滤不属于当前NodeComponent的方法
|
||||
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
|
||||
return StrUtil.isEmpty(liteFlowMethod.nodeId())|| Objects.equals(liteFlowMethod.nodeId(),((NodeComponent) proxy).getNodeId());
|
||||
}).map(m -> {
|
||||
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
|
||||
return new LiteFlowMethodBean(liteFlowMethod.value().getMethodName(), m);
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package com.yomahub.liteflow.enums;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
/**
|
||||
* 注解节点类型枚举
|
||||
*
|
||||
* @author Sorghum
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public enum AnnotationNodeTypeEnum {
|
||||
/**
|
||||
* 普通节点
|
||||
*/
|
||||
COMMON("普通", NodeComponent.class),
|
||||
/**
|
||||
* 选择节点
|
||||
*/
|
||||
SWITCH("选择", NodeSwitchComponent.class),
|
||||
/**
|
||||
* 条件节点
|
||||
*/
|
||||
IF("条件", NodeIfComponent.class),;
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
final String desc;
|
||||
/**
|
||||
* cmp类
|
||||
*/
|
||||
final Class<? extends NodeComponent> cmpClass;
|
||||
|
||||
AnnotationNodeTypeEnum(String desc, Class<? extends NodeComponent> cmpClass) {
|
||||
this.desc = desc;
|
||||
this.cmpClass = cmpClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到Node定义类
|
||||
* @return node定义类
|
||||
*/
|
||||
public Class<? extends NodeComponent> getCmpClass() {
|
||||
return cmpClass;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* @author tangkc
|
||||
*/
|
||||
public class DataNofFoundException extends RuntimeException {
|
||||
public static final String MSG = "DataNofFoundException";
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public DataNofFoundException() {
|
||||
this.message = MSG;
|
||||
}
|
||||
|
||||
public DataNofFoundException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -9,16 +9,17 @@
|
|||
package com.yomahub.liteflow.flow;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.core.*;
|
||||
import com.yomahub.liteflow.exception.NullNodeTypeException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ComponentCannotRegisterException;
|
||||
import com.yomahub.liteflow.exception.NullNodeTypeException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.parser.LocalJsonFlowParser;
|
||||
import com.yomahub.liteflow.parser.LocalXmlFlowParser;
|
||||
import com.yomahub.liteflow.parser.LocalYmlFlowParser;
|
||||
|
@ -36,7 +37,10 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 流程元数据类
|
||||
|
@ -156,7 +160,7 @@ public class FlowBus {
|
|||
try {
|
||||
//判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
|
||||
//如果不是声明式的,就用传统的方式进行判断
|
||||
NodeComponent cmpInstance = null;
|
||||
List<NodeComponent> cmpInstances = new ArrayList<>();
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(cmpClazz)){
|
||||
//这里的逻辑要仔细看下
|
||||
//如果是spring体系,把原始的类往spring上下文中进行注册,那么会走到ComponentScanner中
|
||||
|
@ -167,42 +171,50 @@ public class FlowBus {
|
|||
ContextAware contextAware = ContextAwareHolder.loadContextAware();
|
||||
Object bean = ContextAwareHolder.loadContextAware().registerBean(nodeId, cmpClazz);
|
||||
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())){
|
||||
cmpInstance = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
|
||||
cmpInstances = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
|
||||
}else {
|
||||
cmpInstance = (NodeComponent) bean;
|
||||
cmpInstances = ListUtil.toList((NodeComponent) bean);
|
||||
}
|
||||
}else{
|
||||
//以node方式配置,本质上是为了适配无spring的环境,如果有spring环境,其实不用这么配置
|
||||
//这里的逻辑是判断是否能从spring上下文中取到,如果没有spring,则就是new instance了
|
||||
//如果是script类型的节点,因为class只有一个,所以也不能注册进spring上下文,注册的时候需要new Instance
|
||||
if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.SWITCH_SCRIPT, NodeTypeEnum.IF_SCRIPT).contains(type)){
|
||||
cmpInstance = (NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz);
|
||||
cmpInstances = ListUtil.toList((NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz));
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNull(cmpInstance)) {
|
||||
cmpInstance = (NodeComponent) cmpClazz.newInstance();
|
||||
// 去除null元素
|
||||
cmpInstances.remove(null);
|
||||
// 如果为空
|
||||
if (cmpInstances.isEmpty()) {
|
||||
NodeComponent cmpInstance = (NodeComponent) cmpClazz.newInstance();
|
||||
cmpInstances.add(cmpInstance);
|
||||
}
|
||||
}
|
||||
|
||||
//进行初始化
|
||||
cmpInstance = ComponentInitializer.loadInstance().initComponent(cmpInstance, type, name, nodeId);
|
||||
cmpInstances = cmpInstances.stream()
|
||||
.map(
|
||||
cmpInstance -> ComponentInitializer.loadInstance().initComponent(cmpInstance, type, name, cmpInstance.getNodeId() == null ? nodeId : cmpInstance.getNodeId())).collect(Collectors.toList());
|
||||
|
||||
//初始化Node
|
||||
Node node = new Node(cmpInstance);
|
||||
List<Node> nodes = cmpInstances.stream().map(Node::new).collect(Collectors.toList());
|
||||
|
||||
//如果是脚本节点(普通脚本节点/条件脚本节点),则还要加载script脚本
|
||||
if (StrUtil.isNotBlank(script)){
|
||||
node.setScript(script);
|
||||
if (type.equals(NodeTypeEnum.SCRIPT)){
|
||||
((ScriptComponent)cmpInstance).loadScript(script);
|
||||
}else if(type.equals(NodeTypeEnum.SWITCH_SCRIPT)){
|
||||
((ScriptSwitchComponent)cmpInstance).loadScript(script);
|
||||
}else if(type.equals(NodeTypeEnum.IF_SCRIPT)){
|
||||
((ScriptIfComponent)cmpInstance).loadScript(script);
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
Node node = nodes.get(i);
|
||||
NodeComponent cmpInstance = cmpInstances.get(i);
|
||||
if (StrUtil.isNotBlank(script)){
|
||||
node.setScript(script);
|
||||
if (type.equals(NodeTypeEnum.SCRIPT)){
|
||||
((ScriptComponent)cmpInstance).loadScript(script);
|
||||
}else if(type.equals(NodeTypeEnum.SWITCH_SCRIPT)){
|
||||
((ScriptSwitchComponent)cmpInstance).loadScript(script);
|
||||
}else if(type.equals(NodeTypeEnum.IF_SCRIPT)){
|
||||
((ScriptIfComponent)cmpInstance).loadScript(script);
|
||||
}
|
||||
}
|
||||
String activeNodeId = StrUtil.isEmpty(cmpInstance.getNodeId()) ? nodeId : cmpInstance.getNodeId();
|
||||
//如果是脚本节点(普通脚本节点/条件脚本节点),则还要加载script脚本
|
||||
nodeMap.put(activeNodeId, node);
|
||||
}
|
||||
|
||||
nodeMap.put(nodeId, node);
|
||||
} catch (Exception e) {
|
||||
String error = StrUtil.format("component[{}] register error", StrUtil.isEmpty(name)?nodeId:StrUtil.format("{}({})",nodeId,name));
|
||||
LOG.error(error);
|
||||
|
|
|
@ -331,8 +331,7 @@ public class ParserHelper {
|
|||
}
|
||||
/**
|
||||
* 解析一个chain的过程
|
||||
* <p>
|
||||
* param e chain 节点
|
||||
* @param e chain 节点
|
||||
*/
|
||||
public static void parseOneChain(Element e) {
|
||||
String condValueStr;
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
package com.yomahub.liteflow.util;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowIfCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowSwitchCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.annotation.LiteflowSwitchCmpDefine;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
import com.yomahub.liteflow.core.proxy.ComponentProxy;
|
||||
import com.yomahub.liteflow.exception.ComponentProxyErrorException;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 组件代理类通用方法
|
||||
|
@ -29,23 +30,6 @@ public class LiteFlowProxyUtil {
|
|||
|
||||
//判断一个bean是否是声明式组件
|
||||
public static boolean isDeclareCmp(Class<?> clazz){
|
||||
//判断bean是否标记了@LiteflowCmpDefine,@LiteflowCondCmpDefine,LiteflowIfCmpDefine这3个标注之一
|
||||
boolean flag1 = clazz.getAnnotation(LiteflowCmpDefine.class) != null
|
||||
|| clazz.getAnnotation(LiteflowSwitchCmpDefine.class) != null
|
||||
|| clazz.getAnnotation(LiteflowIfCmpDefine.class) != null;
|
||||
|
||||
if (!flag1){
|
||||
return false;
|
||||
}
|
||||
|
||||
//看超类是否是NodeComponent,NodeCondComponent,NodeIfComponent中的一个,如果不是,则说明满足条件。是的话,也不满足
|
||||
boolean flag2 = !ListUtil.toList(NodeComponent.class, NodeSwitchComponent.class, NodeIfComponent.class)
|
||||
.contains(clazz.getSuperclass());
|
||||
|
||||
if (!flag2){
|
||||
return false;
|
||||
}
|
||||
|
||||
//查看bean里的method是否有方法标记了@LiteflowMethod标注
|
||||
//这里的bean有可能是cglib加强过的class,所以要先进行个判断
|
||||
Class<?> targetClass;
|
||||
|
@ -54,15 +38,14 @@ public class LiteFlowProxyUtil {
|
|||
}else{
|
||||
targetClass = clazz;
|
||||
}
|
||||
boolean flag3 = Arrays.stream(targetClass.getMethods()).anyMatch(
|
||||
// 判断是否有方法标记了@LiteflowMethod标注,有则为声明式组件
|
||||
return Arrays.stream(targetClass.getMethods()).anyMatch(
|
||||
method -> method.getAnnotation(LiteflowMethod.class) != null
|
||||
);
|
||||
|
||||
return flag3;
|
||||
}
|
||||
|
||||
//对一个满足声明式的bean进行代理
|
||||
public static NodeComponent proxy2NodeComponent(Object bean, String nodeId){
|
||||
//对一个满足声明式的bean进行代理,生成代理类数组
|
||||
public static List<NodeComponent> proxy2NodeComponent(Object bean, String nodeId){
|
||||
try{
|
||||
LiteflowCmpDefine liteflowCmpDefine = bean.getClass().getAnnotation(LiteflowCmpDefine.class);
|
||||
LiteflowSwitchCmpDefine liteflowSwitchCmpDefine = bean.getClass().getAnnotation(LiteflowSwitchCmpDefine.class);
|
||||
|
@ -71,21 +54,23 @@ public class LiteFlowProxyUtil {
|
|||
ComponentProxy proxy;
|
||||
if (ObjectUtil.isNotNull(liteflowCmpDefine)){
|
||||
proxy = new ComponentProxy(nodeId, bean, NodeComponent.class);
|
||||
return (NodeComponent) proxy.getProxy();
|
||||
return proxy.getProxyList();
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotNull(liteflowSwitchCmpDefine)){
|
||||
proxy = new ComponentProxy(nodeId, bean, NodeSwitchComponent.class);
|
||||
return (NodeSwitchComponent) proxy.getProxy();
|
||||
return proxy.getProxyList();
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotNull(liteflowIfCmpDefine)){
|
||||
proxy = new ComponentProxy(nodeId, bean, NodeIfComponent.class);
|
||||
return (NodeIfComponent) proxy.getProxy();
|
||||
return proxy.getProxyList();
|
||||
}
|
||||
|
||||
throw new RuntimeException();
|
||||
}catch (Exception e){
|
||||
return new ComponentProxy(nodeId, bean, NodeIfComponent.class).getProxyList();
|
||||
}catch (LiteFlowException liteFlowException){
|
||||
throw liteFlowException;
|
||||
}
|
||||
catch (Exception e){
|
||||
String errMsg = StrUtil.format("Error while proxying bean[{}]",bean.getClass().getName());
|
||||
LOG.error(errMsg);
|
||||
throw new ComponentProxyErrorException(errMsg);
|
||||
|
|
|
@ -55,6 +55,8 @@ public class SerialsUtil {
|
|||
|
||||
/**
|
||||
* 生成一个12位随机数
|
||||
* @param seed 种子值
|
||||
* @return String 随机数
|
||||
*/
|
||||
public static String randomNum12(long seed) {
|
||||
// 被除数
|
||||
|
@ -64,6 +66,8 @@ public class SerialsUtil {
|
|||
|
||||
/**
|
||||
* 生成一个8位随机数
|
||||
* @param seed 种子值
|
||||
* @return String 随机数
|
||||
*/
|
||||
public static String randomNum8(long seed) {
|
||||
// 被除数
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>liteflow</artifactId>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>liteflow-rule-sql</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,19 @@
|
|||
package com.yomahub.liteflow.parser.spi.sql;
|
||||
|
||||
import com.yomahub.liteflow.parser.spi.ParserClassNameSpi;
|
||||
import com.yomahub.liteflow.parser.sql.SQLXmlELParser;
|
||||
|
||||
/**
|
||||
* SQL 解析器 SPI 实现
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class SQLParserClassNameSpi implements ParserClassNameSpi {
|
||||
|
||||
@Override
|
||||
public String getSpiClassName() {
|
||||
return SQLXmlELParser.class.getName();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.yomahub.liteflow.parser.sql;
|
||||
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.parser.el.ClassXmlFlowELParser;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.util.JDBCHelper;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* SQL 解析器实现,只支持 EL 形式的 XML,不支持其他的形式
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class SQLXmlELParser extends ClassXmlFlowELParser {
|
||||
|
||||
private static final String ERROR_MSG_PATTERN = "rule-source-ext-data {} is blank";
|
||||
private static final String ERROR_COMMON_MSG = "rule-source-ext-data is empty";
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*/
|
||||
public SQLXmlELParser() {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
|
||||
if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData())) {
|
||||
throw new ELSQLException(ERROR_COMMON_MSG);
|
||||
}
|
||||
|
||||
try {
|
||||
SQLParserVO sqlParserVO = JsonUtil.parseObject(liteflowConfig.getRuleSourceExtData(), SQLParserVO.class);
|
||||
if (Objects.isNull(sqlParserVO)) {
|
||||
throw new ELSQLException(ERROR_COMMON_MSG);
|
||||
}
|
||||
|
||||
// 检查配置文件
|
||||
checkParserVO(sqlParserVO);
|
||||
|
||||
// 初始化 JDBCHelper
|
||||
JDBCHelper.init(sqlParserVO);
|
||||
|
||||
} catch (ELSQLException elsqlException) {
|
||||
throw elsqlException;
|
||||
} catch (Exception ex) {
|
||||
throw new ELSQLException(ex.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseCustom() {
|
||||
return JDBCHelper.getInstance().getElDataContent();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查配置文件并设置默认值
|
||||
*
|
||||
* @param sqlParserVO sqlParserVO
|
||||
*/
|
||||
private void checkParserVO(SQLParserVO sqlParserVO) {
|
||||
if (StrUtil.isEmpty(sqlParserVO.getUrl())) {
|
||||
throw new ELSQLException(StrFormatter.format(ERROR_MSG_PATTERN, "url"));
|
||||
}
|
||||
if (StrUtil.isEmpty(sqlParserVO.getDriverClassName())) {
|
||||
throw new ELSQLException(StrFormatter.format(ERROR_MSG_PATTERN, "driverClassName"));
|
||||
}
|
||||
if (Objects.isNull(sqlParserVO.getUsername())) {
|
||||
throw new ELSQLException(StrFormatter.format(ERROR_MSG_PATTERN, "username"));
|
||||
}
|
||||
if (Objects.isNull(sqlParserVO.getPassword())) {
|
||||
throw new ELSQLException(StrFormatter.format(ERROR_MSG_PATTERN, "password"));
|
||||
}
|
||||
if (Objects.isNull(sqlParserVO.getElTable())) {
|
||||
sqlParserVO.setElTable(new SQLParserVO.ElTable());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.yomahub.liteflow.parser.sql.exception;
|
||||
|
||||
/**
|
||||
* SQL 相关业务异常
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class ELSQLException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public ELSQLException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
package com.yomahub.liteflow.parser.sql.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* jdbc 工具类
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class JDBCHelper {
|
||||
|
||||
private static final String SQL_PATTERN = "SELECT {},{} FROM {} ";
|
||||
|
||||
private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
|
||||
private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}</flow>";
|
||||
private static final Integer FETCH_SIZE_MAX = 1000;
|
||||
|
||||
private SQLParserVO sqlParserVO;
|
||||
|
||||
private static JDBCHelper INSTANCE;
|
||||
|
||||
/**
|
||||
* 初始化 INSTANCE
|
||||
*/
|
||||
public static void init(SQLParserVO sqlParserVO) {
|
||||
try {
|
||||
INSTANCE = new JDBCHelper();
|
||||
Class.forName(sqlParserVO.getDriverClassName());
|
||||
INSTANCE.setSqlParserVO(sqlParserVO);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 INSTANCE
|
||||
*/
|
||||
public static JDBCHelper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取链接
|
||||
*/
|
||||
public Connection getConn() {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ElData 数据内容
|
||||
*/
|
||||
public String getElDataContent() {
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
String elDataField = sqlParserVO.getElTable().getElDataField();
|
||||
String chainNameField = sqlParserVO.getElTable().getChainNameField();
|
||||
String tableName = sqlParserVO.getElTable().getTableName();
|
||||
String sqlCmd = StrFormatter.format(SQL_PATTERN, chainNameField, elDataField, tableName);
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
// 设置游标拉取数量
|
||||
stmt.setFetchSize(FETCH_SIZE_MAX);
|
||||
rs = stmt.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
String elData = rs.getString(elDataField);
|
||||
if (StrUtil.isBlank(elData)) {
|
||||
throw new ELSQLException(StrFormatter.format("{} table exist {} field value is empty", tableName, elDataField));
|
||||
}
|
||||
String chainName = rs.getString(chainNameField);
|
||||
if (StrUtil.isBlank(elData)) {
|
||||
throw new ELSQLException(StrFormatter.format("{} table exist {} field value is empty", tableName, elDataField));
|
||||
}
|
||||
|
||||
result.add(StrFormatter.format(CHAIN_XML_PATTERN, chainName, elData));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
|
||||
String chains = CollUtil.join(result, StrUtil.CRLF);
|
||||
return StrFormatter.format(XML_PATTERN, chains);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
*
|
||||
* @param conn conn
|
||||
* @param stmt stmt
|
||||
* @param rs rs
|
||||
*/
|
||||
private void close(Connection conn, PreparedStatement stmt, ResultSet rs) {
|
||||
// 关闭连接
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
// 关闭 statement
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
//关闭结果集
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#region get set method
|
||||
private SQLParserVO getSqlParserVO() {
|
||||
return sqlParserVO;
|
||||
}
|
||||
|
||||
private JDBCHelper setSqlParserVO(SQLParserVO sqlParserVO) {
|
||||
this.sqlParserVO = sqlParserVO;
|
||||
return this;
|
||||
}
|
||||
//#endregion
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.yomahub.liteflow.parser.sql.vo;
|
||||
|
||||
/**
|
||||
* 用于解析 RuleSourceExtData 的 VO 类,用于 sql 模式中
|
||||
*
|
||||
* @author tangkc
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class SQLParserVO {
|
||||
|
||||
/**
|
||||
* 连接地址
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 驱动
|
||||
*/
|
||||
private String driverClassName;
|
||||
|
||||
/**
|
||||
* 账号名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* EL 表相关配置
|
||||
*/
|
||||
private ElTable elTable;
|
||||
|
||||
public static class ElTable {
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String tableName = "el_table";
|
||||
|
||||
/**
|
||||
* chainName
|
||||
*/
|
||||
private String chainNameField = "chain_name";
|
||||
|
||||
/**
|
||||
* el 表达式相关数据
|
||||
*/
|
||||
private String elDataField = "el_data";
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getChainNameField() {
|
||||
return chainNameField;
|
||||
}
|
||||
|
||||
public void setChainNameField(String chainNameField) {
|
||||
this.chainNameField = chainNameField;
|
||||
}
|
||||
|
||||
public String getElDataField() {
|
||||
return elDataField;
|
||||
}
|
||||
|
||||
public void setElDataField(String elDataField) {
|
||||
this.elDataField = elDataField;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getDriverClassName() {
|
||||
return driverClassName;
|
||||
}
|
||||
|
||||
public void setDriverClassName(String driverClassName) {
|
||||
this.driverClassName = driverClassName;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public ElTable getElTable() {
|
||||
return elTable;
|
||||
}
|
||||
|
||||
public void setElTable(ElTable elTable) {
|
||||
this.elTable = elTable;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
com.yomahub.liteflow.parser.spi.sql.SQLParserClassNameSpi
|
|
@ -12,7 +12,7 @@
|
|||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>liteflow-rule-zk</module>
|
||||
<module>liteflow-rule-nacos</module>
|
||||
<module>liteflow-rule-sql</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>liteflow-rule-plugin</artifactId>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
package com.yomahub.liteflow.spring;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.aop.ICmpAroundAspect;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
|
@ -19,6 +20,7 @@ import org.springframework.beans.BeansException;
|
|||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -61,9 +63,19 @@ public class ComponentScanner implements BeanPostProcessor {
|
|||
//如果是,就缓存到类属性的map中
|
||||
if (LiteFlowProxyUtil.isDeclareCmp(bean.getClass())){
|
||||
LOG.info("proxy component[{}] has been found", beanName);
|
||||
NodeComponent nodeComponent = LiteFlowProxyUtil.proxy2NodeComponent(bean, beanName);
|
||||
nodeComponentMap.put(beanName, nodeComponent);
|
||||
return nodeComponent;
|
||||
List<NodeComponent> nodeComponents = LiteFlowProxyUtil.proxy2NodeComponent(bean, beanName);
|
||||
nodeComponents.forEach(
|
||||
nodeComponent -> {
|
||||
String nodeId = nodeComponent.getNodeId();
|
||||
nodeId = StrUtil.isEmpty(nodeId) ? beanName : nodeId;
|
||||
nodeComponentMap.put(nodeId, nodeComponent);
|
||||
}
|
||||
);
|
||||
// 只有注解支持单bean多Node,所以一个直接返回
|
||||
if (nodeComponents.size() == 1){
|
||||
return nodeComponents.get(0);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
// 组件的扫描发现,扫到之后缓存到类属性map中
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>liteflow-testcase-el</artifactId>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>liteflow-testcase-el-declare-multi-springboot</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-spring-boot-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.101tec</groupId>
|
||||
<artifactId>zkclient</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-framework</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-recipes</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.8.2</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
package com.yomahub.liteflow.test;
|
||||
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner;
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
import com.yomahub.liteflow.thread.ExecutorHelper;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
public class BaseTest {
|
||||
|
||||
@AfterClass
|
||||
public static void cleanScanCache(){
|
||||
ComponentScanner.cleanCache();
|
||||
FlowBus.cleanCache();
|
||||
ExecutorHelper.loadInstance().clearExecutorServiceMap();
|
||||
SpiFactoryCleaner.clean();
|
||||
LiteflowConfigGetter.clean();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.yomahub.liteflow.test.absoluteConfigPath;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境下异步线程超时日志打印测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/absoluteConfigPath/application.properties")
|
||||
@SpringBootTest(classes = AbsoluteConfigPathELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.absoluteConfigPath.cmp"})
|
||||
public class AbsoluteConfigPathELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testAbsoluteConfig() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.absoluteConfigPath.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpMultiDefine{
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a",nodeType = AnnotationNodeTypeEnum.COMMON)
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package com.yomahub.liteflow.test.aop;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.aop.aspect.CmpAspect;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 切面场景单元测试
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/aop/application.properties")
|
||||
@SpringBootTest(classes = GlobalAOPELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@Import(CmpAspect.class)
|
||||
@ComponentScan({"com.yomahub.liteflow.test.aop.cmp1","com.yomahub.liteflow.test.aop.cmp2"})
|
||||
public class GlobalAOPELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试全局AOP,串行场景
|
||||
@Test
|
||||
public void testGlobalAopS() {
|
||||
LiteflowResponse response= flowExecutor.execute2Resp("chain1", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("before_after", context.getData("a"));
|
||||
Assert.assertEquals("before_after", context.getData("b"));
|
||||
Assert.assertEquals("before_after", context.getData("c"));
|
||||
Assert.assertEquals("before_after", context.getData("d"));
|
||||
Assert.assertEquals("before_after", context.getData("e"));
|
||||
}
|
||||
|
||||
//测试全局AOP,并行场景
|
||||
@Test
|
||||
public void testGlobalAopP() {
|
||||
LiteflowResponse response= flowExecutor.execute2Resp("chain2", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("before_after", context.getData("a"));
|
||||
Assert.assertEquals("before_after", context.getData("b"));
|
||||
Assert.assertEquals("before_after", context.getData("c"));
|
||||
Assert.assertEquals("before_after", context.getData("d"));
|
||||
Assert.assertEquals("before_after", context.getData("e"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGlobalAopException() {
|
||||
LiteflowResponse response= flowExecutor.execute2Resp("chain3", "it's a request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals("before_after", context.getData("a"));
|
||||
Assert.assertEquals("before_after", context.getData("b"));
|
||||
Assert.assertEquals("before_after", context.getData("c"));
|
||||
Assert.assertEquals("before_after", context.getData("f"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanScanCache(){
|
||||
BaseTest.cleanScanCache();
|
||||
ComponentScanner.cmpAroundAspect = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.yomahub.liteflow.test.aop.aspect;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.aop.ICmpAroundAspect;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
public class CmpAspect implements ICmpAroundAspect {
|
||||
@Override
|
||||
public void beforeProcess(String nodeId, Slot slot) {
|
||||
DefaultContext context = slot.getFirstContextBean();
|
||||
context.setData(nodeId, "before");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess(String nodeId, Slot slot) {
|
||||
DefaultContext context = slot.getFirstContextBean();
|
||||
context.setData(nodeId, StrUtil.format("{}_{}", context.getData(nodeId), "after"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.yomahub.liteflow.test.aop.aspect;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
|
||||
@Aspect
|
||||
public class CustomAspect {
|
||||
|
||||
@Pointcut("execution(* com.yomahub.liteflow.test.aop.cmp1.*.process(*))")
|
||||
public void cut() {
|
||||
}
|
||||
|
||||
@Around("cut()")
|
||||
public Object around(ProceedingJoinPoint jp) throws Throwable {
|
||||
NodeComponent cmp = (NodeComponent) jp.getThis();
|
||||
DefaultContext context = cmp.getFirstContextBean();
|
||||
context.setData(cmp.getNodeId(), "before");
|
||||
Object returnObj = jp.proceed();
|
||||
context.setData(cmp.getNodeId(), StrUtil.format("{}_{}", context.getData(cmp.getNodeId()), "after"));
|
||||
return returnObj;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.yomahub.liteflow.test.aop.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class Cmp1Config {
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("Acomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("Bcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("Ccomp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.yomahub.liteflow.test.aop.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class Cmp2Config {
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
System.out.println("Dcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
System.out.println("Ecomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "f")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
throw new RuntimeException("test error");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package com.yomahub.liteflow.test.asyncNode;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.asyncNode.exception.TestException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 测试隐式调用子流程
|
||||
* 单元测试
|
||||
*
|
||||
* @author ssss
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/asyncNode/application.properties")
|
||||
@SpringBootTest(classes = AsyncNodeELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.asyncNode.cmp"})
|
||||
public class AsyncNodeELDeclMultiSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
/*****
|
||||
* 标准chain 嵌套选择 嵌套子chain进行执行
|
||||
* 验证了when情况下 多个node是并行执行
|
||||
* 验证了默认参数情况下 when可以加载执行
|
||||
* **/
|
||||
@Test
|
||||
public void testAsyncFlow1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a base request");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
System.out.println(response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//这个和test1有点类似,只不过进一步验证了步骤
|
||||
@Test
|
||||
public void testAsyncFlow2() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "it's a base request");
|
||||
Assert.assertTrue(ListUtil.toList("b==>j==>g==>f==>h","b==>j==>g==>h==>f",
|
||||
"b==>j==>h==>g==>f","b==>j==>h==>f==>g",
|
||||
"b==>j==>f==>h==>g","b==>j==>f==>g==>h"
|
||||
).contains(response.getExecuteStepStr()));
|
||||
}
|
||||
|
||||
//测试errorResume,默认的errorResume为false,这里测试默认的
|
||||
@Test
|
||||
public void testAsyncFlow3_1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3-1", "it's a base request");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals(response.getSlot().getException().getClass(), TestException.class);
|
||||
}
|
||||
|
||||
//测试errorResume,默认的errorResume为false,这里设置为true
|
||||
@Test
|
||||
public void testAsyncFlow3_2() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3-2", "it's a base request");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
//相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了不抛错
|
||||
@Test
|
||||
public void testAsyncFlow4() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "it's a base request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
//因为不记录错误,所以最终结果是true
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
//因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下
|
||||
Integer count = context.getData("count");
|
||||
Assert.assertEquals(new Integer(2), count);
|
||||
//因为配置了不抛错,所以response里的cause应该为null
|
||||
Assert.assertNull(response.getCause());
|
||||
}
|
||||
|
||||
//相同group的并行组,会合并,并且errorResume根据第一个when来,这里第一个when配置了会抛错
|
||||
@Test
|
||||
public void testAsyncFlow5() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "it's a base request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
//整个并行组是报错的,所以最终结果是false
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
//因为是并行组,所以即便抛错了,其他组件也会执行,i在流程里配置了2遍,i抛错,但是也执行了2遍,这里验证下
|
||||
Integer count = context.getData("count");
|
||||
Assert.assertEquals(new Integer(2), count);
|
||||
//因为第一个when配置了会报错,所以response里的cause里应该会有TestException
|
||||
Assert.assertEquals(TestException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
//不同group的并行组,不会合并,第一个when的errorResume是false,会抛错,那第二个when就不会执行
|
||||
@Test
|
||||
public void testAsyncFlow6() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "it's a base request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
//第一个when会抛错,所以最终结果是false
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
//因为是不同组并行组,第一组的when里的i就抛错了,所以i就执行了1遍
|
||||
Integer count = context.getData("count");
|
||||
Assert.assertEquals(new Integer(1), count);
|
||||
//第一个when会报错,所以最终response的cause里应该会有TestException
|
||||
Assert.assertEquals(TestException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
//不同group的并行组,不会合并,第一个when的errorResume是true,不会报错,那第二个when还会继续执行,但是第二个when的errorResume是false,所以第二个when会报错
|
||||
@Test
|
||||
public void testAsyncFlow7() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "it's a base request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
//第二个when会抛错,所以最终结果是false
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
// 传递了slotIndex,则set的size==2
|
||||
Integer count = context.getData("count");
|
||||
Assert.assertEquals(new Integer(2), count);
|
||||
//第一个when会报错,所以最终response的cause里应该会有TestException
|
||||
Assert.assertEquals(TestException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
//测试任意异步一个执行完即继续的场景
|
||||
//d g h并行,配置了any=true,其中d耗时1秒,g耗时0.5秒,其他都不设耗时
|
||||
//最终执行效果应该是h先返回,然后执行abc,最后gd
|
||||
//这里要注意的是,由于step是先加入,所以step的打印顺序并不是这样的。但是实际执行是正确的
|
||||
@Test
|
||||
public void testAsyncFlow8() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "it's a base request");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertTrue(context.getData("check").toString().startsWith("habc"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
package com.yomahub.liteflow.test.asyncNode.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.asyncNode.exception.TestException;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
}
|
||||
System.out.println("Acomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value =LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
}
|
||||
System.out.println("Bcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
}
|
||||
System.out.println("Ccomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) throws Exception {
|
||||
Thread.sleep(1000);
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
}
|
||||
System.out.println("Dcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeId = "e",nodeType = AnnotationNodeTypeEnum.SWITCH)
|
||||
public String processSwitchE(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("Ecomp executed!");
|
||||
return "g";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "f")
|
||||
public void processF(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("Fcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "g")
|
||||
public void processG(NodeComponent bindCmp) throws Exception {
|
||||
Thread.sleep(500);
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
}
|
||||
System.out.println("Gcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "h")
|
||||
public void processH(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (NodeComponent.class){
|
||||
if (context.hasData("check")){
|
||||
String str = context.getData("check");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("check", str);
|
||||
}else{
|
||||
context.setData("check", bindCmp.getNodeId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
System.out.println("Hcomp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "i")
|
||||
public void processI(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
synchronized (this){
|
||||
if (context.hasData("count")){
|
||||
Integer count = context.getData("count");
|
||||
context.setData("count", ++count);
|
||||
} else{
|
||||
context.setData("count", 1);
|
||||
}
|
||||
}
|
||||
System.out.println("Icomp executed! throw Exception!");
|
||||
throw new TestException();
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeId = "j",nodeType = AnnotationNodeTypeEnum.SWITCH)
|
||||
public String processSwitchJ(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("Jcomp executed!");
|
||||
return "chain3";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package com.yomahub.liteflow.test.asyncNode.exception;
|
||||
|
||||
public class TestException extends Exception{
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.yomahub.liteflow.test.base;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境最普通的例子测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/base/application.properties")
|
||||
@SpringBootTest(classes = BaseELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.base.cmp"})
|
||||
public class BaseELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testBase() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.yomahub.liteflow.test.base.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
|
||||
@Resource
|
||||
private TestDomain testDomain;
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
testDomain.sayHi();
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.yomahub.liteflow.test.base.cmp;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TestDomain {
|
||||
public void sayHi(){
|
||||
System.out.println("hello");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
package com.yomahub.liteflow.test.builder;
|
||||
|
||||
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
|
||||
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
|
||||
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.builder.entity.ExecutableEntity;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.builder.cmp1.*;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
//基于builder模式的单元测试
|
||||
//这里只是最基本的builder模式的测试,只是为了验证在springboot模式下的正常性
|
||||
//更详细的builder模式测试用例会单独拉testcase去做
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = BuilderELDeclMultiSpringbootTest1.class)
|
||||
@EnableAutoConfiguration
|
||||
public class BuilderELDeclMultiSpringbootTest1 extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//基于普通组件的builder模式测试
|
||||
@Test
|
||||
public void testBuilder() throws Exception {
|
||||
LiteFlowNodeBuilder.createNode().setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.ACmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.BCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.CCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("d")
|
||||
.setName("组件D")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.DCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("e")
|
||||
.setName("组件E")
|
||||
.setType(NodeTypeEnum.SWITCH)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.ECmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("f")
|
||||
.setName("组件F")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.FCmp")
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("g")
|
||||
.setName("组件G")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz("com.yomahub.liteflow.test.builder.cmp1.GCmp")
|
||||
.build();
|
||||
|
||||
|
||||
LiteFlowChainELBuilder.createChain().setChainName("chain2").setEL(
|
||||
"THEN(c, d)"
|
||||
).build();
|
||||
|
||||
LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL(
|
||||
"THEN(a, b, WHEN(SWITCH(e).to(f, g, chain2)))"
|
||||
).build();
|
||||
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//基于普通组件的builder模式测试
|
||||
@Test
|
||||
public void testBuilderForClassAndCode() throws Exception {
|
||||
LiteFlowNodeBuilder.createNode().setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("d")
|
||||
.setName("组件D")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(DCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("e")
|
||||
.setName("组件E")
|
||||
.setType(NodeTypeEnum.SWITCH)
|
||||
.setClazz(ECmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("f")
|
||||
.setName("组件F")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(FCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("g")
|
||||
.setName("组件G")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(GCmp.class)
|
||||
.build();
|
||||
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
|
||||
LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
|
||||
).build();
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
|
||||
LiteFlowConditionBuilder
|
||||
.createThenCondition()
|
||||
.setValue("a,b").build()
|
||||
).setCondition(
|
||||
LiteFlowConditionBuilder.createWhenCondition()
|
||||
.setValue("e(f|g|chain2)").build()
|
||||
).build();
|
||||
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
|
||||
//基于普通组件的builder模式测试
|
||||
@Test
|
||||
public void testBuilderForConditionNode() throws Exception {
|
||||
LiteFlowNodeBuilder.createNode().setId("a")
|
||||
.setName("组件A")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(ACmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("b")
|
||||
.setName("组件B")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(BCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("c")
|
||||
.setName("组件C")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(CCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("d")
|
||||
.setName("组件D")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(DCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("e")
|
||||
.setName("组件E")
|
||||
.setType(NodeTypeEnum.SWITCH)
|
||||
.setClazz(ECmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("f")
|
||||
.setName("组件F")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(FCmp.class)
|
||||
.build();
|
||||
LiteFlowNodeBuilder.createNode().setId("g")
|
||||
.setName("组件G")
|
||||
.setType(NodeTypeEnum.COMMON)
|
||||
.setClazz(GCmp.class)
|
||||
.build();
|
||||
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
|
||||
LiteFlowConditionBuilder.createThenCondition()
|
||||
.setExecutable(new ExecutableEntity().setId("c"))
|
||||
.setExecutable(new ExecutableEntity().setId("d"))
|
||||
.build()
|
||||
).build();
|
||||
|
||||
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
|
||||
LiteFlowConditionBuilder
|
||||
.createThenCondition()
|
||||
.setExecutable(new ExecutableEntity().setId("a").setTag("hello"))
|
||||
.setExecutable(new ExecutableEntity().setId("b"))
|
||||
.build()
|
||||
).setCondition(
|
||||
LiteFlowConditionBuilder.createWhenCondition()
|
||||
.setExecutable(
|
||||
new ExecutableEntity().setId("e")
|
||||
.addNodeCondComponent(new ExecutableEntity().setId("f").setTag("FHello"))
|
||||
.addNodeCondComponent(new ExecutableEntity().setId("g"))
|
||||
.addNodeCondComponent(new ExecutableEntity().setId("chain2")
|
||||
)).build()
|
||||
).build();
|
||||
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getExecuteStepStr());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.yomahub.liteflow.test.builder;
|
||||
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
//基于builder模式的单元测试
|
||||
//这里测试的是通过spring去扫描,但是通过代码去构建chain的用例
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = BuilderELDeclMultiSpringbootTest2.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.builder.cmp2"})
|
||||
public class BuilderELDeclMultiSpringbootTest2 extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//通过spring去扫描组件,通过代码去构建chain
|
||||
@Test
|
||||
public void testBuilder() throws Exception {
|
||||
LiteFlowChainELBuilder.createChain().setChainName("chain1").setEL(
|
||||
"THEN(h, i, j)"
|
||||
).build();
|
||||
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("h==>i==>j", response.getExecuteStepStr());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class ACmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class BCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class CCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class DCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.annotation.LiteflowSwitchCmpDefine;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowSwitchCmpDefine
|
||||
public class ECmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS_SWITCH)
|
||||
public String processSwitch(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("ECmp executed!");
|
||||
return "chain2";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class FCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("FCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class GCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("GCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("h")
|
||||
@LiteflowCmpDefine
|
||||
public class HCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("HCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("i")
|
||||
@LiteflowCmpDefine
|
||||
public class ICmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("ICmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.builder.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent("j")
|
||||
@LiteflowCmpDefine
|
||||
public class JCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("JCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package com.yomahub.liteflow.test.cmpRetry;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* 测试springboot下的节点执行器
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.5.10
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/cmpRetry/application.properties")
|
||||
@SpringBootTest(classes = LiteflowRetryELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.cmpRetry.cmp"})
|
||||
public class LiteflowRetryELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//全局重试配置测试
|
||||
@Test
|
||||
public void testRetry1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("a==>b==>b==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//单个组件重试配置测试
|
||||
@Test
|
||||
public void testRetry2() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals("c==>c==>c==>c==>c==>c", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//单个组件指定异常,但抛出的并不是指定异常的场景测试
|
||||
@Test
|
||||
public void testRetry3() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
//单个组件指定异常重试,抛出的是指定异常或者
|
||||
@Test
|
||||
public void testRetry4() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals("e==>e==>e==>e==>e==>e", response.getExecuteStepStr());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.yomahub.liteflow.test.cmpRetry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.annotation.LiteflowRetry;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
private int flag = 0;
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
if (flag < 2){
|
||||
flag++;
|
||||
throw new RuntimeException("demo exception");
|
||||
}
|
||||
}
|
||||
|
||||
@LiteflowRetry(5)
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
throw new RuntimeException("demo exception");
|
||||
}
|
||||
|
||||
@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
System.out.println("DCmp executed!");
|
||||
throw new RuntimeException("demo exception");
|
||||
}
|
||||
|
||||
@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
System.out.println("ECmp executed!");
|
||||
throw new NullPointerException("demo null exception");
|
||||
}
|
||||
|
||||
@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "f")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
System.out.println("ECmp executed!");
|
||||
throw new NullPointerException("demo null exception");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.AFTER_PROCESS,nodeId = "f")
|
||||
public void after(NodeComponent bindCmp) {
|
||||
System.out.println("ECmp executed!");
|
||||
throw new NullPointerException("demo null exception");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.yomahub.liteflow.test.cmpStep;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.flow.entity.CmpStep;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* springboot环境最普通的例子测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/cmpStep/application.properties")
|
||||
@SpringBootTest(classes = CmpStepELDeclSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.cmpStep.cmp"})
|
||||
public class CmpStepELDeclSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testStep() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertTrue(response.getExecuteSteps().get("a").isSuccess());
|
||||
Assert.assertTrue(response.getExecuteSteps().get("b").isSuccess());
|
||||
Assert.assertFalse(response.getExecuteSteps().get("c").isSuccess());
|
||||
Assert.assertFalse(response.getExecuteSteps().get("d").isSuccess());
|
||||
Assert.assertTrue(response.getExecuteSteps().get("c").getTimeSpent() >= 2000);
|
||||
Assert.assertEquals(RuntimeException.class, response.getExecuteSteps().get("c").getException().getClass());
|
||||
Assert.assertEquals(RuntimeException.class, response.getExecuteSteps().get("d").getException().getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStep2() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("a==>b", response.getExecuteStepStrWithoutTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStep3() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Map<String, CmpStep> stepMap = response.getExecuteSteps();
|
||||
Assert.assertEquals(2, stepMap.size());
|
||||
Queue<CmpStep> queue = response.getExecuteStepQueue();
|
||||
Assert.assertEquals(5, queue.size());
|
||||
|
||||
Set<String> tagSet = new HashSet<>();
|
||||
response.getExecuteStepQueue().stream().filter(
|
||||
cmpStep -> cmpStep.getNodeId().equals("a")
|
||||
).forEach(cmpStep -> tagSet.add(cmpStep.getTag()));
|
||||
|
||||
Assert.assertEquals(3, tagSet.size());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.yomahub.liteflow.test.cmpStep.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) throws Exception{
|
||||
Thread.sleep(5000L);
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) throws Exception{
|
||||
System.out.println("CCmp executed!");
|
||||
Thread.sleep(2000);
|
||||
throw new RuntimeException("test error c");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
throw new RuntimeException("test error d");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
System.out.println("ECmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS,nodeId = "e")
|
||||
public boolean isAccessE(NodeComponent bindCmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.yomahub.liteflow.test.comments;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/comments/application.properties")
|
||||
@SpringBootTest(classes = LiteflowNodeELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.comments.cmp"})
|
||||
public class LiteflowNodeELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 测试注释
|
||||
@Test
|
||||
public void testAsyncFlow1() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "it's a base request");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertTrue(ListUtil.toList("a==>b==>c==>b","a==>b==>b==>c").contains(response.getExecuteStepStr()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.yomahub.liteflow.test.comments.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.yomahub.liteflow.test.complex;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境EL复杂例子测试1
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/complex/application1.properties")
|
||||
@SpringBootTest(classes = ComplexELDeclMultiSpringbootTest1.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.complex.cmp1"})
|
||||
public class ComplexELDeclMultiSpringbootTest1 extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试复杂例子,优化前
|
||||
//案例来自于文档中 EL规则写法/复杂编排例子/复杂例子一
|
||||
//因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果
|
||||
@Test
|
||||
public void testComplex1_1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1_1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
//测试复杂例子,优化后
|
||||
//案例来自于文档中 EL规则写法/复杂编排例子/复杂例子一
|
||||
//因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果
|
||||
@Test
|
||||
public void testComplex1_2() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1_2", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.yomahub.liteflow.test.complex;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境EL复杂例子测试1
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/complex/application2.properties")
|
||||
@SpringBootTest(classes = ComplexELDeclMultiSpringbootTest2.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.complex.cmp2"})
|
||||
public class ComplexELDeclMultiSpringbootTest2 extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试复杂例子,优化前
|
||||
//案例来自于文档中 EL规则写法/复杂编排例子/复杂例子二
|
||||
//因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果
|
||||
@Test
|
||||
public void testComplex2_1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2_1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
//测试复杂例子,优化后
|
||||
//案例来自于文档中 EL规则写法/复杂编排例子/复杂例子二
|
||||
//因为所有的组件都是空执行,你可以在组件里加上Thread.sleep来模拟业务耗时,再来看这个打出结果
|
||||
@Test
|
||||
public void testComplex2_2() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2_2", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.yomahub.liteflow.test.complex.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig1 {
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "A")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "B")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "C")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "D")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "E")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "F")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeId = "G",nodeType = AnnotationNodeTypeEnum.SWITCH)
|
||||
public String processSwitchG(NodeComponent bindCmp) throws Exception {
|
||||
return "t1";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "H")
|
||||
public void processH(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "J")
|
||||
public void processJ(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "K")
|
||||
public void processK(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "L")
|
||||
public void processL(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "M")
|
||||
public void processM(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "N")
|
||||
public void processN(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "Z")
|
||||
public void processZ(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.complex.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("I")
|
||||
public class ICmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.yomahub.liteflow.test.complex.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig2 {
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "A")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeType = AnnotationNodeTypeEnum.SWITCH,nodeId = "B")
|
||||
public String processSwitchB(NodeComponent bindCmp) {
|
||||
return "t3";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "C")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "D")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "E")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "F")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeType = AnnotationNodeTypeEnum.SWITCH,nodeId = "G")
|
||||
public String processSwitchG(NodeComponent bindCmp) throws Exception {
|
||||
return "t2";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "H")
|
||||
public void processH(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "J")
|
||||
public void processJ(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "K")
|
||||
public void processK(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "L")
|
||||
public void processL(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "M")
|
||||
public void processM(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "N")
|
||||
public void processN(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId ="Z")
|
||||
public void processZ(NodeComponent bindCmp) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.complex.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("I")
|
||||
public class ICmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.yomahub.liteflow.test.component;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 组件功能点测试
|
||||
* 单元测试
|
||||
*
|
||||
* @author donguo.tao
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/component/application.properties")
|
||||
@SpringBootTest(classes = FlowExecutorELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.component.cmp1","com.yomahub.liteflow.test.component.cmp2"})
|
||||
public class FlowExecutorELDeclMultiSpringbootTest extends BaseTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FlowExecutorELDeclMultiSpringbootTest.class);
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//isAccess方法的功能测试
|
||||
@Test
|
||||
public void testIsAccess() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", 101);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertNotNull(response.getSlot().getResponseData());
|
||||
}
|
||||
|
||||
//组件抛错的功能点测试
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testComponentException() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", 0);
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals("/ by zero", response.getMessage());
|
||||
ReflectionUtils.rethrowException(response.getCause());
|
||||
}
|
||||
|
||||
//isContinueOnError方法的功能点测试
|
||||
@Test
|
||||
public void testIsContinueOnError() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", 0);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertNull(response.getCause());
|
||||
}
|
||||
|
||||
//isEnd方法的功能点测试
|
||||
@Test
|
||||
public void testIsEnd() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", 10);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("d",response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//setIsEnd方法的功能点测试
|
||||
@Test
|
||||
public void testSetIsEnd1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", 10);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("e",response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
//条件组件的功能点测试
|
||||
@Test
|
||||
public void testNodeCondComponent() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", 0);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
//测试setIsEnd如果为true,continueError也为true,那不应该continue了
|
||||
@Test
|
||||
public void testSetIsEnd2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", 10);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("g",response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.yomahub.liteflow.test.component.cmp1;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.util.JsonUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig1 {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("AComp executed!");
|
||||
bindCmp.getSlot().setResponseData("AComp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS,nodeId = "a")
|
||||
public boolean isAccessA(NodeComponent bindCmp) {
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
if (Objects.nonNull(requestData) && requestData > 100){
|
||||
return true;
|
||||
}
|
||||
System.out.println("AComp isAccess false.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BComp executed!");
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
Integer divisor = 130;
|
||||
Integer result = divisor / requestData;
|
||||
bindCmp.getSlot().setResponseData(result);
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS,nodeId = "b")
|
||||
public boolean isAccessB(NodeComponent bindCmp) {
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
if (Objects.nonNull(requestData)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CComp executed!");
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
Integer divisor = 130;
|
||||
Integer result = divisor / requestData;
|
||||
bindCmp.getSlot().setResponseData(result);
|
||||
System.out.println("responseData="+Integer.parseInt(bindCmp.getSlot().getResponseData()));
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR,nodeId = "c")
|
||||
public boolean isContinueOnErrorC(NodeComponent bindCmp) {
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
if (Objects.nonNull(requestData)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("DComp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_END,nodeId = "d")
|
||||
public boolean isEndD(NodeComponent bindCmp) {
|
||||
//组件的process执行完之后才会执行isEnd
|
||||
Object requestData = bindCmp.getSlot().getResponseData();
|
||||
if (Objects.isNull(requestData)){
|
||||
System.out.println("DComp flow isEnd, because of responseData is null.");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) throws Exception {
|
||||
System.out.println("EComp executed!");
|
||||
Object responseData = bindCmp.getSlot().getResponseData();
|
||||
if (Objects.isNull(responseData)){
|
||||
System.out.println("EComp responseData flow must be set end .");
|
||||
//执行到某个条件时,手动结束流程。
|
||||
bindCmp.setIsEnd(true);
|
||||
}
|
||||
System.out.println("EComp responseData responseData=" + JsonUtil.toJsonString(responseData));
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "g")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
System.out.println("GCmp executed!");
|
||||
bindCmp.setIsEnd(true);
|
||||
}
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR)
|
||||
public boolean isContinueOnError(NodeComponent bindCmp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "h")
|
||||
public void processH(NodeComponent bindCmp) {
|
||||
System.out.println("HCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.yomahub.liteflow.test.component.cmp2;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@LiteflowComponent
|
||||
public class FCondCmp{
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeId = "f",nodeType = AnnotationNodeTypeEnum.SWITCH)
|
||||
public String processSwitchF(NodeComponent bindCmp) {
|
||||
Integer requestData = bindCmp.getRequestData();
|
||||
if (Objects.isNull(requestData)){
|
||||
return "d";
|
||||
} else if(requestData == 0){
|
||||
return "c";
|
||||
} else {
|
||||
return "b";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.yomahub.liteflow.test.customMethodName;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 声明式组件自定义方法的测试用例
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.7.2
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/customMethodName/application.properties")
|
||||
@SpringBootTest(classes = CustomMethodNameELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.customMethodName.cmp"})
|
||||
public class CustomMethodNameELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testCustomMethodName() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.yomahub.liteflow.test.customMethodName.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processAcmp(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS,nodeId = "a")
|
||||
public boolean isAcmpAccess(NodeComponent bindCmp){
|
||||
return true;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.BEFORE_PROCESS,nodeId = "a")
|
||||
public void beforeAcmp(String nodeId, Slot slot){
|
||||
System.out.println("before A");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.AFTER_PROCESS,nodeId = "a")
|
||||
public void afterAcmp(String nodeId, Slot slot){
|
||||
System.out.println("after A");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_SUCCESS,nodeId ="a")
|
||||
public void onAcmpSuccess(NodeComponent bindCmp){
|
||||
System.out.println("Acmp success");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_ERROR,nodeId = "a")
|
||||
public void onAcmpError(NodeComponent bindCmp){
|
||||
System.out.println("Acmp error");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.IS_END,nodeId = "a")
|
||||
public boolean isAcmpEnd(NodeComponent bindCmp) {
|
||||
System.out.println("Acmp end config");
|
||||
return false;
|
||||
}
|
||||
///////////////////////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processBcmp(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.yomahub.liteflow.test.customNodes;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境下自定义声明节点的测试
|
||||
* 不通过spring扫描的方式,通过在配置文件里定义nodes的方式
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/customNodes/application.properties")
|
||||
@SpringBootTest(classes = CustomNodesELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.customNodes.domain"})
|
||||
public class CustomNodesELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testCustomNodes() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class ACmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class BCmp{
|
||||
|
||||
@Resource
|
||||
private DemoDomain demoDomain;
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
demoDomain.sayHi();
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class CCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class DCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class ECmp{
|
||||
|
||||
@Resource
|
||||
private DemoDomain demoDomain;
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
demoDomain.sayHi();
|
||||
System.out.println("ECmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.customNodes.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
@LiteflowCmpDefine
|
||||
public class FCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("FCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.yomahub.liteflow.test.customNodes.domain;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class DemoDomain {
|
||||
|
||||
public void sayHi(){
|
||||
System.out.println("hi");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.yomahub.liteflow.test.customWhenThreadPool;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.thread.ExecutorBuilder;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class CustomThreadExecutor1 implements ExecutorBuilder {
|
||||
|
||||
@Override
|
||||
public ExecutorService buildExecutor() {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
//只有在非spring的场景下liteflowConfig才会为null
|
||||
if (ObjectUtil.isNull(liteflowConfig)) {
|
||||
liteflowConfig = new LiteflowConfig();
|
||||
}
|
||||
return buildDefaultExecutor(
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenQueueLimit(),
|
||||
"customer-when-1-thead-");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.yomahub.liteflow.test.customWhenThreadPool;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.thread.ExecutorBuilder;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class CustomThreadExecutor2 implements ExecutorBuilder {
|
||||
@Override
|
||||
public ExecutorService buildExecutor() {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
//只有在非spring的场景下liteflowConfig才会为null
|
||||
if (ObjectUtil.isNull(liteflowConfig)) {
|
||||
liteflowConfig = new LiteflowConfig();
|
||||
}
|
||||
return buildDefaultExecutor(
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenQueueLimit(),
|
||||
"customer-when-2-thead-");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.yomahub.liteflow.test.customWhenThreadPool;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.thread.ExecutorBuilder;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class CustomThreadExecutor3 implements ExecutorBuilder {
|
||||
@Override
|
||||
public ExecutorService buildExecutor() {
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
//只有在非spring的场景下liteflowConfig才会为null
|
||||
if (ObjectUtil.isNull(liteflowConfig)) {
|
||||
liteflowConfig = new LiteflowConfig();
|
||||
}
|
||||
return buildDefaultExecutor(
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenMaxWorkers(),
|
||||
liteflowConfig.getWhenQueueLimit(),
|
||||
"customer-when-3-thead-");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.yomahub.liteflow.test.customWhenThreadPool;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境下异步线程超时日志打印测试
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/customWhenThreadPool/application.properties")
|
||||
@SpringBootTest(classes = CustomWhenThreadPoolELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.customWhenThreadPool.cmp"})
|
||||
public class CustomWhenThreadPoolELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
/**
|
||||
* 测试全局线程池配置
|
||||
*/
|
||||
@Test
|
||||
public void testGlobalThreadPool() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain", "arg");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertTrue(context.getData("threadName").toString().startsWith("lf-when-thead"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试全局和when上自定义线程池-优先以when上为准
|
||||
*/
|
||||
@Test
|
||||
public void testGlobalAndCustomWhenThreadPool() {
|
||||
LiteflowResponse response1 = flowExecutor.execute2Resp("chain1", "arg");
|
||||
DefaultContext context = response1.getFirstContextBean();
|
||||
Assert.assertTrue(response1.isSuccess());
|
||||
Assert.assertTrue(context.getData("threadName").toString().startsWith("customer-when-1-thead"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* when配置的线程池可以共用
|
||||
*/
|
||||
@Test
|
||||
public void testCustomWhenThreadPool() {
|
||||
// 使用when - thread1
|
||||
testGlobalAndCustomWhenThreadPool();
|
||||
// chain配置同一个thead1
|
||||
LiteflowResponse response2 = flowExecutor.execute2Resp("chain2", "arg");
|
||||
DefaultContext context = response2.getFirstContextBean();
|
||||
Assert.assertTrue(response2.isSuccess());
|
||||
Assert.assertTrue(context.getData("threadName").toString().startsWith("customer-when-1-thead"));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("threadName", Thread.currentThread().getName());
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("threadName", Thread.currentThread().getName());
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("threadName", Thread.currentThread().getName());
|
||||
System.out.println("DCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("threadName", Thread.currentThread().getName());
|
||||
System.out.println("ECmp executed!");
|
||||
}
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "f")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("threadName", Thread.currentThread().getName());
|
||||
System.out.println("FCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.yomahub.liteflow.test.event;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* springboot环境最普通的例子测试
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.4
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/event/application.properties")
|
||||
@SpringBootTest(classes = EventELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.event.cmp"})
|
||||
public class EventELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
//测试组件成功事件
|
||||
@Test
|
||||
public void testEvent1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertEquals("abc", context.getData("test"));
|
||||
}
|
||||
|
||||
//测试组件失败事件
|
||||
@Test
|
||||
public void testEvent2() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals(NullPointerException.class, response.getCause().getClass());
|
||||
Assert.assertEquals("ab", context.getData("test"));
|
||||
Assert.assertEquals("error:d", context.getData("error"));
|
||||
}
|
||||
|
||||
//测试组件失败事件本身抛出异常
|
||||
@Test
|
||||
public void testEvent3() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
DefaultContext context = response.getFirstContextBean();
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals(NullPointerException.class, response.getCause().getClass());
|
||||
Assert.assertEquals("a", context.getData("test"));
|
||||
Assert.assertEquals("error:e", context.getData("error"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.yomahub.liteflow.test.event.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("test","");
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_SUCCESS,nodeId = "a")
|
||||
public void onSuccessA(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
String str = context.getData("test");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("test", str);
|
||||
}
|
||||
////////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_SUCCESS,nodeId = "b")
|
||||
public void onSuccessB(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
String str = context.getData("test");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("test", str);
|
||||
}
|
||||
///////////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_SUCCESS,nodeId = "c")
|
||||
public void onSuccessC(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
String str = context.getData("test");
|
||||
str += bindCmp.getNodeId();
|
||||
context.setData("test", str);
|
||||
}
|
||||
///////////////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) throws Exception{
|
||||
System.out.println("CCmp executed!");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_ERROR,nodeId = "d")
|
||||
public void onErrorD(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("error","error:"+bindCmp.getNodeId());
|
||||
}
|
||||
///////////////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
|
||||
public void processE(NodeComponent bindCmp) throws Exception{
|
||||
System.out.println("CCmp executed!");
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.ON_ERROR,nodeId = "e")
|
||||
public void onErrorE(NodeComponent bindCmp) throws Exception {
|
||||
DefaultContext context = bindCmp.getFirstContextBean();
|
||||
context.setData("error","error:"+bindCmp.getNodeId());
|
||||
throw new IllegalAccessException("错误事件回调本身抛出异常");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.yomahub.liteflow.test.exception;
|
||||
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
|
||||
/**
|
||||
* 用户自定义带状态码的异常
|
||||
*/
|
||||
public class CustomStatefulException extends LiteFlowException {
|
||||
public CustomStatefulException(String code, String message) {
|
||||
super(code, message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package com.yomahub.liteflow.test.exception;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.exception.ChainDuplicateException;
|
||||
import com.yomahub.liteflow.exception.ConfigErrorException;
|
||||
import com.yomahub.liteflow.exception.FlowExecutorNotInitException;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 流程执行异常
|
||||
* 单元测试
|
||||
*
|
||||
* @author zendwang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Exception1ELDeclMultiSpringBootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class Exception1ELDeclMultiSpringBootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
/**
|
||||
* 验证 chain 节点重复的异常
|
||||
*/
|
||||
@Test(expected = ChainDuplicateException.class)
|
||||
public void testChainDuplicateException() {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
config.setRuleSource("exception/flow-exception.el.xml");
|
||||
flowExecutor.init();
|
||||
}
|
||||
|
||||
@Test(expected = ConfigErrorException.class)
|
||||
public void testConfigErrorException() {
|
||||
flowExecutor.setLiteflowConfig(null);
|
||||
flowExecutor.init();
|
||||
}
|
||||
|
||||
@Test(expected = FlowExecutorNotInitException.class)
|
||||
public void testFlowExecutorNotInitException() {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
config.setRuleSource("error/flow.txt");
|
||||
flowExecutor.init();
|
||||
}
|
||||
|
||||
@Test(expected = FlowExecutorNotInitException.class)
|
||||
public void testNoConditionInChainException() throws Exception {
|
||||
LiteflowConfig config = LiteflowConfigGetter.get();
|
||||
config.setRuleSource("exception/flow-blank.el.xml");
|
||||
flowExecutor.init();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.yomahub.liteflow.test.exception;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.exception.ChainNotFoundException;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.exception.NoSwitchTargetNodeException;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 流程执行异常
|
||||
* 单元测试
|
||||
*
|
||||
* @author zendwang
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/exception/application.properties")
|
||||
@SpringBootTest(classes = Exception2ELDeclMultiSpringBootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.exception.cmp"})
|
||||
public class Exception2ELDeclMultiSpringBootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test(expected = ChainNotFoundException.class)
|
||||
public void testChainNotFoundException() throws Exception {
|
||||
flowExecutor.execute("chain0", "it's a request");
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testComponentCustomException() throws Exception {
|
||||
flowExecutor.execute("chain1", "exception");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSlotFromResponseWhenException() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "test");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertNotNull(response.getCause());
|
||||
Assert.assertNotNull(response.getSlot());
|
||||
}
|
||||
|
||||
@Test(expected = NoSwitchTargetNodeException.class)
|
||||
public void testNoTargetFindException() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "test");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
throw response.getCause();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeCustomStatefulException() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "custom-stateful-exception");
|
||||
Assert.assertFalse(response.isSuccess());
|
||||
Assert.assertEquals("300", response.getCode());
|
||||
Assert.assertNotNull(response.getCause());
|
||||
Assert.assertTrue(response.getCause() instanceof LiteFlowException);
|
||||
Assert.assertNotNull(response.getSlot());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotInvokeCustomStatefulException() {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "test");
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
Assert.assertNull(response.getCode());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.yomahub.liteflow.test.exception.cmp;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.AnnotationNodeTypeEnum;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.test.exception.CustomStatefulException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CmpConfig.class);
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
String str = bindCmp.getRequestData();
|
||||
if(StrUtil.isNotBlank(str) && str.equals("exception")) {
|
||||
throw new RuntimeException("chain execute execption");
|
||||
}
|
||||
LOG.info("Acomp executed!");
|
||||
}
|
||||
//////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) throws InterruptedException {
|
||||
String str = bindCmp.getRequestData();
|
||||
if(StrUtil.isNotBlank(str) && str.equals("when")) {
|
||||
try {
|
||||
LOG.info("Bcomp sleep begin");
|
||||
Thread.sleep(3000);
|
||||
LOG.info("Bcomp sleep end");
|
||||
} catch (InterruptedException e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
LOG.info("Bcomp executed!");
|
||||
}
|
||||
//////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void processC(NodeComponent bindCmp) {
|
||||
LOG.info("Ccomp executed!");
|
||||
}
|
||||
|
||||
//////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "d")
|
||||
public void processD(NodeComponent bindCmp) {
|
||||
if(1==1){
|
||||
int a = 1/0;
|
||||
}
|
||||
LOG.info("Dcomp executed!");
|
||||
}
|
||||
////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH,nodeId = "e",nodeType = AnnotationNodeTypeEnum.SWITCH)
|
||||
public String processSwitchE(NodeComponent bindCmp) throws Exception {
|
||||
return "a";
|
||||
}
|
||||
//////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "f")
|
||||
public void processF(NodeComponent bindCmp) {
|
||||
String str = bindCmp.getRequestData();
|
||||
if(StrUtil.isNotBlank(str) && str.equals("custom-stateful-exception")) {
|
||||
throw new CustomStatefulException("300", "chain execute custom stateful execption");
|
||||
}
|
||||
LOG.info("Fcomp executed!");
|
||||
}
|
||||
////////
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "g")
|
||||
public void processG(NodeComponent bindCmp) {
|
||||
LOG.info("Gcomp executed!");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue