Merge branch 'dev' of https://gitee.com/dromara/liteFlow into issue/#I8MW6Q-2
Conflicts: liteflow-core/src/main/java/com/yomahub/liteflow/script/ScriptExecutor.java
This commit is contained in:
commit
d6b0e684cf
25
README.md
25
README.md
|
@ -62,6 +62,31 @@ Looking forward to your use!
|
|||
|
||||
Discord Link: [https://discord.gg/MpdBSBnFTu](https://discord.gg/MpdBSBnFTu)
|
||||
|
||||
## 👑LF CLUB Community
|
||||
|
||||
LF CLUB is a premium paid community founded by the author of LiteFlow.
|
||||
|
||||
LF CLUB can help all users of the LiteFlow framework, as well as potential developers who want to use LiteFlow.
|
||||
|
||||
LF CLUB provides the following services:
|
||||
|
||||
**1.Weekly releases of a condensed analysis series for LF. As long as users study along with the Planet series articles, they will definitely be able to fully grasp LF.**
|
||||
|
||||
**2.Provide a Q&A service where members can ask unlimited questions and receive detailed replies and guidance on the same day.**
|
||||
|
||||
**3.Each enrolled user is entitled to two remote one-on-one tutoring sessions per year as part of the remote assistance service.**
|
||||
|
||||
**4.Every 1 to 2 days, there will be updates on LF's current progress and the focus of the next version.**
|
||||
|
||||
The LF CLUB can solve all the problems you encounter when using the LiteFlow framework. It offers a series of courses to help you gain a deep understanding of the LiteFlow framework. Unlike the WeChat community, the LF CLUB prioritizes the importance of questions and provides detailed answers.
|
||||
|
||||
Exclusive content helps you gain a profound understanding without the need to search for answers on other platforms. The author personally teaches, providing expert guidance at your fingertips, eliminating the need to seek help from others.
|
||||
|
||||
To join the LF CLUB, please scan the QR code below or click on the image to go directly to the website.
|
||||
|
||||
<a href="https://t.zsxq.com/16VxfATen"><img src="static/img/zsxq-github.png"></a>
|
||||
|
||||
|
||||
## 🦾Sponsor
|
||||
|
||||
**MISBoot低代码开发平台**
|
||||
|
|
|
@ -57,6 +57,30 @@ LiteFlow拥有极其详细易懂的文档体系,能帮助你解决在使用框
|
|||
|
||||
LiteFlow期待你的了解!
|
||||
|
||||
## 👑LF CLUB社区
|
||||
|
||||
LF CLUB是由LiteFlow作者创办的高级付费社区
|
||||
|
||||
LF CLUB能帮助到所有LiteFlow框架的使用者,以及想使用LiteFlow的潜在开发者。
|
||||
|
||||
LF CLUB提供以下服务:
|
||||
|
||||
**1.每周发布一篇LF的解析精华系列。从头开始解析LF,只要跟着星球解析系列走,使用者一定能完全掌握LF。**
|
||||
|
||||
**2.提供答疑服务,会员可以无限制提问,当天必定得到详细的回复和指导建议。**
|
||||
|
||||
**3.每个加入的用户每年提供2次远程一对一答疑,远程协助服务。**
|
||||
|
||||
**4.每1到2天会分享LF目前的进度,以及下一个版本的重点。**
|
||||
|
||||
LF CLUB里能解决你在使用LiteFlow框架时碰到的所有问题,并有系列课程能帮助你深刻理解LiteFlow框架,不同于微信社区,LF CLUB的问题优先级程度是最高的,且答疑非常详细。
|
||||
|
||||
独家内容帮助深刻理解,不用在其他平台去搜索问题的答案。作者亲授,相当于随时拥有专家在身边,不用再去求助其他人。
|
||||
|
||||
加入LF CLUB,请扫描以下二维码,或者直接点击图片也可以直达:
|
||||
|
||||
<a href="https://t.zsxq.com/16jLy4Bj6"><img src="static/img/zsxq-gitee.png"></a>
|
||||
|
||||
## 🦾赞助商
|
||||
|
||||
**MISBoot低代码开发平台**
|
||||
|
|
|
@ -12,6 +12,12 @@ import java.lang.annotation.*;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Deprecated
|
||||
/**
|
||||
* This class has been deprecated due to its only component retry function. Please use the retry method in the EL expression.
|
||||
* @Deprecated
|
||||
* @see # retry(int retryTimes) e.g. THEN( a, b.retry(3) ); WHEN( a, b ).retry(3);
|
||||
*/
|
||||
public @interface LiteflowRetry {
|
||||
|
||||
@LFAliasFor("retry")
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.yomahub.liteflow.annotation.util;
|
|||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LFAliasFor;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
@ -10,15 +11,25 @@ import java.lang.reflect.AnnotatedElement;
|
|||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 注解工具类
|
||||
* 此工具类带缓存
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class AnnoUtil {
|
||||
|
||||
private static Map<String, Annotation> annoCacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
String cacheKey = StrUtil.format("{}-{}", annotatedElement, annotationType.getSimpleName());
|
||||
|
||||
if (annoCacheMap.containsKey(cacheKey)){
|
||||
return (A)annoCacheMap.get(cacheKey);
|
||||
}
|
||||
|
||||
A annotation = AnnotationUtil.getAnnotation(annotatedElement, annotationType);
|
||||
if (ObjectUtil.isNull(annotation)) {
|
||||
return null;
|
||||
|
@ -42,6 +53,8 @@ public class AnnoUtil {
|
|||
}
|
||||
});
|
||||
|
||||
annoCacheMap.put(cacheKey, annotation);
|
||||
|
||||
return annotation;
|
||||
}
|
||||
|
||||
|
@ -53,5 +66,4 @@ public class AnnoUtil {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ public class LiteFlowChainELBuilder {
|
|||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_SECONDS, Object.class, new MaxWaitSecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.MAX_WAIT_MILLISECONDS, Object.class, new MaxWaitMillisecondsOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.PARALLEL, Object.class, new ParallelOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.RETRY, Object.class, new RetryOperator());
|
||||
}
|
||||
|
||||
public static LiteFlowChainELBuilder createChain() {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.RetryCondition;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rain
|
||||
* @since 2.12.0
|
||||
*
|
||||
*/
|
||||
public class RetryOperator extends BaseOperator<Condition> {
|
||||
@Override
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeGteTwo(objects);
|
||||
Executable executable = OperatorHelper.convert(objects[0], Executable.class);
|
||||
Integer retryTimes = OperatorHelper.convert(objects[1], Integer.class);
|
||||
RetryCondition retryCondition = new RetryCondition();
|
||||
retryCondition.addExecutable(executable);
|
||||
retryCondition.setRetryTimes(retryTimes);
|
||||
if(objects.length > 2) {
|
||||
Class[] forExceptions = new Class[objects.length - 2];
|
||||
for(int i = 2; i < objects.length; i ++) {
|
||||
String className = OperatorHelper.convert(objects[i], String.class);
|
||||
forExceptions[i - 2] = Class.forName(className);
|
||||
}
|
||||
retryCondition.setRetryForExceptions(forExceptions);
|
||||
}
|
||||
return retryCondition;
|
||||
}
|
||||
|
||||
}
|
|
@ -94,4 +94,6 @@ public interface ChainConstant {
|
|||
|
||||
String EXTENDS = "extends";
|
||||
|
||||
String RETRY = "retry";
|
||||
|
||||
}
|
||||
|
|
|
@ -280,6 +280,10 @@ public abstract class NodeComponent {
|
|||
return this.getSlot().getContextBean(contextBeanClazz);
|
||||
}
|
||||
|
||||
public <T> T getContextBean(String contextName) {
|
||||
return this.getSlot().getContextBean(contextName);
|
||||
}
|
||||
|
||||
public String getNodeId() {
|
||||
return nodeId;
|
||||
}
|
||||
|
|
|
@ -101,6 +101,10 @@ public class LiteflowResponse {
|
|||
return this.getSlot().getContextBean(contextBeanClazz);
|
||||
}
|
||||
|
||||
public <T> T getContextBean(String contextName) {
|
||||
return this.getSlot().getContextBean(contextName);
|
||||
}
|
||||
|
||||
public Map<String, List<CmpStep>> getExecuteSteps() {
|
||||
Map<String, List<CmpStep>> map = new LinkedHashMap<>();
|
||||
this.getSlot().getExecuteSteps().forEach(cmpStep -> {
|
||||
|
|
|
@ -21,8 +21,6 @@ import com.yomahub.liteflow.flow.executor.NodeExecutor;
|
|||
import com.yomahub.liteflow.flow.executor.NodeExecutorHelper;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.property.LiteflowConfigGetter;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
|
@ -30,6 +28,7 @@ import com.yomahub.liteflow.slot.Slot;
|
|||
* Node节点,实现可执行器 Node节点并不是单例的,每构建一次都会copy出一个新的实例
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @author luo yi
|
||||
*/
|
||||
public class Node implements Executable, Cloneable, Rollbackable{
|
||||
|
||||
|
@ -57,6 +56,9 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
|
||||
private String currChainId;
|
||||
|
||||
// node 的 isAccess 结果,主要用于 WhenCondition 的提前 isAccess 判断,避免 isAccess 方法重复执行
|
||||
private TransmittableThreadLocal<Boolean> accessResult = new TransmittableThreadLocal<>();
|
||||
|
||||
private TransmittableThreadLocal<Integer> loopIndexTL = new TransmittableThreadLocal<>();
|
||||
|
||||
private TransmittableThreadLocal<Object> currLoopObject = new TransmittableThreadLocal<>();
|
||||
|
@ -125,16 +127,13 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
throw new FlowSystemException("there is no instance for node id " + id);
|
||||
}
|
||||
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try {
|
||||
// 把线程属性赋值给组件对象
|
||||
instance.setSlotIndex(slotIndex);
|
||||
instance.setRefNode(this);
|
||||
|
||||
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
|
||||
|
||||
// 判断是否可执行,所以isAccess经常作为一个组件进入的实际判断要素,用作检查slot里的参数的完备性
|
||||
if (instance.isAccess()) {
|
||||
if (getAccessResult() || instance.isAccess()) {
|
||||
LOG.info("[O]start component[{}] execution", instance.getDisplayName());
|
||||
|
||||
// 这里开始进行重试的逻辑和主逻辑的运行
|
||||
|
@ -142,8 +141,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
.buildNodeExecutor(instance.getNodeExecutorClass());
|
||||
// 调用节点执行器进行执行
|
||||
nodeExecutor.execute(instance);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG.info("[X]skip component[{}] execution", instance.getDisplayName());
|
||||
}
|
||||
// 如果组件覆盖了isEnd方法,或者在在逻辑中主要调用了setEnd(true)的话,流程就会立马结束
|
||||
|
@ -178,6 +176,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
instance.removeIsEnd();
|
||||
instance.removeRefNode();
|
||||
removeLoopIndex();
|
||||
removeAccessResult();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,6 +252,19 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
return currChainId;
|
||||
}
|
||||
|
||||
public boolean getAccessResult() {
|
||||
Boolean result = this.accessResult.get();
|
||||
return result == null ? false : result;
|
||||
}
|
||||
|
||||
public void setAccessResult(boolean accessResult) {
|
||||
this.accessResult.set(accessResult);
|
||||
}
|
||||
|
||||
public void removeAccessResult() {
|
||||
this.accessResult.remove();
|
||||
}
|
||||
|
||||
public void setLoopIndex(int index) {
|
||||
this.loopIndexTL.set(index);
|
||||
}
|
||||
|
@ -299,6 +311,7 @@ public class Node implements Executable, Cloneable, Rollbackable{
|
|||
Node node = (Node)this.clone();
|
||||
node.loopIndexTL = new TransmittableThreadLocal<>();
|
||||
node.currLoopObject = new TransmittableThreadLocal<>();
|
||||
node.accessResult = new TransmittableThreadLocal<>();
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import cn.hutool.core.text.StrFormatter;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.exception.ChainEndException;
|
||||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rain
|
||||
* @since 2.12.0
|
||||
*
|
||||
*/
|
||||
public class RetryCondition extends ThenCondition{
|
||||
|
||||
private final LFLog LOG = LFLoggerManager.getLogger(this.getClass());
|
||||
|
||||
private Integer retryTimes;
|
||||
|
||||
private Class<? extends Exception>[] retryForExceptions = new Class[] { Exception.class };
|
||||
|
||||
public Class<? extends Exception>[] getRetryForExceptions() {
|
||||
return retryForExceptions;
|
||||
}
|
||||
|
||||
public void setRetryForExceptions(Class<? extends Exception>[] retryForExceptions) {
|
||||
this.retryForExceptions = retryForExceptions;
|
||||
}
|
||||
|
||||
public Integer getRetryTimes() {
|
||||
return retryTimes;
|
||||
}
|
||||
|
||||
public void setRetryTimes(Integer retryTimes) {
|
||||
this.retryTimes = retryTimes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
int retryTimes = this.getRetryTimes() < 0 ? 0 : this.getRetryTimes();
|
||||
List<Class<? extends Exception>> forExceptions = Arrays.asList(this.getRetryForExceptions());
|
||||
for (int i = 0; i <= retryTimes; i ++) {
|
||||
try {
|
||||
if(i == 0) {
|
||||
super.executeCondition(slotIndex);
|
||||
} else {
|
||||
retry(slotIndex, i);
|
||||
}
|
||||
break;
|
||||
} catch (ChainEndException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// 判断抛出的异常是不是指定异常的子类
|
||||
boolean flag = forExceptions.stream().anyMatch(clazz -> clazz.isAssignableFrom(e.getClass()));
|
||||
if(!flag || i >= retryTimes) {
|
||||
if(retryTimes > 0) {
|
||||
String retryFailMsg = StrFormatter.format("retry fail when executing the chain[{}] because {} occurs {}.",
|
||||
this.getCurrChainId(), this.getCurrentExecutableId(), e);
|
||||
LOG.error(retryFailMsg);
|
||||
}
|
||||
throw e;
|
||||
} else {
|
||||
DataBus.getSlot(slotIndex).removeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void retry(Integer slotIndex, int retryTime) throws Exception {
|
||||
LOG.info("{} performs {} retry ", this.getCurrentExecutableId(), retryTime);
|
||||
super.executeCondition(slotIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前组件的 id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getCurrentExecutableId() {
|
||||
// retryCondition 只有一个 Executable
|
||||
Executable executable = this.getExecutableList().get(0);
|
||||
if (ObjectUtil.isNotNull(executable.getId())) {
|
||||
// 已经有 id 了
|
||||
return executable.getId();
|
||||
}
|
||||
// 定义 id
|
||||
switch (executable.getExecuteType()) {
|
||||
// chain 和 node 一般都有 id
|
||||
case CHAIN:
|
||||
return ((Chain) executable).getChainId();
|
||||
case CONDITION:
|
||||
return "condition-" + ((Condition) executable).getConditionType().getName();
|
||||
case NODE:
|
||||
return "node-" + ((Node) executable).getType().getCode();
|
||||
default:
|
||||
return "unknown-executable";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -51,13 +51,17 @@ public class ThenCondition extends Condition {
|
|||
}
|
||||
catch (Exception e) {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
String chainId = this.getCurrChainId();
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainId)) {
|
||||
slot.setSubException(chainId, e);
|
||||
}
|
||||
else {
|
||||
slot.setException(e);
|
||||
//正常情况下slot不可能为null
|
||||
//当设置了超时后,还在运行的组件就有可能因为主流程已经结束释放slot而导致slot为null
|
||||
if (slot != null){
|
||||
String chainId = this.getCurrChainId();
|
||||
// 这里事先取到exception set到slot里,为了方便finally取到exception
|
||||
if (slot.isSubChain(chainId)) {
|
||||
slot.setSubException(chainId, e);
|
||||
}
|
||||
else {
|
||||
slot.setException(e);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
|
|
@ -31,9 +31,10 @@ public class AllOfParallelExecutor extends ParallelStrategyExecutor {
|
|||
|
||||
}
|
||||
|
||||
//在allOf这个场景中,不需要过滤
|
||||
// 在 allOf 这个场景中,不需要过滤
|
||||
@Override
|
||||
protected Stream<Executable> filterAccess(Stream<Executable> stream, Integer slotIndex) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package com.yomahub.liteflow.flow.parallel.strategy;
|
||||
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
import com.yomahub.liteflow.flow.parallel.WhenFutureObj;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 完成任一任务
|
||||
|
@ -31,18 +29,4 @@ public class AnyOfParallelExecutor extends ParallelStrategyExecutor {
|
|||
|
||||
}
|
||||
|
||||
//在anyOf这个场景中,需要过滤掉isAccess为false的场景
|
||||
//因为不过滤这个的话,如果加上了 any,那么 isAccess 为 false 那就是最快的了
|
||||
//换句话说,就是anyOf这个场景,isAccess会被执行两次
|
||||
@Override
|
||||
protected Stream<Executable> filterAccess(Stream<Executable> stream, Integer slotIndex) {
|
||||
return stream.filter(executable -> {
|
||||
try {
|
||||
return executable.isAccess(slotIndex);
|
||||
} catch (Exception e) {
|
||||
LOG.error("there was an error when executing the when component isAccess", e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
|
|||
import com.yomahub.liteflow.enums.ParallelStrategyEnum;
|
||||
import com.yomahub.liteflow.exception.WhenExecuteException;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.element.condition.FinallyCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.PreCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
|
@ -93,20 +94,25 @@ public abstract class ParallelStrategyExecutor {
|
|||
// 1.先进行过滤,前置和后置组件过滤掉,因为在 EL Chain 处理的时候已经提出来了
|
||||
// 2.过滤 isAccess 为 false 的情况,因为不过滤这个的话,如果加上了 any,那么 isAccess 为 false 那就是最快的了
|
||||
Stream<Executable> stream = executableList.stream()
|
||||
.filter(executable -> !(executable instanceof PreCondition) && !(executable instanceof FinallyCondition))
|
||||
.filter(executable -> {
|
||||
try {
|
||||
return executable.isAccess(slotIndex);
|
||||
} catch (Exception e) {
|
||||
LOG.error("there was an error when executing the when component isAccess", e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
.filter(executable -> !(executable instanceof PreCondition) && !(executable instanceof FinallyCondition));
|
||||
return filterAccess(stream, slotIndex);
|
||||
}
|
||||
|
||||
//过滤isAccess的抽象接口方法
|
||||
protected abstract Stream<Executable> filterAccess(Stream<Executable> stream, Integer slotIndex);
|
||||
// 过滤 isAccess 的方法,默认实现,同时为避免同一个 node 的 isAccess 方法重复执行,给 node 设置 isAccess 方法执行结果
|
||||
protected Stream<Executable> filterAccess(Stream<Executable> stream, Integer slotIndex) {
|
||||
return stream.filter(executable -> {
|
||||
try {
|
||||
boolean access = executable.isAccess(slotIndex);
|
||||
if (executable instanceof Node) {
|
||||
((Node) executable).setAccessResult(access);
|
||||
}
|
||||
return access;
|
||||
} catch (Exception e) {
|
||||
LOG.error("there was an error when executing the when component isAccess", e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 WHEN 所需线程池
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package com.yomahub.liteflow.flow.parallel.strategy;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.WhenCondition;
|
||||
import com.yomahub.liteflow.flow.parallel.WhenFutureObj;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 完成指定任务执行器,使用 ID 进行比较
|
||||
|
@ -77,19 +75,4 @@ public class SpecifyParallelExecutor extends ParallelStrategyExecutor {
|
|||
|
||||
}
|
||||
|
||||
//在must这个场景中,需要过滤掉isAccess为false的场景
|
||||
//因为不过滤这个的话,如果加上了 any,那么 isAccess 为 false 那就是最快的了
|
||||
//换句话说,就是must这个场景,isAccess会被执行两次
|
||||
@Override
|
||||
protected Stream<Executable> filterAccess(Stream<Executable> stream, Integer slotIndex) {
|
||||
return stream.filter(executable -> {
|
||||
try {
|
||||
return executable.isAccess(slotIndex);
|
||||
} catch (Exception e) {
|
||||
LOG.error("there was an error when executing the when component isAccess", e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,10 @@ import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
|||
import com.yomahub.liteflow.context.ContextBean;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
import java.util.List;
|
||||
import javax.script.ScriptException;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
|
@ -29,12 +28,6 @@ public abstract class ScriptExecutor {
|
|||
|
||||
public abstract void load(String nodeId, String script);
|
||||
|
||||
// 卸载脚本(不包含 node)
|
||||
public abstract void unLoad(String nodeId);
|
||||
|
||||
// 获取该执行器下的所有 nodeId
|
||||
public abstract List<String> getNodeIds();
|
||||
|
||||
public Object execute(ScriptExecuteWrap wrap) throws Exception{
|
||||
try {
|
||||
return executeScript(wrap);
|
||||
|
@ -62,17 +55,7 @@ public abstract class ScriptExecutor {
|
|||
// key的规则为自定义上下文的simpleName
|
||||
// 比如你的自定义上下文为AbcContext,那么key就为:abcContext
|
||||
// 这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
|
||||
DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
|
||||
ContextBean contextBean = AnnoUtil.getAnnotation(o.getClass(), ContextBean.class);
|
||||
String key;
|
||||
if (contextBean != null && contextBean.value().trim().length() > 0) {
|
||||
key = contextBean.value();
|
||||
}
|
||||
else {
|
||||
key = StrUtil.lowerFirst(o.getClass().getSimpleName());
|
||||
}
|
||||
putConsumer.accept(key, o);
|
||||
});
|
||||
DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(tuple -> putConsumer.accept(tuple.get(0), tuple.get(1)));
|
||||
|
||||
// 把wrap对象转换成元数据map
|
||||
Map<String, Object> metaMap = BeanUtil.beanToMap(wrap);
|
||||
|
@ -94,4 +77,12 @@ public abstract class ScriptExecutor {
|
|||
ScriptBeanManager.getScriptBeanMap().forEach(putIfAbsentConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 利用相应框架编译脚本
|
||||
*
|
||||
* @param script 脚本
|
||||
* @return boolean
|
||||
* @throws Exception 例外
|
||||
*/
|
||||
public abstract Object compile(String script) throws Exception;
|
||||
}
|
||||
|
|
|
@ -46,8 +46,7 @@ public abstract class JSR223ScriptExecutor extends ScriptExecutor {
|
|||
@Override
|
||||
public void load(String nodeId, String script) {
|
||||
try {
|
||||
CompiledScript compiledScript = ((Compilable) scriptEngine).compile(convertScript(script));
|
||||
compiledScriptMap.put(nodeId, compiledScript);
|
||||
compiledScriptMap.put(nodeId, (CompiledScript) compile(script));
|
||||
}
|
||||
catch (Exception e) {
|
||||
String errorMsg = StrUtil.format("script loading error for node[{}], error msg:{}", nodeId, e.getMessage());
|
||||
|
@ -85,4 +84,12 @@ public abstract class JSR223ScriptExecutor extends ScriptExecutor {
|
|||
compiledScriptMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) throws ScriptException {
|
||||
if(scriptEngine == null) {
|
||||
LOG.error("script engine has not init");
|
||||
}
|
||||
return ((Compilable) scriptEngine).compile(convertScript(script));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
package com.yomahub.liteflow.script.validator;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.script.ScriptExecutor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 脚本验证类
|
||||
*
|
||||
* @author Ge_Zuao
|
||||
* @since 2.12.0
|
||||
*/
|
||||
public class ScriptValidator {
|
||||
|
||||
private static final LFLog LOG = LFLoggerManager.getLogger(ScriptValidator.class);
|
||||
|
||||
private static Map<ScriptTypeEnum, ScriptExecutor> scriptExecutors;
|
||||
|
||||
static {
|
||||
List<ScriptExecutor> scriptExecutorList = new ArrayList<>();
|
||||
scriptExecutors = new HashMap<>();
|
||||
ServiceLoader.load(ScriptExecutor.class).forEach(scriptExecutorList::add);
|
||||
scriptExecutorList.stream()
|
||||
.peek(ScriptExecutor::init)
|
||||
.forEach(scriptExecutor -> scriptExecutors.put(scriptExecutor.scriptType(), scriptExecutor));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证脚本逻辑的公共部分
|
||||
*
|
||||
* @param script 脚本
|
||||
* @param scriptType 脚本类型
|
||||
* @return boolean
|
||||
*/
|
||||
private static boolean validateScript(String script, ScriptTypeEnum scriptType){
|
||||
// 未加载任何脚本模块
|
||||
if(scriptExecutors.isEmpty()){
|
||||
LOG.error("The loaded script modules not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 指定脚本语言未加载
|
||||
if (scriptType != null && !scriptExecutors.containsKey(scriptType)) {
|
||||
LOG.error(StrUtil.format("Specified script language {} was not found.", scriptType));
|
||||
return false;
|
||||
}
|
||||
|
||||
// 加载多个脚本语言需要指定语言验证
|
||||
if (scriptExecutors.size() > 1 && scriptType == null) {
|
||||
LOG.error("The loaded script modules more than 1. Please specify the script language.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptExecutor scriptExecutor = (scriptType != null) ? scriptExecutors.get(scriptType) : scriptExecutors.values().iterator().next();
|
||||
try {
|
||||
scriptExecutor.compile(script);
|
||||
} catch (Exception e) {
|
||||
LOG.error(StrUtil.format("{} Script component validate failure. ", scriptExecutor.scriptType()) + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 只引入一种脚本语言时,可以不指定语言验证
|
||||
*
|
||||
* @param script 脚本
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean validate(String script){
|
||||
return validateScript(script, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定脚本语言验证
|
||||
*
|
||||
* @param script 脚本
|
||||
* @param scriptType 脚本类型
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean validate(String script, ScriptTypeEnum scriptType){
|
||||
return validateScript(script, scriptType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多语言脚本批量验证
|
||||
*
|
||||
* @param scripts 脚本
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean validate(Map<ScriptTypeEnum, String> scripts){
|
||||
for(Map.Entry<ScriptTypeEnum, String> script : scripts.entrySet()){
|
||||
if(!validate(script.getValue(), script.getKey())){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -7,10 +7,14 @@
|
|||
*/
|
||||
package com.yomahub.liteflow.slot;
|
||||
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
|
@ -74,13 +78,22 @@ public class DataBus {
|
|||
.map((Function<Class<?>, Object>) ReflectUtil::newInstanceIfPossible)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Slot slot = new Slot(contextBeanList);
|
||||
|
||||
return offerIndex(slot);
|
||||
return offerSlotByBean(contextBeanList);
|
||||
}
|
||||
|
||||
public static int offerSlotByBean(List<Object> contextList) {
|
||||
Slot slot = new Slot(contextList);
|
||||
List<Tuple> contextBeanList = contextList.stream().map(object -> {
|
||||
ContextBean contextBean = AnnoUtil.getAnnotation(object.getClass(), ContextBean.class);
|
||||
String contextKey;
|
||||
if (contextBean != null && StrUtil.isNotBlank(contextBean.value())){
|
||||
contextKey = contextBean.value();
|
||||
}else{
|
||||
contextKey = StrUtil.lowerFirst(object.getClass().getSimpleName());
|
||||
}
|
||||
return new Tuple(contextKey, object);
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
Slot slot = new Slot(contextBeanList);
|
||||
|
||||
return offerIndex(slot);
|
||||
}
|
||||
|
@ -128,7 +141,7 @@ public class DataBus {
|
|||
return SLOTS.get(slotIndex);
|
||||
}
|
||||
|
||||
public static List<Object> getContextBeanList(int slotIndex) {
|
||||
public static List<Tuple> getContextBeanList(int slotIndex) {
|
||||
Slot slot = getSlot(slotIndex);
|
||||
return slot.getContextBeanList();
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ package com.yomahub.liteflow.slot;
|
|||
|
||||
import cn.hutool.core.collection.ConcurrentHashSet;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.lang.Tuple;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.yomahub.liteflow.exception.NoSuchContextBeanException;
|
||||
import com.yomahub.liteflow.exception.NullParamException;
|
||||
import com.yomahub.liteflow.flow.element.Condition;
|
||||
|
@ -29,6 +31,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Slot的抽象类实现
|
||||
|
@ -90,14 +93,14 @@ public class Slot {
|
|||
|
||||
protected ConcurrentHashMap<String, Object> metaDataMap = new ConcurrentHashMap<>();
|
||||
|
||||
private List<Object> contextBeanList;
|
||||
private List<Tuple> contextBeanList;
|
||||
|
||||
private static final ThreadLocal<Deque<Condition>> conditionStack = ThreadLocal.withInitial(LinkedList::new);
|
||||
private static final TransmittableThreadLocal<Deque<Condition>> conditionStack = TransmittableThreadLocal.withInitial(ConcurrentLinkedDeque::new);
|
||||
|
||||
public Slot() {
|
||||
}
|
||||
|
||||
public Slot(List<Object> contextBeanList) {
|
||||
public Slot(List<Tuple> contextBeanList) {
|
||||
this.contextBeanList = contextBeanList;
|
||||
}
|
||||
|
||||
|
@ -448,21 +451,30 @@ public class Slot {
|
|||
metaDataMap.remove(SUB_EXCEPTION_PREFIX + chainId);
|
||||
}
|
||||
|
||||
public List<Object> getContextBeanList() {
|
||||
public List<Tuple> getContextBeanList() {
|
||||
return this.contextBeanList;
|
||||
}
|
||||
|
||||
public <T> T getContextBean(Class<T> contextBeanClazz) {
|
||||
T t = (T) contextBeanList.stream().filter(o -> o.getClass().getName().equals(contextBeanClazz.getName())).findFirst().orElse(null);
|
||||
if (t == null) {
|
||||
Tuple contextTuple = contextBeanList.stream().filter(tuple -> tuple.get(1).getClass().getName().equals(contextBeanClazz.getName())).findFirst().orElse(null);
|
||||
if (contextTuple == null) {
|
||||
contextBeanList.forEach(o -> LOG.info("ChainId[{}], Context class:{},Request class:{}", this.getChainId(), o.getClass().getName(), contextBeanClazz.getName()));
|
||||
throw new NoSuchContextBeanException("this type is not in the context type passed in");
|
||||
}
|
||||
return t;
|
||||
return contextTuple.get(1);
|
||||
}
|
||||
|
||||
public <T> T getContextBean(String contextBeanKey) {
|
||||
Tuple contextTuple = contextBeanList.stream().filter(tuple -> tuple.get(0).equals(contextBeanKey)).findFirst().orElse(null);
|
||||
if (contextTuple == null) {
|
||||
contextBeanList.forEach(o -> LOG.info("ChainId[{}], Context class:{},Request contextBeanKey:{}", this.getChainId(), o.getClass().getName(), contextBeanKey));
|
||||
throw new NoSuchContextBeanException("this context key is not defined");
|
||||
}
|
||||
return contextTuple.get(1);
|
||||
}
|
||||
|
||||
public <T> T getFirstContextBean() {
|
||||
Class<T> firstContextBeanClazz = (Class<T>) this.getContextBeanList().get(0).getClass();
|
||||
Class<T> firstContextBeanClazz = (Class<T>) this.getContextBeanList().get(0).get(1).getClass();
|
||||
return this.getContextBean(firstContextBeanClazz);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ public class GraalJavaScriptExecutor extends ScriptExecutor {
|
|||
@Override
|
||||
public void load(String nodeId, String script) {
|
||||
try {
|
||||
String wrapScript = StrUtil.format("function process(){{}} process();", script);
|
||||
scriptMap.put(nodeId, Source.create("js", wrapScript));
|
||||
scriptMap.put(nodeId, Source.create("js", (CharSequence) compile(script)));
|
||||
}
|
||||
catch (Exception e) {
|
||||
String errorMsg = StrUtil.format("script loading error for node[{}], error msg:{}", nodeId, e.getMessage());
|
||||
|
@ -99,4 +98,12 @@ public class GraalJavaScriptExecutor extends ScriptExecutor {
|
|||
return ScriptTypeEnum.JS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) throws Exception {
|
||||
String wrapScript = StrUtil.format("function process(){{}} process();", script);
|
||||
Context context = Context.newBuilder().allowAllAccess(true).engine(engine).build();
|
||||
context.parse(Source.create("js", wrapScript));
|
||||
return wrapScript;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,12 +23,7 @@ public class JavaExecutor extends ScriptExecutor {
|
|||
@Override
|
||||
public void load(String nodeId, String script) {
|
||||
try{
|
||||
IScriptEvaluator se = CompilerFactoryFactory.getDefaultCompilerFactory(this.getClass().getClassLoader()).newScriptEvaluator();
|
||||
se.setTargetVersion(8);
|
||||
se.setReturnType(Object.class);
|
||||
se.setParameters(new String[] {"_meta"}, new Class[] {ScriptExecuteWrap.class});
|
||||
se.cook(convertScript(script));
|
||||
compiledScriptMap.put(nodeId, se);
|
||||
compiledScriptMap.put(nodeId, (IScriptEvaluator) compile(script));
|
||||
}catch (Exception e){
|
||||
String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage());
|
||||
throw new ScriptLoadException(errorMsg);
|
||||
|
@ -66,6 +61,16 @@ public class JavaExecutor extends ScriptExecutor {
|
|||
return ScriptTypeEnum.JAVA;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) throws Exception {
|
||||
IScriptEvaluator se = CompilerFactoryFactory.getDefaultCompilerFactory(this.getClass().getClassLoader()).newScriptEvaluator();
|
||||
se.setTargetVersion(8);
|
||||
se.setReturnType(Object.class);
|
||||
se.setParameters(new String[] {"_meta"}, new Class[] {ScriptExecuteWrap.class});
|
||||
se.cook(convertScript(script));
|
||||
return se;
|
||||
}
|
||||
|
||||
private String convertScript(String script){
|
||||
//替换掉public,private,protected等修饰词
|
||||
String script1 = script.replaceAll("public class", "class")
|
||||
|
|
|
@ -13,6 +13,8 @@ import com.yomahub.liteflow.script.exception.ScriptLoadException;
|
|||
import com.yomahub.liteflow.util.CopyOnWriteHashMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -41,8 +43,7 @@ public class QLExpressScriptExecutor extends ScriptExecutor {
|
|||
@Override
|
||||
public void load(String nodeId, String script) {
|
||||
try {
|
||||
InstructionSet instructionSet = expressRunner.getInstructionSetFromLocalCache(script);
|
||||
compiledScriptMap.put(nodeId, instructionSet);
|
||||
compiledScriptMap.put(nodeId, (InstructionSet) compile(script));
|
||||
}
|
||||
catch (Exception e) {
|
||||
String errorMsg = StrUtil.format("script loading error for node[{}],error msg:{}", nodeId, e.getMessage());
|
||||
|
@ -96,4 +97,9 @@ public class QLExpressScriptExecutor extends ScriptExecutor {
|
|||
return ScriptTypeEnum.QLEXPRESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object compile(String script) throws Exception {
|
||||
return expressRunner.getInstructionSetFromLocalCache(script);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import cn.hutool.core.annotation.AnnotationUtil;
|
|||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.proxy.DeclWarpBean;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
|
@ -12,6 +14,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
|||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -23,38 +26,42 @@ import java.util.Map;
|
|||
* @since 2.11.4
|
||||
*/
|
||||
public class DeclBeanDefinition implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
private final LFLog LOG = LFLoggerManager.getLogger(this.getClass());
|
||||
@Override
|
||||
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
|
||||
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) registry;
|
||||
Map<String, BeanDefinition> beanDefinitionHolderMap = (Map<String, BeanDefinition>)ReflectUtil.getFieldValue(defaultListableBeanFactory, "mergedBeanDefinitions");
|
||||
|
||||
beanDefinitionHolderMap.entrySet().stream().filter(entry -> {
|
||||
Class<?> rawClass = entry.getValue().getResolvableType().getRawClass();
|
||||
String[] beanDefinitionNames = defaultListableBeanFactory.getBeanDefinitionNames();
|
||||
|
||||
Arrays.stream(beanDefinitionNames).filter(beanName -> {
|
||||
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
||||
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
||||
if (rawClass == null){
|
||||
return false;
|
||||
}else{
|
||||
return Arrays.stream(rawClass.getMethods()).anyMatch(method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class) != null);
|
||||
}
|
||||
}).forEach(entry -> {
|
||||
Class<?> rawClass = entry.getValue().getResolvableType().getRawClass();
|
||||
}).forEach(beanName -> {
|
||||
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
||||
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
||||
List<DeclWarpBean> declWarpBeanList = DeclComponentParserHolder.loadDeclComponentParser().parseDeclBean(rawClass);
|
||||
|
||||
declWarpBeanList.forEach(declWarpBean -> {
|
||||
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
|
||||
beanDefinition.setBeanClass(DeclWarpBean.class);
|
||||
beanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
|
||||
GenericBeanDefinition newBeanDefinition = new GenericBeanDefinition();
|
||||
newBeanDefinition.setBeanClass(DeclWarpBean.class);
|
||||
newBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
|
||||
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
|
||||
mutablePropertyValues.add("nodeId", declWarpBean.getNodeId());
|
||||
mutablePropertyValues.add("nodeName", declWarpBean.getNodeName());
|
||||
mutablePropertyValues.add("nodeType", declWarpBean.getNodeType());
|
||||
mutablePropertyValues.add("rawClazz", declWarpBean.getRawClazz());
|
||||
mutablePropertyValues.add("methodWrapBeanList", declWarpBean.getMethodWrapBeanList());
|
||||
mutablePropertyValues.add("rawBean", entry.getValue());
|
||||
beanDefinition.setPropertyValues(mutablePropertyValues);
|
||||
mutablePropertyValues.add("rawBean", beanDefinition);
|
||||
newBeanDefinition.setPropertyValues(mutablePropertyValues);
|
||||
defaultListableBeanFactory.setAllowBeanDefinitionOverriding(true);
|
||||
defaultListableBeanFactory.registerBeanDefinition(declWarpBean.getNodeId(), beanDefinition);
|
||||
defaultListableBeanFactory.registerBeanDefinition(declWarpBean.getNodeId(), newBeanDefinition);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -62,4 +69,19 @@ public class DeclBeanDefinition implements BeanDefinitionRegistryPostProcessor {
|
|||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
|
||||
}
|
||||
|
||||
private Class<?> getRawClassFromBeanDefinition(BeanDefinition beanDefinition){
|
||||
try{
|
||||
Method method = ReflectUtil.getMethodByName(DeclBeanDefinition.class, "getResolvableType");
|
||||
if (method != null){
|
||||
Object resolvableType = ReflectUtil.invoke(beanDefinition, method);
|
||||
return ReflectUtil.invoke(resolvableType, "getRawClass");
|
||||
}else{
|
||||
return ReflectUtil.invoke(beanDefinition, "getTargetType");
|
||||
}
|
||||
}catch (Exception e){
|
||||
LOG.error("An error occurred while obtaining the rowClass.",e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@TestPropertySource(value = "classpath:/retry/application.properties")
|
||||
@SpringBootTest(classes = RetryELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.retry.cmp"})
|
||||
public class RetryELDeclMultiSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
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.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
int flagb = 0;
|
||||
int flagc = 0;
|
||||
int flagd = 0;
|
||||
int flagf = 0;
|
||||
int flagi = 0;
|
||||
int flagn = 0;
|
||||
int flagm = 0;
|
||||
|
||||
@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) {
|
||||
flagb ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flagb < 4) throw new RuntimeException();
|
||||
else flagb = 0;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_FOR, nodeId = "c", nodeType = NodeTypeEnum.FOR)
|
||||
public int processC(NodeComponent bindCmp) {
|
||||
flagc ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flagc < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_SWITCH, nodeId = "d", nodeType = NodeTypeEnum.SWITCH)
|
||||
public String processD(NodeComponent bindCmp) {
|
||||
flagd ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flagd < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_IF, nodeId = "f", nodeType = NodeTypeEnum.IF)
|
||||
public boolean processF(NodeComponent bindCmp) {
|
||||
System.out.println("FCmp executed!");
|
||||
flagf ++;
|
||||
if(flagf < 4) throw new RuntimeException();
|
||||
else return true;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_ITERATOR, nodeId = "i", nodeType = NodeTypeEnum.ITERATOR)
|
||||
public Iterator<?> processI(NodeComponent bindCmp) {
|
||||
flagi ++;
|
||||
if(flagi < 4) throw new RuntimeException();
|
||||
else {
|
||||
List<String> list = ListUtil.toList("jack");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "m")
|
||||
public void processM(NodeComponent bindCmp) {
|
||||
flagm ++;
|
||||
System.out.println("MCmp executed!");
|
||||
if(flagm < 4) throw new ELParseException("MCmp error!");
|
||||
else flagm = 0;
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_WHILE, nodeId = "n", nodeType = NodeTypeEnum.WHILE)
|
||||
public boolean processN(NodeComponent bindCmp) {
|
||||
flagn ++;
|
||||
System.out.println("NCmp executed!");
|
||||
if(flagn < 4) throw new RuntimeException();
|
||||
else return flagn == 4 ? true : false;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=retry/flow.el.xml
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
WHEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN( a, b.retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
FOR(c).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
SWITCH(d).TO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
IF(f, a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
WHILE(n).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
ITERATOR(i).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN( a, b ).retry(1);
|
||||
</chain>
|
||||
|
||||
<chain name="chain10">
|
||||
THEN( a, FINALLY(b, a).retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain11">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.ELParseException", "com.yomahub.liteflow.exception.FlowSystemException");
|
||||
</chain>
|
||||
|
||||
<chain name="chain12">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.AndOrConditionException");
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,117 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 javax.annotation.Resource;
|
||||
|
||||
|
||||
@TestPropertySource(value = "classpath:/retry/application.properties")
|
||||
@SpringBootTest(classes = RetryELDeclSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.retry.cmp"})
|
||||
public class RetryELDeclSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
flag ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeForComponent;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp extends NodeForComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp extends NodeSwitchComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
System.out.println("FCmp executed!");
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("i")
|
||||
public class ICmp extends NodeIteratorComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else {
|
||||
List<String> list = ListUtil.toList("jack");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
|
||||
@LiteflowComponent("m")
|
||||
public class MCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("MCmp executed!");
|
||||
if(flag < 4) throw new ELParseException("MCmp error!");
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
@LiteflowComponent("n")
|
||||
public class NCmp extends NodeWhileComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("NCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return flag == 4 ? true : false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=retry/flow.el.xml
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
WHEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN( a, b.retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
FOR(c).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
SWITCH(d).TO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
IF(f, a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
WHILE(n).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
ITERATOR(i).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN( a, b ).retry(1);
|
||||
</chain>
|
||||
|
||||
<chain name="chain10">
|
||||
THEN( a, FINALLY(b, a).retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain11">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.ELParseException", "com.yomahub.liteflow.exception.FlowSystemException");
|
||||
</chain>
|
||||
|
||||
<chain name="chain12">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.AndOrConditionException");
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,116 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class RetryTest extends BaseTest {
|
||||
|
||||
private static FlowExecutor flowExecutor;
|
||||
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
LiteflowConfig config = new LiteflowConfig();
|
||||
config.setRuleSource("retry/flow.el.xml");
|
||||
flowExecutor = FlowExecutorHolder.loadInstance(config);
|
||||
}
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class BCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
flag ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeForComponent;
|
||||
|
||||
public class CCmp extends NodeForComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
public class DCmp extends NodeSwitchComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
public class FCmp extends NodeIfComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
System.out.println("FCmp executed!");
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ICmp extends NodeIteratorComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else {
|
||||
List<String> list = ListUtil.toList("jack");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
|
||||
public class MCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("MCmp executed!");
|
||||
if(flag < 4) throw new ELParseException("MCmp error!");
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
public class NCmp extends NodeWhileComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("NCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return flag == 4 ? true : false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<nodes>
|
||||
<node id="a" class="com.yomahub.liteflow.test.retry.cmp.ACmp"/>
|
||||
<node id="b" class="com.yomahub.liteflow.test.retry.cmp.BCmp"/>
|
||||
<node id="c" class="com.yomahub.liteflow.test.retry.cmp.CCmp"/>
|
||||
<node id="d" class="com.yomahub.liteflow.test.retry.cmp.DCmp"/>
|
||||
<node id="f" class="com.yomahub.liteflow.test.retry.cmp.FCmp"/>
|
||||
<node id="i" class="com.yomahub.liteflow.test.retry.cmp.ICmp"/>
|
||||
<node id="n" class="com.yomahub.liteflow.test.retry.cmp.NCmp"/>
|
||||
<node id="m" class="com.yomahub.liteflow.test.retry.cmp.MCmp"/>
|
||||
</nodes>
|
||||
<chain name="chain1">
|
||||
THEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
WHEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN( a, b.retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
FOR(c).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
SWITCH(d).TO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
IF(f, a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
WHILE(n).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
ITERATOR(i).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN( a, b ).retry(1);
|
||||
</chain>
|
||||
|
||||
<chain name="chain10">
|
||||
THEN( a, FINALLY(b, a).retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain11">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.ELParseException", "com.yomahub.liteflow.exception.FlowSystemException");
|
||||
</chain>
|
||||
|
||||
<chain name="chain12">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.AndOrConditionException");
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,47 @@
|
|||
package com.yomahub.liteflow.test.script.aviator.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.aviator.AviatorScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@SpringBootTest(classes = ValidateAviatorScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateAviatorScriptComponentTest {
|
||||
|
||||
@Test
|
||||
public void testAviatorScriptComponentValidateFunction(){
|
||||
String correctScript = " use java.util.Date;\n" +
|
||||
" use cn.hutool.core.date.DateUtil;\n" +
|
||||
" let d = DateUtil.formatDateTime(new Date());\n" +
|
||||
" println(d);\n" +
|
||||
"\n" +
|
||||
" a = 2;\n" +
|
||||
" b = 3;\n" +
|
||||
"\n" +
|
||||
" setData(defaultContext, \"s1\", a*b);";
|
||||
// 语法错误
|
||||
String wrongScript = " use java.util.Date;\n" +
|
||||
" use cn.hutool.core.date.DateUtil;\n" +
|
||||
" lt d = DateUtil.formatDateTime(new Date());\n" +
|
||||
" println(d);\n" +
|
||||
"\n" +
|
||||
" a = 2;\n" +
|
||||
" b = 3;\n" +
|
||||
"\n" +
|
||||
" setData(defaultContext, \"s1\", a*b);";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.AVIATOR));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.PYTHON));
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.yomahub.liteflow.test.script.graaljs.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.graaljs.GraalJavaScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateGraaljsScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateGraaljsScriptComponentTest {
|
||||
@Test
|
||||
public void testGraaljsScriptComponentValidateFunction(){
|
||||
String correctScript = " var a=3;\n" +
|
||||
" var b=2;\n" +
|
||||
" var c=1;\n" +
|
||||
" var d=5;\n" +
|
||||
"\n" +
|
||||
" function addByArray(values) {\n" +
|
||||
" var sum = 0;\n" +
|
||||
" for (var i = 0; i < values.length; i++) {\n" +
|
||||
" sum += values[i];\n" +
|
||||
" }\n" +
|
||||
" return sum;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var result = addByArray([a,b,c,d]);\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"s1\",parseInt(result));";
|
||||
// 语法错误
|
||||
String wrongScript = " var a=3;\n" +
|
||||
" var b=2;\n" +
|
||||
" var c=1;\n" +
|
||||
" var d=5;\n" +
|
||||
"\n" +
|
||||
" fn addByArray(values) {\n" +
|
||||
" var sum = 0;\n" +
|
||||
" for (var i = 0; i < values.length; i++) {\n" +
|
||||
" sum += values[i];\n" +
|
||||
" }\n" +
|
||||
" return sum;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var result = addByArray([a,b,c,d]);\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"s1\",parseInt(result));";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.JS));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.AVIATOR));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package com.yomahub.liteflow.test.script.groovy.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.groovy.GroovyScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateGroovyScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateGroovyScriptComponentTest {
|
||||
@Test
|
||||
public void testGroovyScriptComponentValidateFunction(){
|
||||
String correctScript = " import cn.hutool.core.collection.ListUtil\n" +
|
||||
" import cn.hutool.core.date.DateUtil\n" +
|
||||
"\n" +
|
||||
" import java.util.function.Consumer\n" +
|
||||
" import java.util.function.Function\n" +
|
||||
" import java.util.stream.Collectors\n" +
|
||||
"\n" +
|
||||
" def date = DateUtil.parse(\"2022-10-17 13:31:43\")\n" +
|
||||
" println(date)\n" +
|
||||
" defaultContext.setData(\"demoDate\", date)\n" +
|
||||
"\n" +
|
||||
" List<String> list = ListUtil.toList(\"a\", \"b\", \"c\")\n" +
|
||||
"\n" +
|
||||
" List<String> resultList = list.stream().map(s -> \"hello,\" + s).collect(Collectors.toList())\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"resultList\", resultList)\n" +
|
||||
"\n" +
|
||||
" class Student {\n" +
|
||||
" int studentID\n" +
|
||||
" String studentName\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" Student student = new Student()\n" +
|
||||
" student.studentID = 100301\n" +
|
||||
" student.studentName = \"张三\"\n" +
|
||||
" defaultContext.setData(\"student\", student)\n" +
|
||||
"\n" +
|
||||
" def a = 3\n" +
|
||||
" def b = 2\n" +
|
||||
" defaultContext.setData(\"s1\", a * b)";
|
||||
// 语法错误
|
||||
String wrongScript = " import cn.hutool.core.collection.ListUtil\n" +
|
||||
" import cn.hutool.core.date.DateUtil\n" +
|
||||
"\n" +
|
||||
" import java.util.function.Consumer\n" +
|
||||
" import java.util.function.Function\n" +
|
||||
" import java.util.stream.Collectors\n" +
|
||||
"\n" +
|
||||
" d date = DateUtil.parse(\"2022-10-17 13:31:43\")\n" +
|
||||
" println(date)\n" +
|
||||
" defaultContext.setData(\"demoDate\", date)\n" +
|
||||
"\n" +
|
||||
" List<String> list = ListUtil.toList(\"a\", \"b\", \"c\")\n" +
|
||||
"\n" +
|
||||
" List<String> resultList = list.stream().map(s -> \"hello,\" + s).collect(Collectors.toList())\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"resultList\", resultList)\n" +
|
||||
"\n" +
|
||||
" class Student {\n" +
|
||||
" int studentID\n" +
|
||||
" String studentName\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" Student student = new Student()\n" +
|
||||
" student.studentID = 100301\n" +
|
||||
" student.studentName = \"张三\"\n" +
|
||||
" defaultContext.setData(\"student\", student)\n" +
|
||||
"\n" +
|
||||
" def a = 3\n" +
|
||||
" def b = 2\n" +
|
||||
" defaultContext.setData(\"s1\", a * b)";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.GROOVY));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.JS));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.yomahub.liteflow.test.script.java.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.java.JavaExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateJavaScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateJavaScriptComponentTest {
|
||||
@Test
|
||||
public void testJavaScriptComponentValidateFunction(){
|
||||
String correctScript = "import com.alibaba.fastjson2.JSON;\n" +
|
||||
" import com.yomahub.liteflow.slot.DefaultContext;\n" +
|
||||
" import com.yomahub.liteflow.spi.holder.ContextAwareHolder;\n" +
|
||||
" import com.yomahub.liteflow.test.script.java.common.cmp.TestDomain;\n" +
|
||||
" import com.yomahub.liteflow.script.body.JaninoCommonScriptBody;\n" +
|
||||
" import com.yomahub.liteflow.script.ScriptExecuteWrap;\n" +
|
||||
"\n" +
|
||||
" public class Demo implements JaninoCommonScriptBody {\n" +
|
||||
" public Void body(ScriptExecuteWrap wrap) {\n" +
|
||||
" int v1 = 2;\n" +
|
||||
" int v2 = 3;\n" +
|
||||
" DefaultContext ctx = (DefaultContext) wrap.getCmp().getFirstContextBean();\n" +
|
||||
" ctx.setData(\"s1\", v1 * v2);\n" +
|
||||
"\n" +
|
||||
" TestDomain domain = (TestDomain) ContextAwareHolder.loadContextAware().getBean(TestDomain.class);\n" +
|
||||
" System.out.println(JSON.toJSONString(domain));\n" +
|
||||
" String str = domain.sayHello(\"jack\");\n" +
|
||||
" ctx.setData(\"hi\", str);\n" +
|
||||
"\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
" }";
|
||||
// 未指定类型名错误
|
||||
String wrongScript = "import com.alibaba.fastjson2.JSON;\n" +
|
||||
" import com.yomahub.liteflow.slot.DefaultContext;\n" +
|
||||
" import com.yomahub.liteflow.spi.holder.ContextAwareHolder;\n" +
|
||||
" import com.yomahub.liteflow.test.script.java.common.cmp.TestDomain;\n" +
|
||||
" import com.yomahub.liteflow.script.body.JaninoCommonScriptBody;\n" +
|
||||
" import com.yomahub.liteflow.script.ScriptExecuteWrap;\n" +
|
||||
"\n" +
|
||||
" public class Demo implements JaninoCommonScriptBody {\n" +
|
||||
" public Void body(ScriptExecuteWrap wrap) {\n" +
|
||||
" v1 = 2;\n" +
|
||||
" int v2 = 3;\n" +
|
||||
" DefaultContext ctx = (DefaultContext) wrap.getCmp().getFirstContextBean();\n" +
|
||||
" ctx.setData(\"s1\", v1 * v2);\n" +
|
||||
"\n" +
|
||||
" TestDomain domain = (TestDomain) ContextAwareHolder.loadContextAware().getBean(TestDomain.class);\n" +
|
||||
" System.out.println(JSON.toJSONString(domain));\n" +
|
||||
" String str = domain.sayHello(\"jack\");\n" +
|
||||
" ctx.setData(\"hi\", str);\n" +
|
||||
"\n" +
|
||||
" return null;\n" +
|
||||
" }\n" +
|
||||
" }";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.JAVA));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.GROOVY));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.yomahub.liteflow.test.script.javascript.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.javascript.JavaScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateJavaScriptScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateJavaScriptScriptComponentTest {
|
||||
@Test
|
||||
public void testJavaScriptScriptComponentValidateFunction(){
|
||||
String correctScript = "var a=3;\n" +
|
||||
" var b=2;\n" +
|
||||
" var c=1;\n" +
|
||||
" var d=5;\n" +
|
||||
"\n" +
|
||||
" function addByArray(values) {\n" +
|
||||
" var sum = 0;\n" +
|
||||
" for (var i = 0; i < values.length; i++) {\n" +
|
||||
" sum += values[i];\n" +
|
||||
" }\n" +
|
||||
" return sum;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var result = addByArray([a,b,c,d]);\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"s1\",parseInt(result));";
|
||||
// 语法错误
|
||||
String wrongScript = "var a=3;\n" +
|
||||
" var b=2;\n" +
|
||||
" var c=1;\n" +
|
||||
" var d=5;\n" +
|
||||
"\n" +
|
||||
" fon addByArray(values) {\n" +
|
||||
" var sum = 0;\n" +
|
||||
" for (var i = 0; i < values.length; i++) {\n" +
|
||||
" sum += values[i];\n" +
|
||||
" }\n" +
|
||||
" return sum;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" var result = addByArray([a,b,c,d]);\n" +
|
||||
"\n" +
|
||||
" defaultContext.setData(\"s1\",parseInt(result));";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.JS));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.JAVA));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.yomahub.liteflow.test.script.lua.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.lua.LuaScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateLuaScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateLuaScriptComponentTest {
|
||||
@Test
|
||||
public void testLuaScriptComponentValidateFunction(){
|
||||
String correctScript = " local a=6\n" +
|
||||
" local b=10\n" +
|
||||
" if(a>5) then\n" +
|
||||
" b=5\n" +
|
||||
" else\n" +
|
||||
" b=2\n" +
|
||||
" end\n" +
|
||||
" defaultContext:setData(\"s1\",a*b)\n" +
|
||||
" defaultContext:setData(\"s2\",_meta:get(\"nodeId\"))";
|
||||
// 语法错误
|
||||
String wrongScript = " local a=6\n" +
|
||||
" local b=10\n" +
|
||||
" if(a>5) tn\n" +
|
||||
" b=5\n" +
|
||||
" else\n" +
|
||||
" b=2\n" +
|
||||
" end\n" +
|
||||
" defaultContext:setData(\"s1\",a*b)\n" +
|
||||
" defaultContext:setData(\"s2\",_meta:get(\"nodeId\"))";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.LUA));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.JS));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.yomahub.liteflow.test.script.multi.language.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.ScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SpringBootTest(classes = ValidateMultiLanguageScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateMultiLanguageScriptComponentTest {
|
||||
@Test
|
||||
public void testMultiLanguageScriptComponentValidateFunction(){
|
||||
String correctGroovyScript = " class Student {\n" +
|
||||
" int studentID;\n" +
|
||||
" String studentName;\n" +
|
||||
"\n" +
|
||||
" public void setStudentID(int id){\n" +
|
||||
" this.studentID = id;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" Student student = new Student()\n" +
|
||||
" student.studentID = 100301\n" +
|
||||
" student.studentName = \"张三\"\n" +
|
||||
" defaultContext.setData(\"student\", student)\n" +
|
||||
"\n" +
|
||||
" def a = 3\n" +
|
||||
" def b = 2\n" +
|
||||
" defaultContext.setData(\"s1\", a * b)";
|
||||
String correctJavascriptScript = " var student = defaultContext.getData(\"student\");\n" +
|
||||
" student.setStudentID(10032);";
|
||||
String correctPythonScript = " a = 3\n" +
|
||||
" s1 = defaultContext.getData(\"s1\")\n" +
|
||||
" defaultContext.setData(\"s1\",s1*a)";
|
||||
// 语法错误 缩进
|
||||
String wrongPythonScript = " a = 3\n" +
|
||||
" s1 = defaultContext.getData(\"s1\")\n" +
|
||||
" defaultContext.setData(\"s1\",s1*a)";
|
||||
// 在加载多脚本时使用默认验证方法会错误
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctGroovyScript));
|
||||
|
||||
// 多语言脚本验证 正确样例
|
||||
Map<ScriptTypeEnum, String> correctData = new HashMap<>();
|
||||
correctData.put(ScriptTypeEnum.GROOVY, correctGroovyScript);
|
||||
correctData.put(ScriptTypeEnum.JS, correctJavascriptScript);
|
||||
correctData.put(ScriptTypeEnum.PYTHON, correctPythonScript);
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctData));
|
||||
|
||||
// 多语言脚本验证 错误样例
|
||||
Map<ScriptTypeEnum, String> wrongData = new HashMap<>();
|
||||
wrongData.put(ScriptTypeEnum.GROOVY, correctGroovyScript);
|
||||
wrongData.put(ScriptTypeEnum.JS, correctJavascriptScript);
|
||||
wrongData.put(ScriptTypeEnum.PYTHON, wrongPythonScript);
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongData));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.yomahub.liteflow.test.script.python.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.python.PythonScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidatePythonScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidatePythonScriptComponentTest {
|
||||
@Test
|
||||
public void testPythonScriptComponentValidateFunction(){
|
||||
String correctScript = " import json\n" +
|
||||
"\n" +
|
||||
" x='{\"name\": \"杰克\", \"age\": 75, \"nationality\": \"China\"}'\n" +
|
||||
" jsonData=json.loads(x)\n" +
|
||||
" name=jsonData['name']\n" +
|
||||
" defaultContext.setData(\"name\", name.decode('utf-8'))\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
" a=6\n" +
|
||||
" b=10\n" +
|
||||
" if a>5:\n" +
|
||||
" b=5\n" +
|
||||
" print '你好'.decode('UTF-8')\n" +
|
||||
" else:\n" +
|
||||
" print 'hi'\n" +
|
||||
" defaultContext.setData(\"s1\",a*b)\n" +
|
||||
" defaultContext.setData(\"td\", td.sayHi(\"jack\"))";
|
||||
// 语法错误 缩进
|
||||
String wrongScript = " import json\n" +
|
||||
"\n" +
|
||||
" x='{\"name\": \"杰克\", \"age\": 75, \"nationality\": \"China\"}'\n" +
|
||||
" jsonData=json.loads(x)\n" +
|
||||
" name=jsonData['name']\n" +
|
||||
" defaultContext.setData(\"name\", name.decode('utf-8'))\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
" a=6\n" +
|
||||
" b=10\n" +
|
||||
" if a>5:\n" +
|
||||
" b=5\n" +
|
||||
" print '你好'.decode('UTF-8')\n" +
|
||||
" else:\n" +
|
||||
" print 'hi'\n" +
|
||||
" defaultContext.setData(\"s1\",a*b)\n" +
|
||||
" defaultContext.setData(\"td\", td.sayHi(\"jack\"))";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.PYTHON));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.LUA));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.yomahub.liteflow.test.script.qlexpress.validate;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.qlexpress.QLExpressScriptExecutor;
|
||||
import com.yomahub.liteflow.script.validator.ScriptValidator;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = ValidateQLExpressScriptComponentTest.class)
|
||||
@EnableAutoConfiguration
|
||||
public class ValidateQLExpressScriptComponentTest {
|
||||
@Test
|
||||
public void testQLExpressScriptComponentValidateFunction(){
|
||||
String correctScript = " count = defaultContext.getData(\"count\");\n" +
|
||||
" if(count > 100){\n" +
|
||||
" return \"a\";\n" +
|
||||
" }else{\n" +
|
||||
" return \"b\";\n" +
|
||||
" }";
|
||||
// 语法错误
|
||||
String wrongScript = " count = defaultContext.getData(\"count\");\n" +
|
||||
" if(count > 100){\n" +
|
||||
" return \"a\";\n" +
|
||||
" }el{\n" +
|
||||
" return \"b\";\n" +
|
||||
" }";
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript));
|
||||
Assertions.assertFalse(ScriptValidator.validate(wrongScript));
|
||||
|
||||
Assertions.assertTrue(ScriptValidator.validate(correctScript, ScriptTypeEnum.QLEXPRESS));
|
||||
Assertions.assertFalse(ScriptValidator.validate(correctScript, ScriptTypeEnum.PYTHON));
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ import com.yomahub.liteflow.test.BaseTest;
|
|||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.noear.snack.ONode;
|
||||
import org.noear.solon.annotation.Import;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.noear.solon.annotation.Import;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
import org.noear.solon.test.annotation.TestPropertySource;
|
||||
|
||||
@ExtendWith(SolonJUnit5Extension.class)
|
||||
@TestPropertySource("classpath:/retry/application.properties")
|
||||
public class RetrySpringbootTest extends BaseTest {
|
||||
|
||||
@Inject
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
flag ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeForComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeForComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("d")
|
||||
public class DCmp extends NodeSwitchComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
System.out.println("FCmp executed!");
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@Component("i")
|
||||
public class ICmp extends NodeIteratorComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else {
|
||||
List<String> list = ListUtil.toList("jack");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("m")
|
||||
public class MCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("MCmp executed!");
|
||||
if(flag < 4) throw new ELParseException("MCmp error!");
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
@Component("n")
|
||||
public class NCmp extends NodeWhileComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("NCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return flag == 4 ? true : false;
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
import org.noear.solon.annotation.Import;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.test.SolonJUnit5Extension;
|
||||
import org.noear.solon.test.annotation.TestPropertySource;
|
||||
|
||||
|
||||
@ExtendWith(SolonJUnit5Extension.class)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=retry/flow.el.xml
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
WHEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN( a, b.retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
FOR(c).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
SWITCH(d).TO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
IF(f, a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
WHILE(n).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
ITERATOR(i).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN( a, b ).retry(1);
|
||||
</chain>
|
||||
|
||||
<chain name="chain10">
|
||||
THEN( a, FINALLY(b, a).retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain11">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.ELParseException", "com.yomahub.liteflow.exception.FlowSystemException");
|
||||
</chain>
|
||||
|
||||
<chain name="chain12">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.AndOrConditionException");
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -17,5 +17,4 @@ public class ACmp extends NodeComponent {
|
|||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,4 +18,9 @@ public class CCmp extends NodeComponent {
|
|||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccess() {
|
||||
System.out.println("hello");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.yomahub.liteflow.test.contextBean;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.contextBean.context.TestContext;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* ContextBean测试
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
@TestPropertySource(value = "classpath:/contextBean/application.properties")
|
||||
@SpringBootTest(classes = ContextBeanSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({ "com.yomahub.liteflow.test.contextBean.cmp" })
|
||||
public class ContextBeanSpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// 最简单的情况
|
||||
@Test
|
||||
public void testContextBean1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", TestContext.class);
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
TestContext context = response.getContextBean("skuContext");
|
||||
Assertions.assertEquals("J001", context.getSkuCode());
|
||||
}
|
||||
}
|
|
@ -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.contextBean.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.test.contextBean.context.TestContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
TestContext context = this.getContextBean("skuContext");
|
||||
context.setSkuCode("J001");
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.contextBean.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.yomahub.liteflow.test.contextBean.context;
|
||||
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
|
||||
@ContextBean("skuContext")
|
||||
public class TestContext {
|
||||
|
||||
private String skuCode;
|
||||
|
||||
private String skuName;
|
||||
|
||||
public TestContext(String skuCode, String skuName) {
|
||||
this.skuCode = skuCode;
|
||||
this.skuName = skuName;
|
||||
}
|
||||
|
||||
public String getSkuCode() {
|
||||
return skuCode;
|
||||
}
|
||||
|
||||
public void setSkuCode(String skuCode) {
|
||||
this.skuCode = skuCode;
|
||||
}
|
||||
|
||||
public String getSkuName() {
|
||||
return skuName;
|
||||
}
|
||||
|
||||
public void setSkuName(String skuName) {
|
||||
this.skuName = skuName;
|
||||
}
|
||||
}
|
|
@ -182,6 +182,16 @@ public class MaxWaitSecondsELSpringbootTest extends BaseTest {
|
|||
assertNotTimeout("chain2");
|
||||
}
|
||||
|
||||
// 测试超时情况下组件还在运行的场景是否会报错
|
||||
@Test
|
||||
public void testChain3() {
|
||||
DefaultContext context = new DefaultContext();
|
||||
context.setData("test", "123");
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg", context);
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals(TimeoutException.class, response.getCause().getClass());
|
||||
}
|
||||
|
||||
private void assertTimeout(String chainId) {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.yomahub.liteflow.test.maxWaitSeconds.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
@LiteflowComponent("e")
|
||||
public class ECmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() throws Exception{
|
||||
DefaultContext context = this.getFirstContextBean();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
String str = context.getData("test");
|
||||
System.out.println(str);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
System.out.println("ECmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
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 javax.annotation.Resource;
|
||||
|
||||
|
||||
@TestPropertySource(value = "classpath:/retry/application.properties")
|
||||
@SpringBootTest(classes = RetrySpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.retry.cmp"})
|
||||
public class RetrySpringbootTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
@LiteflowComponent("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
flag ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeForComponent;
|
||||
|
||||
@LiteflowComponent("c")
|
||||
public class CCmp extends NodeForComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
|
||||
@LiteflowComponent("d")
|
||||
public class DCmp extends NodeSwitchComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIfComponent;
|
||||
|
||||
@LiteflowComponent("f")
|
||||
public class FCmp extends NodeIfComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public boolean processIf() throws Exception {
|
||||
System.out.println("FCmp executed!");
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeIteratorComponent;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@LiteflowComponent("i")
|
||||
public class ICmp extends NodeIteratorComponent {
|
||||
int flag = 0;
|
||||
@Override
|
||||
public Iterator<?> processIterator() throws Exception {
|
||||
flag ++;
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else {
|
||||
List<String> list = ListUtil.toList("jack");
|
||||
return list.iterator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.exception.ELParseException;
|
||||
|
||||
@LiteflowComponent("m")
|
||||
public class MCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("MCmp executed!");
|
||||
if(flag < 4) throw new ELParseException("MCmp error!");
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeWhileComponent;
|
||||
|
||||
@LiteflowComponent("n")
|
||||
public class NCmp extends NodeWhileComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public boolean processWhile() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("NCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return flag == 4 ? true : false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=contextBean/flow.xml
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE flow PUBLIC "liteflow" "liteflow.dtd">
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN(a,b);
|
||||
</chain>
|
||||
</flow>
|
|
@ -107,4 +107,8 @@
|
|||
<!-- 不超时 -->
|
||||
testChain.maxWaitSeconds(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN(a, b, e).maxWaitSeconds(8);
|
||||
</chain>
|
||||
</flow>
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=retry/flow.el.xml
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
WHEN( a, b ).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain3">
|
||||
THEN( a, b.retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain4">
|
||||
FOR(c).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain5">
|
||||
SWITCH(d).TO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain6">
|
||||
IF(f, a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain7">
|
||||
WHILE(n).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain8">
|
||||
ITERATOR(i).DO(a).retry(3);
|
||||
</chain>
|
||||
|
||||
<chain name="chain9">
|
||||
THEN( a, b ).retry(1);
|
||||
</chain>
|
||||
|
||||
<chain name="chain10">
|
||||
THEN( a, FINALLY(b, a).retry(3) );
|
||||
</chain>
|
||||
|
||||
<chain name="chain11">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.ELParseException", "com.yomahub.liteflow.exception.FlowSystemException");
|
||||
</chain>
|
||||
|
||||
<chain name="chain12">
|
||||
THEN( a, m ).retry(3, "com.yomahub.liteflow.exception.AndOrConditionException");
|
||||
</chain>
|
||||
</flow>
|
|
@ -0,0 +1,114 @@
|
|||
package com.yomahub.liteflow.test.retry;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration("classpath:/retry/application.xml")
|
||||
public class RetrySpringTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
// THEN测试
|
||||
@Test
|
||||
public void testThen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b==>a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHEN测试
|
||||
@Test
|
||||
public void testWhen() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// node测试
|
||||
@Test
|
||||
public void testNode() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain3", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// FOR测试
|
||||
@Test
|
||||
public void testFor() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain4", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("c==>c==>c==>c==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// SWITCH测试
|
||||
@Test
|
||||
public void testSwitch() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain5", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("d==>d==>d==>d==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// IF测试
|
||||
@Test
|
||||
public void testIf() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("f==>f==>f==>f==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// WHILE测试
|
||||
@Test
|
||||
public void testWhile() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("n==>n==>n==>n==>a==>n", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// ITERATOR测试
|
||||
@Test
|
||||
public void testIterator() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain8", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
Assertions.assertEquals("i==>i==>i==>i==>a", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 重试失败提示信息测试
|
||||
@Test
|
||||
public void testRetryFail() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain9", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b==>a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// FINALLY测试
|
||||
@Test
|
||||
public void testFinally() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain10", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
Assertions.assertEquals("a==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
// 指定异常重试测试1
|
||||
@Test
|
||||
public void testException1() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain11", "arg");
|
||||
Assertions.assertTrue(response.isSuccess());
|
||||
}
|
||||
|
||||
// 指定异常重试测试2
|
||||
@Test
|
||||
public void testException2() throws Exception {
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain12", "arg");
|
||||
Assertions.assertFalse(response.isSuccess());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp extends NodeComponent {
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp extends NodeComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
flag ++;
|
||||
System.out.println("BCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else flag = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeForComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeForComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public int processFor() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("CCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.yomahub.liteflow.test.retry.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeSwitchComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("d")
|
||||
public class DCmp extends NodeSwitchComponent {
|
||||
int flag = 0;
|
||||
|
||||
@Override
|
||||
public String processSwitch() throws Exception {
|
||||
flag ++;
|
||||
System.out.println("DCmp executed!");
|
||||
if(flag < 4) throw new RuntimeException();
|
||||
else return "a";
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue