Merge branch 'dev'
This commit is contained in:
commit
26c24692cf
|
@ -11,7 +11,7 @@ LiteFlow是一个轻量且强大的国产规则引擎框架,可用于复杂的
|
|||
|
||||
LiteFlow于2020年正式开源,2021年获得开源中国年度最受欢迎开源软件殊荣。于2022年获得Gitee最有价值开源项目(GVP)荣誉。是一个正处在高速发展中的开源项目。
|
||||
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个1800多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
LiteFlow是一个由社区驱动的项目,我们非常重视社区建设,拥有一个2500多人的使用者社区,在使用中碰到任何问题或者建议都可以在社区中反应。
|
||||
|
||||
你在官网中可以找到加入社区的方式!
|
||||
|
||||
|
@ -52,7 +52,7 @@ LiteFlow利用规则表达式为驱动引擎,去驱动你定义的组件。你
|
|||
|
||||
LiteFlow拥有极其详细易懂的文档体系,能帮助你解决在使用框架的时候95%以上的问题。
|
||||
|
||||
目前为止,LiteFlow拥有800多个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
|
||||
目前为止,LiteFlow拥有900多个测试用例,并且不断在增加中。完备的文档+覆盖全面的测试用例保障了LiteFlow框架的稳定性!
|
||||
|
||||
LiteFlow期待你的了解!
|
||||
|
||||
|
|
|
@ -50,5 +50,9 @@
|
|||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.yomahub.liteflow.enums.NodeTypeEnum;
|
|||
import com.yomahub.liteflow.exception.NodeBuildException;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.monitor.MonitorFile;
|
||||
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -134,6 +135,10 @@ public class LiteFlowNodeBuilder {
|
|||
List<String> scriptList = PathContentParserHolder.loadContextAware().parseContent(ListUtil.toList(filePath));
|
||||
String script = CollUtil.getFirst(scriptList);
|
||||
setScript(script);
|
||||
|
||||
// 添加脚本文件监听
|
||||
List<String> fileAbsolutePath = PathContentParserHolder.loadContextAware().getFileAbsolutePath(ListUtil.toList(filePath));
|
||||
MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath);
|
||||
} catch (Exception e) {
|
||||
String errMsg = StrUtil.format("An exception occurred while building the node[{}],{}", this.node.getId(), e.getMessage());
|
||||
throw new NodeBuildException(errMsg);
|
||||
|
@ -141,12 +146,17 @@ public class LiteFlowNodeBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public LiteFlowNodeBuilder setLanguage(String language) {
|
||||
this.node.setLanguage(language);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build() {
|
||||
checkBuild();
|
||||
try {
|
||||
// 用于处理脚本 node
|
||||
if (this.node.getType().isScript()){
|
||||
FlowBus.addScriptNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getScript());
|
||||
FlowBus.addScriptNode(this.node.getId(), this.node.getName(), this.node.getType(), this.node.getScript(), this.node.getLanguage());
|
||||
}
|
||||
// 用于处理普通 node
|
||||
else{
|
||||
|
|
|
@ -59,6 +59,12 @@ public class LiteFlowChainELBuilder {
|
|||
EXPRESS_RUNNER.addFunction(ChainConstant.PRE, new PreOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FINALLY, new FinallyOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.IF, new IfOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.CATCH, new CatchOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELSE, Object.class, new ElseOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ELIF, Object.class, new ElifOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.TO, Object.class, new ToOperator());
|
||||
|
@ -69,11 +75,6 @@ public class LiteFlowChainELBuilder {
|
|||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.ID, Object.class, new IdOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.IGNORE_ERROR, Object.class, new IgnoreErrorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.THREAD_POOL, Object.class, new ThreadPoolOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE.toUpperCase(), new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.NODE, new NodeOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.FOR, new ForOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.WHILE, new WhileOperator());
|
||||
EXPRESS_RUNNER.addFunction(ChainConstant.ITERATOR, new IteratorOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DO, Object.class, new DoOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.BREAK, Object.class, new BreakOperator());
|
||||
EXPRESS_RUNNER.addFunctionAndClassMethod(ChainConstant.DATA, Object.class, new DataOperator());
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
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.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.CatchCondition;
|
||||
|
||||
/**
|
||||
* EL规则中的CATCH的操作符
|
||||
* 用法:CATCH...DO...
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class CatchOperator extends BaseOperator<CatchCondition> {
|
||||
@Override
|
||||
public CatchCondition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEq(objects, 1);
|
||||
|
||||
Executable catchItem = OperatorHelper.convert(objects[0], Executable.class);
|
||||
|
||||
CatchCondition catchCondition = new CatchCondition();
|
||||
catchCondition.setCatchItem(catchItem);
|
||||
|
||||
return catchCondition;
|
||||
}
|
||||
}
|
|
@ -1,33 +1,46 @@
|
|||
package com.yomahub.liteflow.builder.el.operator;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.ql.util.express.exception.QLException;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.BaseOperator;
|
||||
import com.yomahub.liteflow.builder.el.operator.base.OperatorHelper;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.condition.CatchCondition;
|
||||
import com.yomahub.liteflow.flow.element.condition.Condition;
|
||||
import com.yomahub.liteflow.flow.element.condition.LoopCondition;
|
||||
|
||||
/**
|
||||
* EL规则中的DO的操作符
|
||||
* 有两种用法
|
||||
* 有三种用法
|
||||
* FOR...DO...BREAK
|
||||
* WHILE...DO...BREAK
|
||||
* CATCH...DO
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.9.0
|
||||
*/
|
||||
public class DoOperator extends BaseOperator<LoopCondition> {
|
||||
public class DoOperator extends BaseOperator<Condition> {
|
||||
@Override
|
||||
public LoopCondition build(Object[] objects) throws Exception {
|
||||
public Condition build(Object[] objects) throws Exception {
|
||||
OperatorHelper.checkObjectSizeEqTwo(objects);
|
||||
|
||||
//DO关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断是不是这两种类型的超类LoopCondition
|
||||
String errorMsg = "The caller must be ForCondition or WhileCondition item";
|
||||
LoopCondition condition = OperatorHelper.convert(objects[0], LoopCondition.class, errorMsg);
|
||||
|
||||
//获得需要执行的可执行表达式
|
||||
Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
|
||||
condition.setExecutableList(ListUtil.toList(doExecutableItem));
|
||||
|
||||
return condition;
|
||||
if (objects[0] instanceof CatchCondition){
|
||||
String errorMsg = "The caller must be CatchCondition item";
|
||||
CatchCondition condition = OperatorHelper.convert(objects[0], CatchCondition.class, errorMsg);
|
||||
//获得需要执行的可执行表达式
|
||||
Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
|
||||
condition.setDoItem(doExecutableItem);
|
||||
return condition;
|
||||
}else if(objects[0] instanceof LoopCondition){
|
||||
String errorMsg = "The caller must be LoopCondition item";
|
||||
//DO关键字有可能用在FOR后面,也有可能用于WHILE后面,所以这里要进行判断是不是这两种类型的超类LoopCondition
|
||||
LoopCondition condition = OperatorHelper.convert(objects[0], LoopCondition.class, errorMsg);
|
||||
//获得需要执行的可执行表达式
|
||||
Executable doExecutableItem = OperatorHelper.convert(objects[1], Executable.class);
|
||||
condition.setDoExecutor(doExecutableItem);
|
||||
return condition;
|
||||
}else{
|
||||
String errorMsg = "The caller must be LoopCondition or CatchCondition item";
|
||||
throw new QLException(errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class ElifOperator extends BaseOperator<IfCondition> {
|
|||
|
||||
//构建一个内部的IfCondition
|
||||
IfCondition ifConditionItem = new IfCondition();
|
||||
ifConditionItem.setExecutableList(ListUtil.toList(ifNode));
|
||||
ifConditionItem.setIfNode(ifNode);
|
||||
ifConditionItem.setTrueCaseExecutableItem(trueCaseExecutableItem);
|
||||
|
||||
//因为可能会有多个ELIF,所以每一次拿到的caller总是最开始大的if,需要遍历到没有falseCaseExecutable的地方。
|
||||
|
|
|
@ -37,7 +37,7 @@ public class IfOperator extends BaseOperator<IfCondition> {
|
|||
}
|
||||
|
||||
IfCondition ifCondition = new IfCondition();
|
||||
ifCondition.setExecutableList(ListUtil.toList(ifNode));
|
||||
ifCondition.setIfNode(ifNode);
|
||||
ifCondition.setTrueCaseExecutableItem(trueCaseExecutableItem);
|
||||
ifCondition.setFalseCaseExecutableItem(falseCaseExecutableItem);
|
||||
return ifCondition;
|
||||
|
|
|
@ -35,6 +35,11 @@ public class NodePropBean {
|
|||
*/
|
||||
String file;
|
||||
|
||||
/**
|
||||
* 脚本语言
|
||||
*/
|
||||
String language;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
@ -88,4 +93,13 @@ public class NodePropBean {
|
|||
this.file = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public NodePropBean setLanguage(String language) {
|
||||
this.language = language;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ public interface ChainConstant {
|
|||
|
||||
String NAME = "name";
|
||||
|
||||
String LANGUAGE = "language";
|
||||
|
||||
String VALUE = "value";
|
||||
|
||||
String ANY = "any";
|
||||
|
@ -70,4 +72,6 @@ public interface ChainConstant {
|
|||
String CURR_CHAIN_ID = "currChainId";
|
||||
|
||||
String DEFAULT = "DEFAULT";
|
||||
|
||||
String CATCH = "CATCH";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.yomahub.liteflow.context;
|
||||
|
||||
import com.yomahub.liteflow.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @description 用于标注上下文bean的别名,以便在脚本或者组件中通过别名来获取上下文对象
|
||||
* @since 2.9.7
|
||||
* @author Tingliang Wang
|
||||
* @createTime 2023/2/6 15:06
|
||||
* @update: [序号][日期YYYY-MM-DD] [更改人姓名][变更描述]
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface ContextBean {
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
|
||||
@AliasFor("value")
|
||||
String name() default "";
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ import com.yomahub.liteflow.flow.LiteflowResponse;
|
|||
import com.yomahub.liteflow.flow.element.Chain;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import com.yomahub.liteflow.flow.id.IdGeneratorHolder;
|
||||
import com.yomahub.liteflow.monitor.MonitorFile;
|
||||
import com.yomahub.liteflow.parser.base.FlowParser;
|
||||
import com.yomahub.liteflow.parser.factory.FlowParserProvider;
|
||||
import com.yomahub.liteflow.parser.spi.ParserClassNameSpi;
|
||||
|
@ -27,6 +28,7 @@ import com.yomahub.liteflow.slot.DataBus;
|
|||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
import com.yomahub.liteflow.spi.holder.ContextCmpInitHolder;
|
||||
import com.yomahub.liteflow.spi.holder.PathContentParserHolder;
|
||||
import com.yomahub.liteflow.thread.ExecutorHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -89,11 +91,11 @@ public class FlowExecutor {
|
|||
//所有的Parser的SPI实现都是以custom形式放入的,且只支持xml形式
|
||||
ServiceLoader<ParserClassNameSpi> loader = ServiceLoader.load(ParserClassNameSpi.class);
|
||||
Iterator<ParserClassNameSpi> it = loader.iterator();
|
||||
if (it.hasNext()){
|
||||
if (it.hasNext()) {
|
||||
ParserClassNameSpi parserClassNameSpi = it.next();
|
||||
ruleSource = "el_xml:" + parserClassNameSpi.getSpiClassName();
|
||||
liteflowConfig.setRuleSource(ruleSource);
|
||||
}else{
|
||||
} else {
|
||||
//ruleSource为空,而且没有spi形式的扩展,那么说明真的没有ruleSource
|
||||
//这种情况有可能是基于代码动态构建的
|
||||
return;
|
||||
|
@ -124,6 +126,7 @@ public class FlowExecutor {
|
|||
|
||||
//支持多类型的配置文件,分别解析
|
||||
if (BooleanUtil.isTrue(liteflowConfig.isSupportMultipleType())) {
|
||||
// 解析文件
|
||||
parser.parseMain(ListUtil.toList(path));
|
||||
}
|
||||
} catch (CyclicDependencyException e) {
|
||||
|
@ -148,6 +151,7 @@ public class FlowExecutor {
|
|||
//进行多个配置文件的一起解析
|
||||
try {
|
||||
if (parser != null) {
|
||||
// 解析文件
|
||||
parser.parseMain(rulePathList);
|
||||
} else {
|
||||
throw new ConfigErrorException("parse error, please check liteflow config property");
|
||||
|
@ -167,30 +171,44 @@ public class FlowExecutor {
|
|||
}
|
||||
|
||||
//如果是ruleSource方式的,最后判断下有没有解析出来,如果没有解析出来则报错
|
||||
if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData()) && MapUtil.isEmpty(liteflowConfig.getRuleSourceExtDataMap())){
|
||||
if (FlowBus.getChainMap().isEmpty()){
|
||||
if (StrUtil.isBlank(liteflowConfig.getRuleSourceExtData()) && MapUtil.isEmpty(liteflowConfig.getRuleSourceExtDataMap())) {
|
||||
if (FlowBus.getChainMap().isEmpty()) {
|
||||
String errMsg = StrUtil.format("no valid rule config found in rule path [{}]", liteflowConfig.getRuleSource());
|
||||
throw new ConfigErrorException(errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
//执行钩子
|
||||
if(hook){
|
||||
if (hook) {
|
||||
FlowInitHook.executeHook();
|
||||
}
|
||||
|
||||
// 文件监听
|
||||
if (liteflowConfig.getEnableMonitorFile()) {
|
||||
try{
|
||||
addMonitorFilePaths(rulePathList);
|
||||
MonitorFile.getInstance().create();
|
||||
}catch (Exception e){
|
||||
String errMsg = StrUtil.format("file monitor init error for path:{}", rulePathList);
|
||||
throw new MonitorFileInitErrorException(errMsg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//此方法就是从原有的配置源主动拉取新的进行刷新
|
||||
//和FlowBus.refreshFlowMetaData的区别就是一个为主动拉取,一个为被动监听到新的内容进行刷新
|
||||
public void reloadRule() {
|
||||
long start = System.currentTimeMillis();
|
||||
init(false);
|
||||
LOG.info("reload rules takes {}ms", System.currentTimeMillis() - start);
|
||||
}
|
||||
|
||||
//隐式流程的调用方法
|
||||
@Deprecated
|
||||
public void invoke(String chainId, Object param, Integer slotIndex) throws Exception {
|
||||
LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_SYNC);
|
||||
if (!response.isSuccess()){
|
||||
if (!response.isSuccess()) {
|
||||
throw response.getCause();
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +216,7 @@ public class FlowExecutor {
|
|||
@Deprecated
|
||||
public void invokeInAsync(String chainId, Object param, Integer slotIndex) throws Exception {
|
||||
LiteflowResponse response = this.invoke2Resp(chainId, param, slotIndex, InnerChainTypeEnum.IN_ASYNC);
|
||||
if (!response.isSuccess()){
|
||||
if (!response.isSuccess()) {
|
||||
throw response.getCause();
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +258,7 @@ public class FlowExecutor {
|
|||
//调用一个流程并返回Future<LiteflowResponse>,允许多上下文的传入
|
||||
public Future<LiteflowResponse> execute2Future(String chainId, Object param, Class<?>... contextBeanClazzArray) {
|
||||
return ExecutorHelper.loadInstance().buildMainExecutor(liteflowConfig.getMainExecutorClass()).submit(()
|
||||
-> FlowExecutorHolder.loadInstance().execute2Resp(chainId, param, contextBeanClazzArray,null));
|
||||
-> FlowExecutorHolder.loadInstance().execute2Resp(chainId, param, contextBeanClazzArray, null));
|
||||
}
|
||||
|
||||
|
||||
|
@ -251,11 +269,11 @@ public class FlowExecutor {
|
|||
|
||||
//调用一个流程,返回默认的上下文,适用于简单的调用
|
||||
@Deprecated
|
||||
public DefaultContext execute(String chainId, Object param) throws Exception{
|
||||
public DefaultContext execute(String chainId, Object param) throws Exception {
|
||||
LiteflowResponse response = this.execute2Resp(chainId, param, DefaultContext.class);
|
||||
if (!response.isSuccess()){
|
||||
if (!response.isSuccess()) {
|
||||
throw response.getCause();
|
||||
}else{
|
||||
} else {
|
||||
return response.getFirstContextBean();
|
||||
}
|
||||
}
|
||||
|
@ -269,8 +287,8 @@ public class FlowExecutor {
|
|||
}
|
||||
|
||||
private LiteflowResponse invoke2Resp(String chainId,
|
||||
Object param,
|
||||
Integer slotIndex, InnerChainTypeEnum innerChainType) {
|
||||
Object param,
|
||||
Integer slotIndex, InnerChainTypeEnum innerChainType) {
|
||||
Slot slot = doExecute(chainId, param, null, null, slotIndex, innerChainType);
|
||||
return LiteflowResponse.newInnerResponse(chainId, slot);
|
||||
}
|
||||
|
@ -288,9 +306,9 @@ public class FlowExecutor {
|
|||
//如果不是隐式流程,那么需要分配Slot
|
||||
if (innerChainType.equals(InnerChainTypeEnum.NONE) && ObjectUtil.isNull(slotIndex)) {
|
||||
//这里可以根据class分配,也可以根据bean去分配
|
||||
if (ArrayUtil.isNotEmpty(contextBeanClazzArray)){
|
||||
if (ArrayUtil.isNotEmpty(contextBeanClazzArray)) {
|
||||
slotIndex = DataBus.offerSlotByClass(ListUtil.toList(contextBeanClazzArray));
|
||||
}else{
|
||||
} else {
|
||||
slotIndex = DataBus.offerSlotByBean(ListUtil.toList(contextBeanArray));
|
||||
}
|
||||
if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
|
||||
|
@ -311,7 +329,7 @@ public class FlowExecutor {
|
|||
//如果是隐式流程,事先把subException给置空,然后把隐式流程的chainId放入slot元数据中
|
||||
//我知道这在多线程调用隐式流程中会有问题。但是考虑到这种场景的不会多,也有其他的转换方式。
|
||||
//所以暂且这么做,以后再优化
|
||||
if (!innerChainType.equals(InnerChainTypeEnum.NONE)){
|
||||
if (!innerChainType.equals(InnerChainTypeEnum.NONE)) {
|
||||
slot.removeSubException(chainId);
|
||||
slot.addSubChain(chainId);
|
||||
}
|
||||
|
@ -326,9 +344,9 @@ public class FlowExecutor {
|
|||
if (ObjectUtil.isNotNull(param)) {
|
||||
if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
|
||||
slot.setRequestData(param);
|
||||
} else if(innerChainType.equals(InnerChainTypeEnum.IN_SYNC)){
|
||||
} else if (innerChainType.equals(InnerChainTypeEnum.IN_SYNC)) {
|
||||
slot.setChainReqData(chainId, param);
|
||||
} else if(innerChainType.equals(InnerChainTypeEnum.IN_ASYNC)){
|
||||
} else if (innerChainType.equals(InnerChainTypeEnum.IN_ASYNC)) {
|
||||
slot.setChainReqData2Queue(chainId, param);
|
||||
}
|
||||
}
|
||||
|
@ -351,15 +369,15 @@ public class FlowExecutor {
|
|||
} catch (Exception e) {
|
||||
if (ObjectUtil.isNotNull(chain)) {
|
||||
String errMsg = StrUtil.format("[{}]:chain[{}] execute error on slot[{}]", slot.getRequestId(), chain.getChainName(), slotIndex);
|
||||
if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){
|
||||
if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
|
||||
LOG.error(errMsg, e);
|
||||
}else{
|
||||
} else {
|
||||
LOG.error(errMsg);
|
||||
}
|
||||
}else{
|
||||
if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())){
|
||||
} else {
|
||||
if (BooleanUtil.isTrue(liteflowConfig.getPrintExecutionLog())) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}else{
|
||||
} else {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -368,7 +386,7 @@ public class FlowExecutor {
|
|||
//如果是隐式流程,则需要设置到隐式流程的exception属性里
|
||||
if (innerChainType.equals(InnerChainTypeEnum.NONE)) {
|
||||
slot.setException(e);
|
||||
}else{
|
||||
} else {
|
||||
slot.setSubException(chainId, e);
|
||||
}
|
||||
} finally {
|
||||
|
@ -389,4 +407,15 @@ public class FlowExecutor {
|
|||
//把liteFlowConfig设到LiteFlowGetter中去
|
||||
LiteflowConfigGetter.setLiteflowConfig(liteflowConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加监听文件路径
|
||||
*
|
||||
* @param pathList 文件路径
|
||||
*/
|
||||
private void addMonitorFilePaths(List<String> pathList) throws Exception {
|
||||
// 添加规则文件监听
|
||||
List<String> fileAbsolutePath = PathContentParserHolder.loadContextAware().getFileAbsolutePath(pathList);
|
||||
MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath);
|
||||
}
|
||||
}
|
|
@ -19,11 +19,11 @@ public class ScriptBreakComponent extends NodeBreakComponent implements ScriptCo
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
public void loadScript(String script, String language) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ public class ScriptCommonComponent extends NodeComponent implements ScriptCompon
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
public void loadScript(String script, String language) {
|
||||
log.info("load script for component[{}]", getDisplayName());
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,5 +28,5 @@ public interface ScriptComponent {
|
|||
* 加载脚本
|
||||
* @param script
|
||||
*/
|
||||
void loadScript(String script);
|
||||
void loadScript(String script, String language);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ public class ScriptForComponent extends NodeForComponent implements ScriptCompon
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
return (int) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
return (int) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
public void loadScript(String script, String language) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ public class ScriptIfComponent extends NodeIfComponent implements ScriptComponen
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
return (boolean)ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
return (boolean)ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
public void loadScript(String script, String language) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ public class ScriptSwitchComponent extends NodeSwitchComponent implements Script
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
return (String)ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
return (String)ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
public void loadScript(String script, String language) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ public class ScriptWhileComponent extends NodeWhileComponent implements ScriptCo
|
|||
wrap.setSlotIndex(this.getSlotIndex());
|
||||
wrap.setTag(this.getTag());
|
||||
wrap.setCmpData(this.getCmpData(Map.class));
|
||||
return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor().execute(wrap);
|
||||
return (boolean) ScriptExecutorFactory.loadInstance().getScriptExecutor(this.getRefNode().getLanguage()).execute(wrap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadScript(String script) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor().load(getNodeId(), script);
|
||||
public void loadScript(String script, String language) {
|
||||
ScriptExecutorFactory.loadInstance().getScriptExecutor(language).load(getNodeId(), script);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ public enum ConditionTypeEnum {
|
|||
|
||||
TYPE_WHILE("while", "while"),
|
||||
|
||||
TYPE_ITERATOR("iterator", "iterator")
|
||||
TYPE_ITERATOR("iterator", "iterator"),
|
||||
|
||||
TYPE_CATCH("catch", "catch")
|
||||
;
|
||||
private String type;
|
||||
private String name;
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package com.yomahub.liteflow.enums;
|
||||
|
||||
public enum ScriptTypeEnum {
|
||||
|
||||
GROOVY("groovy", "groovy"),
|
||||
QLEXPRESS("qlexpress", "qlexpress"),
|
||||
JS("javascript", "js"),
|
||||
PYTHON("python", "python"),
|
||||
LUA("luaj", "lua")
|
||||
;
|
||||
private String engineName;
|
||||
|
||||
private String displayName;
|
||||
|
||||
ScriptTypeEnum(String engineName, String displayName) {
|
||||
this.engineName = engineName;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getEngineName() {
|
||||
return engineName;
|
||||
}
|
||||
|
||||
public void setEngineName(String engineName) {
|
||||
this.engineName = engineName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public static ScriptTypeEnum getEnumByDisplayName(String displayName) {
|
||||
for (ScriptTypeEnum e : ScriptTypeEnum.values()) {
|
||||
if (e.getDisplayName().equals(displayName)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 类型错误异常
|
||||
* @author Yun
|
||||
*/
|
||||
public class CatchErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 异常信息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public CatchErrorException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* 文件监听异常
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class MonitorFileInitErrorException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 异常信息 */
|
||||
private String message;
|
||||
|
||||
public MonitorFileInitErrorException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
|
@ -106,7 +106,7 @@ public class FlowBus {
|
|||
* @param cmpClazz 节点组件类
|
||||
*/
|
||||
public static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz) {
|
||||
addNode(nodeId, name, type, cmpClazz, null);
|
||||
addNode(nodeId, name, type, cmpClazz, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +124,7 @@ public class FlowBus {
|
|||
} catch (Exception e) {
|
||||
throw new ComponentCannotRegisterException(e.getMessage());
|
||||
}
|
||||
addNode(nodeId, name, nodeType, cmpClazz, null);
|
||||
addNode(nodeId, name, nodeType, cmpClazz, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,11 +135,11 @@ public class FlowBus {
|
|||
* @param nodeType 节点类型
|
||||
* @param script 脚本
|
||||
*/
|
||||
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script) {
|
||||
addNode(nodeId, name, nodeType, ScriptComponent.ScriptComponentClassMap.get(nodeType), script);
|
||||
public static void addScriptNode(String nodeId, String name, NodeTypeEnum nodeType, String script, String language) {
|
||||
addNode(nodeId, name, nodeType, ScriptComponent.ScriptComponentClassMap.get(nodeType), script, language);
|
||||
}
|
||||
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
|
||||
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script, String language) {
|
||||
try {
|
||||
//判断此类是否是声明式的组件,如果是声明式的组件,就用动态代理生成实例
|
||||
//如果不是声明式的,就用传统的方式进行判断
|
||||
|
@ -193,7 +193,8 @@ public class FlowBus {
|
|||
if (type.isScript()) {
|
||||
if (StrUtil.isNotBlank(script)) {
|
||||
node.setScript(script);
|
||||
((ScriptComponent) cmpInstance).loadScript(script);
|
||||
node.setLanguage(language);
|
||||
((ScriptComponent) cmpInstance).loadScript(script, language);
|
||||
} else {
|
||||
String errorMsg = StrUtil.format("script for node[{}] is empty", nodeId);
|
||||
throw new ScriptLoadException(errorMsg);
|
||||
|
@ -244,10 +245,7 @@ public class FlowBus {
|
|||
public static void cleanScriptCache() {
|
||||
//如果引入了脚本组件SPI,则还需要清理脚本的缓存
|
||||
try {
|
||||
ScriptExecutor scriptExecutor = ScriptExecutorFactory.loadInstance().getScriptExecutor();
|
||||
if (ObjectUtil.isNotNull(scriptExecutor)) {
|
||||
scriptExecutor.cleanCache();
|
||||
}
|
||||
ScriptExecutorFactory.loadInstance().cleanScriptCache();
|
||||
} catch (ScriptSpiException ignored) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@ import java.util.Queue;
|
|||
* 执行结果封装类
|
||||
* @author zend.wang
|
||||
*/
|
||||
public class LiteflowResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2792556188993845048L;
|
||||
public class LiteflowResponse{
|
||||
|
||||
private boolean success;
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ public class Node implements Executable,Cloneable{
|
|||
|
||||
private String script;
|
||||
|
||||
private String language;
|
||||
|
||||
private NodeComponent instance;
|
||||
|
||||
private String tag;
|
||||
|
@ -255,4 +257,12 @@ public class Node implements Executable,Cloneable{
|
|||
public void removeCurrLoopObject(){
|
||||
this.currLoopObject.remove();
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.exception.CatchErrorException;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
/**
|
||||
* Catch Condition
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class CatchCondition extends Condition{
|
||||
|
||||
@Override
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
try{
|
||||
Executable catchExecutable = this.getCatchItem();
|
||||
if (ObjectUtil.isNull(catchExecutable)){
|
||||
String errorInfo = StrUtil.format("[{}]:no catch item find", slot.getRequestId());
|
||||
throw new CatchErrorException(errorInfo);
|
||||
}
|
||||
catchExecutable.setCurrChainId(this.getCurrChainId());
|
||||
catchExecutable.execute(slotIndex);
|
||||
}catch (Exception e){
|
||||
Executable doExecutable = this.getDoItem();
|
||||
if (ObjectUtil.isNotNull(doExecutable)){
|
||||
doExecutable.setCurrChainId(this.getCurrChainId());
|
||||
doExecutable.execute(slotIndex);
|
||||
}
|
||||
//catch之后需要把exception给清除掉
|
||||
//正如同java的catch一样,异常自己处理了,属于正常流程了,整个流程状态应该是成功的
|
||||
DataBus.getSlot(slotIndex).removeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionTypeEnum getConditionType() {
|
||||
return ConditionTypeEnum.TYPE_CATCH;
|
||||
}
|
||||
|
||||
public Executable getCatchItem(){
|
||||
return this.getExecutableOne(ConditionKey.CATCH_KEY);
|
||||
}
|
||||
|
||||
public void setCatchItem(Executable executable){
|
||||
this.addExecutable(ConditionKey.CATCH_KEY, executable);
|
||||
}
|
||||
|
||||
public Executable getDoItem(){
|
||||
return this.getExecutableOne(ConditionKey.DO_KEY);
|
||||
}
|
||||
|
||||
public void setDoItem(Executable executable){
|
||||
this.addExecutable(ConditionKey.DO_KEY, executable);
|
||||
}
|
||||
}
|
|
@ -7,12 +7,20 @@
|
|||
*/
|
||||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.enums.ExecuteTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ChainEndException;
|
||||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Condition的抽象类
|
||||
|
@ -25,8 +33,7 @@ public abstract class Condition implements Executable{
|
|||
/**
|
||||
* 可执行元素的集合
|
||||
*/
|
||||
private List<Executable> executableList = new ArrayList<>();
|
||||
|
||||
private final Map<String, List<Executable>> executableGroup = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 当前所在的ChainName
|
||||
|
@ -34,6 +41,29 @@ public abstract class Condition implements Executable{
|
|||
*/
|
||||
private String currChainId;
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
try{
|
||||
executeCondition(slotIndex);
|
||||
}catch (ChainEndException e){
|
||||
//这里单独catch ChainEndException是因为ChainEndException是用户自己setIsEnd抛出的异常
|
||||
//是属于正常逻辑,所以会在FlowExecutor中判断。这里不作为异常处理
|
||||
throw e;
|
||||
}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);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void executeCondition(Integer slotIndex) throws Exception;
|
||||
|
||||
@Override
|
||||
public ExecuteTypeEnum getExecuteType() {
|
||||
return ExecuteTypeEnum.CONDITION;
|
||||
|
@ -45,15 +75,44 @@ public abstract class Condition implements Executable{
|
|||
}
|
||||
|
||||
public List<Executable> getExecutableList() {
|
||||
return getExecutableList(ConditionKey.DEFAULT_KEY);
|
||||
}
|
||||
|
||||
public List<Executable> getExecutableList(String groupKey) {
|
||||
List<Executable> executableList = this.executableGroup.get(groupKey);
|
||||
if (CollUtil.isEmpty(executableList)){
|
||||
executableList = new ArrayList<>();
|
||||
}
|
||||
return executableList;
|
||||
}
|
||||
|
||||
public Executable getExecutableOne(String groupKey) {
|
||||
List<Executable> list = getExecutableList(groupKey);
|
||||
if (CollUtil.isEmpty(list)){
|
||||
return null;
|
||||
}else{
|
||||
return list.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void setExecutableList(List<Executable> executableList) {
|
||||
this.executableList = executableList;
|
||||
this.executableGroup.put(ConditionKey.DEFAULT_KEY, executableList);
|
||||
}
|
||||
|
||||
public void addExecutable(Executable executable) {
|
||||
this.executableList.add(executable);
|
||||
addExecutable(ConditionKey.DEFAULT_KEY, executable);
|
||||
}
|
||||
|
||||
public void addExecutable(String groupKey, Executable executable) {
|
||||
if (ObjectUtil.isNull(executable)){
|
||||
return;
|
||||
}
|
||||
List<Executable> executableList = this.executableGroup.get(groupKey);
|
||||
if (CollUtil.isEmpty(executableList)){
|
||||
this.executableGroup.put(groupKey, ListUtil.toList(executable));
|
||||
}else{
|
||||
this.executableGroup.get(groupKey).add(executable);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract ConditionTypeEnum getConditionType();
|
||||
|
@ -68,7 +127,6 @@ public abstract class Condition implements Executable{
|
|||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* @deprecated 请使用 {@link #setCurrChainId(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -84,4 +142,8 @@ public abstract class Condition implements Executable{
|
|||
public void setCurrChainId(String currChainId) {
|
||||
this.currChainId = currChainId;
|
||||
}
|
||||
|
||||
public Map<String, List<Executable>> getExecutableGroup() {
|
||||
return executableGroup;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
public interface ConditionKey {
|
||||
|
||||
String DEFAULT_KEY = "DEFAULT_KEY";
|
||||
|
||||
String FOR_KEY = "FOR_KEY";
|
||||
|
||||
String IF_KEY = "IF_KEY";
|
||||
|
||||
String IF_TRUE_CASE_KEY = "IF_TRUE_CASE_KEY";
|
||||
|
||||
String IF_FALSE_CASE_KEY = "IF_FALSE_CASE_KEY";
|
||||
|
||||
String ITERATOR_KEY = "ITERATOR_KEY";
|
||||
|
||||
String DO_KEY = "DO_KEY";
|
||||
|
||||
String BREAK_KEY = "BREAK_KEY";
|
||||
|
||||
String SWITCH_KEY = "SWITCH_KEY";
|
||||
|
||||
String SWITCH_TARGET_KEY = "SWITCH_TARGET_KEY";
|
||||
|
||||
String SWITCH_DEFAULT_KEY = "SWITCH_DEFAULT_KEY";
|
||||
|
||||
String PRE_KEY = "PRE_KEY";
|
||||
|
||||
String FINALLY_KEY = "FINALLY_KEY";
|
||||
|
||||
String WHILE_KEY = "WHILE_KEY";
|
||||
|
||||
String CATCH_KEY = "CATCH_KEY";
|
||||
}
|
|
@ -18,7 +18,7 @@ import com.yomahub.liteflow.flow.element.Executable;
|
|||
public class FinallyCondition extends Condition {
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
for(Executable executableItem : this.getExecutableList()){
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
executableItem.execute(slotIndex);
|
||||
|
|
|
@ -18,28 +18,35 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
|||
*/
|
||||
public class ForCondition extends LoopCondition{
|
||||
|
||||
private Node forNode;
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
Node forNode = this.getForNode();
|
||||
if (ObjectUtil.isNull(forNode)){
|
||||
String errorInfo = StrUtil.format("[{}]:no for-node found", slot.getRequestId());
|
||||
throw new NoForNodeException(errorInfo);
|
||||
}
|
||||
|
||||
//先去判断isAccess方法,如果isAccess方法都返回false,整个FOR表达式不执行
|
||||
if (!this.getForNode().isAccess(slotIndex)){
|
||||
return;
|
||||
}
|
||||
|
||||
//执行forCount组件
|
||||
forNode.setCurrChainId(this.getCurrChainId());
|
||||
forNode.execute(slotIndex);
|
||||
|
||||
//这里可能会有spring代理过的bean,所以拿到user原始的class
|
||||
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(this.forNode.getInstance().getClass());
|
||||
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(forNode.getInstance().getClass());
|
||||
//获得循环次数
|
||||
int forCount = slot.getForResult(originalForCountClass.getName());
|
||||
|
||||
//获得要循环的可执行对象
|
||||
Executable executableItem = this.getDoExecutor();
|
||||
|
||||
//获取Break节点
|
||||
Node breakNode = this.getBreakNode();
|
||||
|
||||
//循环执行
|
||||
for (int i = 0; i < forCount; i++) {
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
|
@ -51,7 +58,7 @@ public class ForCondition extends LoopCondition{
|
|||
breakNode.setCurrChainId(this.getCurrChainId());
|
||||
setLoopIndex(breakNode, i);
|
||||
breakNode.execute(slotIndex);
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
|
||||
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
|
||||
if (isBreak){
|
||||
break;
|
||||
|
@ -66,10 +73,10 @@ public class ForCondition extends LoopCondition{
|
|||
}
|
||||
|
||||
public Node getForNode() {
|
||||
return forNode;
|
||||
return (Node) this.getExecutableOne(ConditionKey.FOR_KEY);
|
||||
}
|
||||
|
||||
public void setForNode(Node forNode) {
|
||||
this.forNode = forNode;
|
||||
this.addExecutable(ConditionKey.FOR_KEY, forNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
|||
*/
|
||||
public class IfCondition extends Condition {
|
||||
|
||||
private Executable trueCaseExecutableItem;
|
||||
|
||||
private Executable falseCaseExecutableItem;
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
if (ListUtil.toList(NodeTypeEnum.IF, NodeTypeEnum.IF_SCRIPT).contains(getIfNode().getType())){
|
||||
//先去判断isAccess方法,如果isAccess方法都返回false,整个IF表达式不执行
|
||||
if (!this.getIfNode().isAccess(slotIndex)){
|
||||
return;
|
||||
}
|
||||
|
||||
//先执行IF节点
|
||||
this.getIfNode().setCurrChainId(this.getCurrChainId());
|
||||
this.getIfNode().execute(slotIndex);
|
||||
|
@ -37,6 +38,9 @@ public class IfCondition extends Condition {
|
|||
//拿到If执行过的结果
|
||||
boolean ifResult = slot.getIfResult(originalClass.getName());
|
||||
|
||||
Executable trueCaseExecutableItem = this.getTrueCaseExecutableItem();
|
||||
Executable falseCaseExecutableItem = this.getFalseCaseExecutableItem();
|
||||
|
||||
if (ifResult) {
|
||||
//trueCaseExecutableItem这个不能为空,否则执行什么呢
|
||||
if (ObjectUtil.isNull(trueCaseExecutableItem)) {
|
||||
|
@ -51,7 +55,7 @@ public class IfCondition extends Condition {
|
|||
}
|
||||
|
||||
//执行trueCaseExecutableItem
|
||||
trueCaseExecutableItem.setCurrChainName(this.getCurrChainName());
|
||||
trueCaseExecutableItem.setCurrChainId(this.getCurrChainId());
|
||||
trueCaseExecutableItem.execute(slotIndex);
|
||||
} else {
|
||||
//falseCaseExecutableItem可以为null,但是不为null时就执行否的情况
|
||||
|
@ -78,22 +82,26 @@ public class IfCondition extends Condition {
|
|||
}
|
||||
|
||||
public Executable getTrueCaseExecutableItem() {
|
||||
return trueCaseExecutableItem;
|
||||
return this.getExecutableOne(ConditionKey.IF_TRUE_CASE_KEY);
|
||||
}
|
||||
|
||||
public void setTrueCaseExecutableItem(Executable trueCaseExecutableItem) {
|
||||
this.trueCaseExecutableItem = trueCaseExecutableItem;
|
||||
this.addExecutable(ConditionKey.IF_TRUE_CASE_KEY, trueCaseExecutableItem);
|
||||
}
|
||||
|
||||
public Executable getFalseCaseExecutableItem() {
|
||||
return falseCaseExecutableItem;
|
||||
return this.getExecutableOne(ConditionKey.IF_FALSE_CASE_KEY);
|
||||
}
|
||||
|
||||
public void setFalseCaseExecutableItem(Executable falseCaseExecutableItem) {
|
||||
this.falseCaseExecutableItem = falseCaseExecutableItem;
|
||||
this.addExecutable(ConditionKey.IF_FALSE_CASE_KEY, falseCaseExecutableItem);
|
||||
}
|
||||
|
||||
public void setIfNode(Node ifNode){
|
||||
this.addExecutable(ConditionKey.IF_KEY, ifNode);
|
||||
}
|
||||
|
||||
public Node getIfNode() {
|
||||
return (Node) this.getExecutableList().get(0);
|
||||
return (Node) this.getExecutableOne(ConditionKey.IF_KEY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,28 +14,36 @@ import java.util.Iterator;
|
|||
|
||||
public class IteratorCondition extends LoopCondition{
|
||||
|
||||
private Node iteratorNode;
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
Node iteratorNode = this.getIteratorNode();
|
||||
|
||||
if (ObjectUtil.isNull(iteratorNode)){
|
||||
String errorInfo = StrUtil.format("[{}]:no iterator-node found", slot.getRequestId());
|
||||
throw new NoIteratorNodeException(errorInfo);
|
||||
}
|
||||
|
||||
//先去判断isAccess方法,如果isAccess方法都返回false,整个ITERATOR表达式不执行
|
||||
if (!this.getIteratorNode().isAccess(slotIndex)){
|
||||
return;
|
||||
}
|
||||
|
||||
//执行Iterator组件
|
||||
iteratorNode.setCurrChainId(this.getCurrChainId());
|
||||
iteratorNode.execute(slotIndex);
|
||||
|
||||
//这里可能会有spring代理过的bean,所以拿到user原始的class
|
||||
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(this.iteratorNode.getInstance().getClass());
|
||||
Class<?> originalForCountClass = LiteFlowProxyUtil.getUserClass(iteratorNode.getInstance().getClass());
|
||||
//获得迭代器
|
||||
Iterator<?> it = slot.getIteratorResult(originalForCountClass.getName());
|
||||
|
||||
//获得要循环的可执行对象
|
||||
Executable executableItem = this.getDoExecutor();
|
||||
|
||||
//获取Break节点
|
||||
Node breakNode = this.getBreakNode();
|
||||
|
||||
int index = 0;
|
||||
while(it.hasNext()){
|
||||
Object itObj = it.next();
|
||||
|
@ -53,7 +61,7 @@ public class IteratorCondition extends LoopCondition{
|
|||
setLoopIndex(breakNode, index);
|
||||
setCurrLoopObject(breakNode, itObj);
|
||||
breakNode.execute(slotIndex);
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
|
||||
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
|
||||
if (isBreak){
|
||||
break;
|
||||
|
@ -69,10 +77,10 @@ public class IteratorCondition extends LoopCondition{
|
|||
}
|
||||
|
||||
public Node getIteratorNode() {
|
||||
return iteratorNode;
|
||||
return (Node) this.getExecutableOne(ConditionKey.ITERATOR_KEY);
|
||||
}
|
||||
|
||||
public void setIteratorNode(Node iteratorNode) {
|
||||
this.iteratorNode = iteratorNode;
|
||||
this.addExecutable(ConditionKey.ITERATOR_KEY, iteratorNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@ import com.yomahub.liteflow.flow.element.Chain;
|
|||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 循环Condition的抽象类
|
||||
* 主要继承对象有ForCondition和WhileCondition
|
||||
|
@ -13,25 +17,27 @@ import com.yomahub.liteflow.flow.element.Node;
|
|||
*/
|
||||
public abstract class LoopCondition extends Condition {
|
||||
|
||||
protected Node breakNode;
|
||||
|
||||
public Node getBreakNode() {
|
||||
return breakNode;
|
||||
protected Node getBreakNode() {
|
||||
return (Node) this.getExecutableOne(ConditionKey.BREAK_KEY);
|
||||
}
|
||||
|
||||
public void setBreakNode(Node breakNode) {
|
||||
this.breakNode = breakNode;
|
||||
this.addExecutable(ConditionKey.BREAK_KEY, breakNode);
|
||||
}
|
||||
|
||||
protected Executable getDoExecutor() {
|
||||
return this.getExecutableOne(ConditionKey.DO_KEY);
|
||||
}
|
||||
|
||||
public void setDoExecutor(Executable executable) {
|
||||
this.addExecutable(ConditionKey.DO_KEY, executable);
|
||||
}
|
||||
|
||||
protected void setLoopIndex(Executable executableItem, int index){
|
||||
if (executableItem instanceof Chain){
|
||||
((Chain)executableItem).getConditionList().forEach(condition -> setLoopIndex(condition, index));
|
||||
}else if(executableItem instanceof IfCondition){
|
||||
((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
|
||||
setLoopIndex(((IfCondition)executableItem).getTrueCaseExecutableItem(), index);
|
||||
setLoopIndex(((IfCondition)executableItem).getFalseCaseExecutableItem(), index);
|
||||
}else if(executableItem instanceof Condition){
|
||||
((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
|
||||
((Condition) executableItem).getExecutableGroup().forEach((key, value) -> value.forEach(executable -> setLoopIndex(executable, index)));
|
||||
}else if(executableItem instanceof Node){
|
||||
((Node)executableItem).setLoopIndex(index);
|
||||
}
|
||||
|
@ -40,18 +46,12 @@ public abstract class LoopCondition extends Condition {
|
|||
protected void setCurrLoopObject(Executable executableItem, Object obj){
|
||||
if (executableItem instanceof Chain){
|
||||
((Chain)executableItem).getConditionList().forEach(condition -> setCurrLoopObject(condition, obj));
|
||||
}else if(executableItem instanceof IfCondition){
|
||||
((Condition)executableItem).getExecutableList().forEach(executable -> setCurrLoopObject(executable, obj));
|
||||
setCurrLoopObject(((IfCondition)executableItem).getTrueCaseExecutableItem(), obj);
|
||||
setCurrLoopObject(((IfCondition)executableItem).getFalseCaseExecutableItem(), obj);
|
||||
}else if(executableItem instanceof Condition){
|
||||
((Condition)executableItem).getExecutableList().forEach(executable -> setCurrLoopObject(executable, obj));
|
||||
((Condition) executableItem).getExecutableGroup().forEach((key, value) -> value.forEach(executable -> setCurrLoopObject(executable, obj)));
|
||||
}else if(executableItem instanceof Node){
|
||||
((Node)executableItem).setCurrLoopObject(obj);
|
||||
}
|
||||
}
|
||||
|
||||
protected Executable getDoExecutor() {
|
||||
return this.getExecutableList().get(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import com.yomahub.liteflow.flow.element.Executable;
|
|||
public class PreCondition extends Condition {
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
for(Executable executableItem : this.getExecutableList()){
|
||||
executableItem.setCurrChainId(this.getCurrChainId());
|
||||
executableItem.execute(slotIndex);
|
||||
|
|
|
@ -23,27 +23,30 @@ import java.util.List;
|
|||
* @since 2.8.0
|
||||
*/
|
||||
public class SwitchCondition extends Condition{
|
||||
|
||||
|
||||
private final List<Executable> targetList = new ArrayList<>();
|
||||
|
||||
private final String TAG_PREFIX = "tag";
|
||||
private final String TAG_FLAG = ":";
|
||||
|
||||
private Executable defaultExecutor;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
if (ListUtil.toList(NodeTypeEnum.SWITCH, NodeTypeEnum.SWITCH_SCRIPT).contains(this.getSwitchNode().getType())){
|
||||
//获取switch node
|
||||
Node switchNode = this.getSwitchNode();
|
||||
//获取target List
|
||||
List<Executable> targetList = this.getTargetList();
|
||||
|
||||
//先去判断isAccess方法,如果isAccess方法都返回false,整个SWITCH表达式不执行
|
||||
if (!switchNode.isAccess(slotIndex)){
|
||||
return;
|
||||
}
|
||||
|
||||
//先执行switch节点
|
||||
this.getSwitchNode().setCurrChainId(this.getCurrChainId());
|
||||
this.getSwitchNode().execute(slotIndex);
|
||||
switchNode.setCurrChainId(this.getCurrChainId());
|
||||
switchNode.execute(slotIndex);
|
||||
|
||||
//根据switch节点执行出来的结果选择
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
//这里可能会有spring代理过的bean,所以拿到user原始的class
|
||||
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(this.getSwitchNode().getInstance().getClass());
|
||||
Class<?> originalClass = LiteFlowProxyUtil.getUserClass(switchNode.getInstance().getClass());
|
||||
String targetId = slot.getSwitchResult(originalClass.getName());
|
||||
|
||||
Executable targetExecutor = null;
|
||||
|
@ -70,7 +73,7 @@ public class SwitchCondition extends Condition{
|
|||
|
||||
if (ObjectUtil.isNull(targetExecutor)) {
|
||||
//没有匹配到执行节点,则走默认的执行节点
|
||||
targetExecutor = defaultExecutor;
|
||||
targetExecutor = this.getDefaultExecutor();
|
||||
}
|
||||
|
||||
if (ObjectUtil.isNotNull(targetExecutor)) {
|
||||
|
@ -98,26 +101,26 @@ public class SwitchCondition extends Condition{
|
|||
}
|
||||
|
||||
public void addTargetItem(Executable executable){
|
||||
this.targetList.add(executable);
|
||||
}
|
||||
|
||||
public void setSwitchNode(Node switchNode) {
|
||||
this.getExecutableList().add(switchNode);
|
||||
this.addExecutable(ConditionKey.SWITCH_TARGET_KEY, executable);
|
||||
}
|
||||
|
||||
public List<Executable> getTargetList(){
|
||||
return targetList;
|
||||
return this.getExecutableList(ConditionKey.SWITCH_TARGET_KEY);
|
||||
}
|
||||
|
||||
public void setSwitchNode(Node switchNode) {
|
||||
this.addExecutable(ConditionKey.SWITCH_KEY, switchNode);
|
||||
}
|
||||
|
||||
public Node getSwitchNode(){
|
||||
return (Node) this.getExecutableList().get(0);
|
||||
return (Node) this.getExecutableOne(ConditionKey.SWITCH_KEY);
|
||||
}
|
||||
|
||||
public Executable getDefaultExecutor() {
|
||||
return defaultExecutor;
|
||||
return this.getExecutableOne(ConditionKey.SWITCH_DEFAULT_KEY);
|
||||
}
|
||||
|
||||
public void setDefaultExecutor(Executable defaultExecutor) {
|
||||
this.defaultExecutor = defaultExecutor;
|
||||
this.addExecutable(ConditionKey.SWITCH_DEFAULT_KEY, defaultExecutor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,8 @@ import com.yomahub.liteflow.exception.ChainEndException;
|
|||
import com.yomahub.liteflow.flow.element.Executable;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 串行器
|
||||
|
@ -22,23 +21,16 @@ import java.util.List;
|
|||
*/
|
||||
public class ThenCondition extends Condition {
|
||||
|
||||
/**
|
||||
* 前置处理Condition
|
||||
*/
|
||||
private final List<PreCondition> preConditionList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 后置处理Condition
|
||||
*/
|
||||
private final List<FinallyCondition> finallyConditionList = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public ConditionTypeEnum getConditionType() {
|
||||
return ConditionTypeEnum.TYPE_THEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
List<PreCondition> preConditionList = this.getPreConditionList();
|
||||
List<FinallyCondition> finallyConditionList = this.getFinallyConditionList();
|
||||
|
||||
try{
|
||||
for (PreCondition preCondition : preConditionList){
|
||||
preCondition.setCurrChainId(this.getCurrChainId());
|
||||
|
@ -74,11 +66,27 @@ public class ThenCondition extends Condition {
|
|||
@Override
|
||||
public void addExecutable(Executable executable) {
|
||||
if (executable instanceof PreCondition){
|
||||
preConditionList.add((PreCondition) executable);
|
||||
this.addPreCondition((PreCondition) executable);
|
||||
}else if (executable instanceof FinallyCondition){
|
||||
finallyConditionList.add((FinallyCondition) executable);
|
||||
this.addFinallyCondition((FinallyCondition) executable);
|
||||
}else{
|
||||
super.addExecutable(executable);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PreCondition> getPreConditionList() {
|
||||
return this.getExecutableList(ConditionKey.PRE_KEY).stream().map(executable -> (PreCondition) executable).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void addPreCondition(PreCondition preCondition){
|
||||
this.addExecutable(ConditionKey.PRE_KEY, preCondition);
|
||||
}
|
||||
|
||||
public List<FinallyCondition> getFinallyConditionList() {
|
||||
return this.getExecutableList(ConditionKey.FINALLY_KEY).stream().map(executable -> (FinallyCondition) executable).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void addFinallyCondition(FinallyCondition finallyCondition){
|
||||
this.addExecutable(ConditionKey.FINALLY_KEY, finallyCondition);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class WhenCondition extends Condition {
|
|||
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
executeAsyncCondition(slotIndex);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,19 +18,26 @@ import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
|||
*/
|
||||
public class WhileCondition extends LoopCondition{
|
||||
|
||||
private Node whileNode;
|
||||
|
||||
@Override
|
||||
public void execute(Integer slotIndex) throws Exception {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
Node whileNode = this.getWhileNode();
|
||||
if (ObjectUtil.isNull(whileNode)){
|
||||
String errorInfo = StrUtil.format("[{}]:no while-node found", slot.getRequestId());
|
||||
throw new NoWhileNodeException(errorInfo);
|
||||
}
|
||||
|
||||
//先去判断isAccess方法,如果isAccess方法都返回false,整个WHILE表达式不执行
|
||||
if (!this.getWhileNode().isAccess(slotIndex)){
|
||||
return;
|
||||
}
|
||||
|
||||
//获得要循环的可执行对象
|
||||
Executable executableItem = this.getDoExecutor();
|
||||
|
||||
//获取Break节点
|
||||
Node breakNode = this.getBreakNode();
|
||||
|
||||
//循环执行
|
||||
int index = 0;
|
||||
while(getWhileResult(slotIndex)){
|
||||
|
@ -42,7 +49,7 @@ public class WhileCondition extends LoopCondition{
|
|||
breakNode.setCurrChainId(this.getCurrChainId());
|
||||
setLoopIndex(breakNode, index);
|
||||
breakNode.execute(slotIndex);
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(this.breakNode.getInstance().getClass());
|
||||
Class<?> originalBreakClass = LiteFlowProxyUtil.getUserClass(breakNode.getInstance().getClass());
|
||||
boolean isBreak = slot.getBreakResult(originalBreakClass.getName());
|
||||
if (isBreak){
|
||||
break;
|
||||
|
@ -54,10 +61,11 @@ public class WhileCondition extends LoopCondition{
|
|||
|
||||
private boolean getWhileResult(Integer slotIndex) throws Exception{
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
Node whileNode = this.getWhileNode();
|
||||
//执行while组件
|
||||
whileNode.setCurrChainId(this.getCurrChainId());
|
||||
whileNode.execute(slotIndex);
|
||||
Class<?> originalWhileClass = LiteFlowProxyUtil.getUserClass(this.whileNode.getInstance().getClass());
|
||||
Class<?> originalWhileClass = LiteFlowProxyUtil.getUserClass(whileNode.getInstance().getClass());
|
||||
return slot.getWhileResult(originalWhileClass.getName());
|
||||
}
|
||||
|
||||
|
@ -67,10 +75,10 @@ public class WhileCondition extends LoopCondition{
|
|||
}
|
||||
|
||||
public Node getWhileNode() {
|
||||
return whileNode;
|
||||
return (Node) this.getExecutableOne(ConditionKey.WHILE_KEY);
|
||||
}
|
||||
|
||||
public void setWhileNode(Node whileNode) {
|
||||
this.whileNode = whileNode;
|
||||
this.addExecutable(ConditionKey.WHILE_KEY, whileNode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,4 +100,8 @@ public class MonitorBus {
|
|||
public void closeScheduler(){
|
||||
this.printLogScheduler.shutdown();
|
||||
}
|
||||
|
||||
public ConcurrentHashMap<String, BoundedPriorityBlockingQueue<CompStatistics>> getStatisticsMap() {
|
||||
return statisticsMap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package com.yomahub.liteflow.monitor;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.watch.SimpleWatcher;
|
||||
import cn.hutool.core.io.watch.WatchMonitor;
|
||||
import cn.hutool.core.io.watch.watchers.DelayWatcher;
|
||||
import cn.hutool.core.lang.Singleton;
|
||||
import com.yomahub.liteflow.core.FlowExecutorHolder;
|
||||
import org.apache.commons.io.filefilter.FileFilterUtils;
|
||||
import org.apache.commons.io.filefilter.HiddenFileFilter;
|
||||
import org.apache.commons.io.filefilter.IOFileFilter;
|
||||
import org.apache.commons.io.monitor.FileAlterationListener;
|
||||
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
|
||||
import org.apache.commons.io.monitor.FileAlterationMonitor;
|
||||
import org.apache.commons.io.monitor.FileAlterationObserver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.WatchEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 规则文件监听器
|
||||
*
|
||||
* @author tangkc
|
||||
*/
|
||||
public class MonitorFile {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private final Set<String> PATH_SET = new HashSet<>();
|
||||
|
||||
public static MonitorFile getInstance() {
|
||||
return Singleton.get(MonitorFile.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加监听文件路径
|
||||
*
|
||||
* @param path 文件路径
|
||||
*/
|
||||
public void addMonitorFilePath(String path) {
|
||||
if (FileUtil.isFile(path)){
|
||||
String parentFolder = FileUtil.getParent(path, 1);
|
||||
PATH_SET.add(parentFolder);
|
||||
}else{
|
||||
PATH_SET.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加监听文件路径
|
||||
*
|
||||
* @param filePaths 文件路径
|
||||
*/
|
||||
public void addMonitorFilePaths(List<String> filePaths) {
|
||||
filePaths.forEach(this::addMonitorFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件监听
|
||||
*/
|
||||
public void create() throws Exception{
|
||||
for (String path : PATH_SET) {
|
||||
long interval = TimeUnit.MILLISECONDS.toMillis(2);
|
||||
//不使用过滤器
|
||||
FileAlterationObserver observer = new FileAlterationObserver(new File(path));
|
||||
observer.addListener(new FileAlterationListenerAdaptor() {
|
||||
@Override
|
||||
public void onFileChange(File file) {
|
||||
logger.info("file modify,filePath={}", file.getAbsolutePath());
|
||||
FlowExecutorHolder.loadInstance().reloadRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDelete(File file) {
|
||||
logger.info("file delete,filePath={}", file.getAbsolutePath());
|
||||
FlowExecutorHolder.loadInstance().reloadRule();
|
||||
}
|
||||
});
|
||||
//创建文件变化监听器
|
||||
FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
|
||||
// 开始监控
|
||||
monitor.start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* 基于本地的json方式EL表达式解析器
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.8.0
|
||||
*/
|
||||
|
|
|
@ -44,6 +44,7 @@ public class ParserHelper {
|
|||
String script = nodePropBean.getScript();
|
||||
String type = nodePropBean.getType();
|
||||
String file = nodePropBean.getFile();
|
||||
String language = nodePropBean.getLanguage();
|
||||
|
||||
//clazz有值的,基本都不是脚本节点
|
||||
//脚本节点,都必须配置type
|
||||
|
@ -80,6 +81,7 @@ public class ParserHelper {
|
|||
.setType(nodeTypeEnum)
|
||||
.setScript(script)
|
||||
.setFile(file)
|
||||
.setLanguage(language)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -98,7 +100,7 @@ public class ParserHelper {
|
|||
// 当存在<nodes>节点定义时,解析node节点
|
||||
if (ObjectUtil.isNotNull(nodesElement)) {
|
||||
List<Element> nodeList = nodesElement.elements(NODE);
|
||||
String id, name, clazz, type, script, file;
|
||||
String id, name, clazz, type, script, file, language;
|
||||
for (Element e : nodeList) {
|
||||
id = e.attributeValue(ID);
|
||||
name = e.attributeValue(NAME);
|
||||
|
@ -106,6 +108,7 @@ public class ParserHelper {
|
|||
type = e.attributeValue(TYPE);
|
||||
script = e.getText();
|
||||
file = e.attributeValue(FILE);
|
||||
language = e.attributeValue(LANGUAGE);
|
||||
|
||||
// 构建 node
|
||||
NodePropBean nodePropBean = new NodePropBean()
|
||||
|
@ -114,7 +117,8 @@ public class ParserHelper {
|
|||
.setClazz(clazz)
|
||||
.setScript(script)
|
||||
.setType(type)
|
||||
.setFile(file);
|
||||
.setFile(file)
|
||||
.setLanguage(language);
|
||||
|
||||
ParserHelper.buildNode(nodePropBean);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,17 @@ public class LiteflowConfig {
|
|||
//替补组件class路径
|
||||
private String substituteCmpClass;
|
||||
|
||||
// 规则文件/脚本文件变更监听
|
||||
private Boolean enableMonitorFile = Boolean.FALSE;
|
||||
|
||||
public Boolean getEnableMonitorFile() {
|
||||
return enableMonitorFile;
|
||||
}
|
||||
|
||||
public void setEnableMonitorFile(Boolean enableMonitorFile) {
|
||||
this.enableMonitorFile = enableMonitorFile;
|
||||
}
|
||||
|
||||
public Boolean getEnable() {
|
||||
if (ObjectUtil.isNull(enable)) {
|
||||
return Boolean.TRUE;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.yomahub.liteflow.script;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
|
||||
/**
|
||||
* 脚本执行器接口
|
||||
* @author Bryan.Zhang
|
||||
|
@ -14,4 +16,6 @@ public interface ScriptExecutor {
|
|||
Object execute(ScriptExecuteWrap wrap) throws Exception;
|
||||
|
||||
void cleanCache();
|
||||
|
||||
ScriptTypeEnum scriptType();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
package com.yomahub.liteflow.script;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.exception.ScriptSpiException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 脚本执行器工厂类
|
||||
|
@ -14,7 +20,9 @@ public class ScriptExecutorFactory {
|
|||
|
||||
private static ScriptExecutorFactory scriptExecutorFactory;
|
||||
|
||||
private ScriptExecutor scriptExecutor;
|
||||
private final Map<String,ScriptExecutor> scriptExecutorMap = new HashMap<>();
|
||||
|
||||
private final String NONE_LANGUAGE = "none";
|
||||
|
||||
public static ScriptExecutorFactory loadInstance(){
|
||||
if (ObjectUtil.isNull(scriptExecutorFactory)){
|
||||
|
@ -23,17 +31,43 @@ public class ScriptExecutorFactory {
|
|||
return scriptExecutorFactory;
|
||||
}
|
||||
|
||||
public ScriptExecutor getScriptExecutor(){
|
||||
if (ObjectUtil.isNull(scriptExecutor)){
|
||||
public ScriptExecutor getScriptExecutor(String language){
|
||||
if (StrUtil.isBlank(language)){
|
||||
language = NONE_LANGUAGE;
|
||||
}
|
||||
|
||||
|
||||
if (!scriptExecutorMap.containsKey(language)){
|
||||
ServiceLoader<ScriptExecutor> loader = ServiceLoader.load(ScriptExecutor.class);
|
||||
|
||||
if (loader.iterator().hasNext()){
|
||||
scriptExecutor = loader.iterator().next().init();
|
||||
return scriptExecutor;
|
||||
}else{
|
||||
throw new ScriptSpiException("script spi component failed to load");
|
||||
ScriptExecutor scriptExecutor;
|
||||
Iterator<ScriptExecutor> it = loader.iterator();
|
||||
while(it.hasNext()){
|
||||
scriptExecutor = it.next().init();
|
||||
if (language.equals(NONE_LANGUAGE)){
|
||||
scriptExecutorMap.put(language, scriptExecutor);
|
||||
break;
|
||||
}else{
|
||||
ScriptTypeEnum scriptType = ScriptTypeEnum.getEnumByDisplayName(language);
|
||||
if (ObjectUtil.isNull(scriptType)){
|
||||
throw new ScriptSpiException("script language config error");
|
||||
}
|
||||
if (scriptType.equals(scriptExecutor.scriptType())){
|
||||
scriptExecutorMap.put(language, scriptExecutor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return scriptExecutor;
|
||||
|
||||
if (scriptExecutorMap.containsKey(language)){
|
||||
return scriptExecutorMap.get(language);
|
||||
}else{
|
||||
throw new ScriptSpiException("script spi component failed to load");
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanScriptCache(){
|
||||
this.scriptExecutorMap.forEach((key, value) -> value.cleanCache());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package com.yomahub.liteflow.script.jsr223;
|
|||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.script.ScriptBeanManager;
|
||||
import com.yomahub.liteflow.script.ScriptExecuteWrap;
|
||||
|
@ -16,6 +18,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import javax.script.*;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* JSR223 script engine的统一实现抽象类
|
||||
|
@ -33,12 +36,10 @@ public abstract class JSR223ScriptExecutor implements ScriptExecutor {
|
|||
@Override
|
||||
public ScriptExecutor init() {
|
||||
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
|
||||
scriptEngine = scriptEngineManager.getEngineByName(scriptEngineName());
|
||||
scriptEngine = scriptEngineManager.getEngineByName(this.scriptType().getEngineName());
|
||||
return this;
|
||||
}
|
||||
|
||||
protected abstract String scriptEngineName();
|
||||
|
||||
protected String convertScript(String script){
|
||||
return script;
|
||||
}
|
||||
|
@ -71,7 +72,13 @@ public abstract class JSR223ScriptExecutor implements ScriptExecutor {
|
|||
//比如你的自定义上下文为AbcContext,那么key就为:abcContext
|
||||
//这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
|
||||
DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
|
||||
String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
|
||||
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());
|
||||
}
|
||||
bindings.put(key, o);
|
||||
});
|
||||
|
||||
|
|
|
@ -339,6 +339,10 @@ public class Slot{
|
|||
putMetaDataMap(EXCEPTION, e);
|
||||
}
|
||||
|
||||
public void removeException(){
|
||||
metaDataMap.remove(EXCEPTION);
|
||||
}
|
||||
|
||||
public Exception getSubException(String chainId) {
|
||||
return (Exception) this.metaDataMap.get(SUB_EXCEPTION_PREFIX + chainId);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,23 @@ package com.yomahub.liteflow.spi;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public interface PathContentParser extends SpiPriority{
|
||||
public interface PathContentParser extends SpiPriority {
|
||||
|
||||
/**
|
||||
* 解析路径下的文件内容
|
||||
*
|
||||
* @param pathList 文件路径(支持 classpath 路径和 file 绝对路径,spring 环境支持 PathMatchingResourcePatternResolver 规则)
|
||||
* @return 返回文件内容
|
||||
* @throws Exception ex
|
||||
*/
|
||||
List<String> parseContent(List<String> pathList) throws Exception;
|
||||
|
||||
/**
|
||||
* 获取文件路径的绝对路径
|
||||
*
|
||||
* @param pathList 文件路径(支持 classpath 路径和 file 绝对路径,spring 环境支持 PathMatchingResourcePatternResolver 规则)
|
||||
* @return 返回文件绝对路径
|
||||
* @throws Exception ex
|
||||
*/
|
||||
List<String> getFileAbsolutePath(List<String> pathList) throws Exception;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@ package com.yomahub.liteflow.spi.local;
|
|||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.io.resource.FileResource;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.util.ClassLoaderUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.exception.ConfigErrorException;
|
||||
import com.yomahub.liteflow.spi.PathContentParser;
|
||||
|
@ -18,14 +21,14 @@ public class LocalPathContentParser implements PathContentParser {
|
|||
|
||||
@Override
|
||||
public List<String> parseContent(List<String> pathList) throws Exception {
|
||||
if(CollectionUtil.isEmpty(pathList)){
|
||||
if (CollectionUtil.isEmpty(pathList)) {
|
||||
throw new ConfigErrorException("rule source must not be null");
|
||||
}
|
||||
|
||||
List<String> contentList = new ArrayList<>();
|
||||
|
||||
for(String path : pathList){
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)){
|
||||
for (String path : pathList) {
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
|
||||
path = FILE_URL_PREFIX + path;
|
||||
} else {
|
||||
if (!path.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
|
@ -33,7 +36,7 @@ public class LocalPathContentParser implements PathContentParser {
|
|||
}
|
||||
}
|
||||
String content = ResourceUtil.readUtf8Str(path);
|
||||
if (StrUtil.isNotBlank(content)){
|
||||
if (StrUtil.isNotBlank(content)) {
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +44,33 @@ public class LocalPathContentParser implements PathContentParser {
|
|||
return contentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
|
||||
if (CollectionUtil.isEmpty(pathList)) {
|
||||
throw new ConfigErrorException("rule source must not be null");
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
|
||||
for (String path : pathList) {
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
|
||||
path = FILE_URL_PREFIX + path;
|
||||
result.add(new FileResource(path).getFile().getAbsolutePath());
|
||||
} else {
|
||||
if (!path.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
path = CLASSPATH_URL_PREFIX + path;
|
||||
|
||||
// 这里会有自定义解析器
|
||||
if(ClassLoaderUtil.isPresent(path)){
|
||||
result.add(new ClassPathResource(path).getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 2;
|
||||
|
|
|
@ -26,8 +26,11 @@ public class LOGOPrinter {
|
|||
str.append(" | |___ | | | | | |__|_____| _| | |__| |_| |\\ V V / \n");
|
||||
str.append(" |_____|___| |_| |_____| |_| |_____\\___/ \\_/\\_/ \n\n");
|
||||
str.append(" Version: " + VERSION_NO + "\n");
|
||||
str.append(" 轻量且强大的规则引擎框架。\n");
|
||||
str.append(" 新一代轻量且强大的规则引擎编排框架。\n");
|
||||
str.append(" 基于开源社区文化,社区驱动型开源框架。\n");
|
||||
str.append(" Small but powerful rules engine.\n");
|
||||
str.append(" 官网地址:https://liteflow.yomahub.com/\n");
|
||||
str.append(" wechat:bryan_31\n");
|
||||
str.append("================================================================================================\n");
|
||||
LOG.info(str.toString());
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package com.yomahub.liteflow.parser.sql.util;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.XmlUtil;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.parser.sql.exception.ELSQLException;
|
||||
import com.yomahub.liteflow.parser.sql.vo.SQLParserVO;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
|
@ -22,250 +24,250 @@ import java.util.Objects;
|
|||
*/
|
||||
public class JDBCHelper {
|
||||
|
||||
private static final String SQL_PATTERN = "SELECT {},{} FROM {} WHERE {}=?";
|
||||
private static final String SQL_PATTERN = "SELECT {},{} FROM {} WHERE {}=?";
|
||||
|
||||
private static final String SCRIPT_SQL_CHECK_PATTERN = "SELECT 1 FROM {} WHERE {}=?";
|
||||
private static final String SCRIPT_SQL_CHECK_PATTERN = "SELECT 1 FROM {} WHERE {}=?";
|
||||
|
||||
private static final String SCRIPT_SQL_PATTERN = "SELECT {},{},{},{} FROM {} WHERE {}=?";
|
||||
private static final String SCRIPT_SQL_PATTERN = "SELECT {},{},{},{} FROM {} WHERE {}=?";
|
||||
|
||||
private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
|
||||
private static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
|
||||
private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";
|
||||
private static final String NODE_XML_PATTERN = "<nodes>{}</nodes>";
|
||||
|
||||
private static final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
|
||||
private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
|
||||
private static final Integer FETCH_SIZE_MAX = 1000;
|
||||
private static final String NODE_ITEM_XML_PATTERN = "<node id=\"{}\" name=\"{}\" type=\"{}\"><![CDATA[{}]]></node>";
|
||||
private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";
|
||||
private static final Integer FETCH_SIZE_MAX = 1000;
|
||||
|
||||
private SQLParserVO sqlParserVO;
|
||||
private SQLParserVO sqlParserVO;
|
||||
|
||||
private static JDBCHelper INSTANCE;
|
||||
private static JDBCHelper INSTANCE;
|
||||
|
||||
/**
|
||||
* 初始化 INSTANCE
|
||||
*/
|
||||
public static void init(SQLParserVO sqlParserVO) {
|
||||
try {
|
||||
INSTANCE = new JDBCHelper();
|
||||
Class.forName(sqlParserVO.getDriverClassName());
|
||||
INSTANCE.setSqlParserVO(sqlParserVO);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 初始化 INSTANCE
|
||||
*/
|
||||
public static void init(SQLParserVO sqlParserVO) {
|
||||
try {
|
||||
INSTANCE = new JDBCHelper();
|
||||
Class.forName(sqlParserVO.getDriverClassName());
|
||||
INSTANCE.setSqlParserVO(sqlParserVO);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 INSTANCE
|
||||
*/
|
||||
public static JDBCHelper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
/**
|
||||
* 获取 INSTANCE
|
||||
*/
|
||||
public static JDBCHelper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取链接
|
||||
*/
|
||||
public Connection getConn() {
|
||||
Connection connection;
|
||||
try {
|
||||
connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
/**
|
||||
* 获取链接
|
||||
*/
|
||||
public Connection getConn() {
|
||||
Connection connection;
|
||||
try {
|
||||
connection = DriverManager.getConnection(sqlParserVO.getUrl(), sqlParserVO.getUsername(), sqlParserVO.getPassword());
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 ElData 数据内容
|
||||
*/
|
||||
public String getContent() {
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
/**
|
||||
* 获取 ElData 数据内容
|
||||
*/
|
||||
public String getContent() {
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
String chainTableName = sqlParserVO.getChainTableName();
|
||||
String elDataField = sqlParserVO.getElDataField();
|
||||
String chainNameField = sqlParserVO.getChainNameField();
|
||||
String chainApplicationNameField = sqlParserVO.getChainApplicationNameField();
|
||||
String applicationName = sqlParserVO.getApplicationName();
|
||||
String chainTableName = sqlParserVO.getChainTableName();
|
||||
String elDataField = sqlParserVO.getElDataField();
|
||||
String chainNameField = sqlParserVO.getChainNameField();
|
||||
String chainApplicationNameField = sqlParserVO.getChainApplicationNameField();
|
||||
String applicationName = sqlParserVO.getApplicationName();
|
||||
|
||||
if(StrUtil.isBlank(chainTableName)){
|
||||
throw new ELSQLException("You did not define the chainTableName property");
|
||||
}
|
||||
if (StrUtil.isBlank(chainTableName)) {
|
||||
throw new ELSQLException("You did not define the chainTableName property");
|
||||
}
|
||||
|
||||
if(StrUtil.isBlank(applicationName) || StrUtil.isBlank(chainApplicationNameField)){
|
||||
throw new ELSQLException("You did not define the applicationName or chainApplicationNameField property");
|
||||
}
|
||||
if (StrUtil.isBlank(applicationName) || StrUtil.isBlank(chainApplicationNameField)) {
|
||||
throw new ELSQLException("You did not define the applicationName or chainApplicationNameField property");
|
||||
}
|
||||
|
||||
String sqlCmd = StrUtil.format(SQL_PATTERN, chainNameField, elDataField, chainTableName, chainApplicationNameField);
|
||||
String sqlCmd = StrUtil.format(SQL_PATTERN, chainNameField, elDataField, chainTableName, chainApplicationNameField);
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
// 设置游标拉取数量
|
||||
stmt.setFetchSize(FETCH_SIZE_MAX);
|
||||
stmt.setString(1, applicationName);
|
||||
rs = stmt.executeQuery();
|
||||
List<String> result = new ArrayList<>();
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
// 设置游标拉取数量
|
||||
stmt.setFetchSize(FETCH_SIZE_MAX);
|
||||
stmt.setString(1, applicationName);
|
||||
rs = stmt.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
String elData = getStringFromResultSet(rs, elDataField);
|
||||
String chainName = getStringFromResultSet(rs, chainNameField);
|
||||
while (rs.next()) {
|
||||
String elData = getStringFromResultSet(rs, elDataField);
|
||||
String chainName = getStringFromResultSet(rs, chainNameField);
|
||||
|
||||
result.add(StrUtil.format(CHAIN_XML_PATTERN, chainName, elData));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
result.add(StrUtil.format(CHAIN_XML_PATTERN, XmlUtil.escape(chainName), elData));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
|
||||
String chainsContent = CollUtil.join(result, StrUtil.EMPTY);
|
||||
String chainsContent = CollUtil.join(result, StrUtil.EMPTY);
|
||||
|
||||
String nodesContent;
|
||||
if (hasScriptData()){
|
||||
nodesContent = getScriptNodes();
|
||||
}else{
|
||||
nodesContent = StrUtil.EMPTY;
|
||||
}
|
||||
String nodesContent;
|
||||
if (hasScriptData()) {
|
||||
nodesContent = getScriptNodes();
|
||||
} else {
|
||||
nodesContent = StrUtil.EMPTY;
|
||||
}
|
||||
|
||||
return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
|
||||
}
|
||||
return StrUtil.format(XML_PATTERN, nodesContent, chainsContent);
|
||||
}
|
||||
|
||||
public String getScriptNodes() {
|
||||
List<String> result = new ArrayList<>();
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
public String getScriptNodes() {
|
||||
List<String> result = new ArrayList<>();
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
String scriptTableName = sqlParserVO.getScriptTableName();
|
||||
String scriptIdField = sqlParserVO.getScriptIdField();
|
||||
String scriptDataField = sqlParserVO.getScriptDataField();
|
||||
String scriptNameField = sqlParserVO.getScriptNameField();
|
||||
String scriptTypeField = sqlParserVO.getScriptTypeField();
|
||||
String scriptApplicationNameField = sqlParserVO.getScriptApplicationNameField();
|
||||
String applicationName = sqlParserVO.getApplicationName();
|
||||
String scriptTableName = sqlParserVO.getScriptTableName();
|
||||
String scriptIdField = sqlParserVO.getScriptIdField();
|
||||
String scriptDataField = sqlParserVO.getScriptDataField();
|
||||
String scriptNameField = sqlParserVO.getScriptNameField();
|
||||
String scriptTypeField = sqlParserVO.getScriptTypeField();
|
||||
String scriptApplicationNameField = sqlParserVO.getScriptApplicationNameField();
|
||||
String applicationName = sqlParserVO.getApplicationName();
|
||||
|
||||
if(StrUtil.isBlank(applicationName) || StrUtil.isBlank(scriptApplicationNameField)){
|
||||
throw new ELSQLException("You did not define the applicationName or scriptApplicationNameField property");
|
||||
}
|
||||
if (StrUtil.isBlank(applicationName) || StrUtil.isBlank(scriptApplicationNameField)) {
|
||||
throw new ELSQLException("You did not define the applicationName or scriptApplicationNameField property");
|
||||
}
|
||||
|
||||
String sqlCmd = StrUtil.format(
|
||||
SCRIPT_SQL_PATTERN,
|
||||
scriptIdField,
|
||||
scriptDataField,
|
||||
scriptNameField,
|
||||
scriptTypeField,
|
||||
scriptTableName,
|
||||
scriptApplicationNameField
|
||||
);
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
// 设置游标拉取数量
|
||||
stmt.setFetchSize(FETCH_SIZE_MAX);
|
||||
stmt.setString(1, applicationName);
|
||||
rs = stmt.executeQuery();
|
||||
String sqlCmd = StrUtil.format(
|
||||
SCRIPT_SQL_PATTERN,
|
||||
scriptIdField,
|
||||
scriptDataField,
|
||||
scriptNameField,
|
||||
scriptTypeField,
|
||||
scriptTableName,
|
||||
scriptApplicationNameField
|
||||
);
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
// 设置游标拉取数量
|
||||
stmt.setFetchSize(FETCH_SIZE_MAX);
|
||||
stmt.setString(1, applicationName);
|
||||
rs = stmt.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
String id = getStringFromResultSet(rs, scriptIdField);
|
||||
String data = getStringFromResultSet(rs, scriptDataField);
|
||||
String name = getStringFromResultSet(rs, scriptNameField);
|
||||
String type = getStringFromResultSet(rs, scriptTypeField);
|
||||
while (rs.next()) {
|
||||
String id = getStringFromResultSet(rs, scriptIdField);
|
||||
String data = getStringFromResultSet(rs, scriptDataField);
|
||||
String name = getStringFromResultSet(rs, scriptNameField);
|
||||
String type = getStringFromResultSet(rs, scriptTypeField);
|
||||
|
||||
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
|
||||
if (Objects.isNull(nodeTypeEnum)){
|
||||
throw new ELSQLException(StrUtil.format("Invalid type value[{}]", type));
|
||||
}
|
||||
NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getEnumByCode(type);
|
||||
if (Objects.isNull(nodeTypeEnum)) {
|
||||
throw new ELSQLException(StrUtil.format("Invalid type value[{}]", type));
|
||||
}
|
||||
|
||||
if (!nodeTypeEnum.isScript()) {
|
||||
throw new ELSQLException(StrUtil.format("The type value[{}] is not a script type", type));
|
||||
}
|
||||
if (!nodeTypeEnum.isScript()) {
|
||||
throw new ELSQLException(StrUtil.format("The type value[{}] is not a script type", type));
|
||||
}
|
||||
|
||||
result.add(StrUtil.format(NODE_ITEM_XML_PATTERN, id, name, type, data));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
return StrUtil.format(NODE_XML_PATTERN, CollUtil.join(result, StrUtil.EMPTY));
|
||||
}
|
||||
result.add(StrUtil.format(NODE_ITEM_XML_PATTERN, XmlUtil.escape(id), XmlUtil.escape(name), type, data));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
return StrUtil.format(NODE_XML_PATTERN, CollUtil.join(result, StrUtil.EMPTY));
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭连接
|
||||
*
|
||||
* @param conn conn
|
||||
* @param stmt stmt
|
||||
* @param rs rs
|
||||
*/
|
||||
private void close(Connection conn, PreparedStatement stmt, ResultSet rs) {
|
||||
// 关闭连接
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
// 关闭 statement
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
//关闭结果集
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 关闭连接
|
||||
*
|
||||
* @param conn conn
|
||||
* @param stmt stmt
|
||||
* @param rs rs
|
||||
*/
|
||||
private void close(Connection conn, PreparedStatement stmt, ResultSet rs) {
|
||||
// 关闭连接
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
// 关闭 statement
|
||||
if (stmt != null) {
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
//关闭结果集
|
||||
if (rs != null) {
|
||||
try {
|
||||
rs.close();
|
||||
} catch (SQLException e) {
|
||||
throw new ELSQLException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasScriptData(){
|
||||
if (StrUtil.isBlank(sqlParserVO.getScriptTableName())){
|
||||
return false;
|
||||
}
|
||||
private boolean hasScriptData() {
|
||||
if (StrUtil.isBlank(sqlParserVO.getScriptTableName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
String sqlCmd = StrUtil.format(SCRIPT_SQL_CHECK_PATTERN,
|
||||
sqlParserVO.getScriptTableName(),
|
||||
sqlParserVO.getScriptApplicationNameField());
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
stmt.setFetchSize(1);
|
||||
stmt.setString(1, sqlParserVO.getApplicationName());
|
||||
rs = stmt.executeQuery();
|
||||
return rs.next();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
}
|
||||
Connection conn = null;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
String sqlCmd = StrUtil.format(SCRIPT_SQL_CHECK_PATTERN,
|
||||
sqlParserVO.getScriptTableName(),
|
||||
sqlParserVO.getScriptApplicationNameField());
|
||||
try {
|
||||
conn = getConn();
|
||||
stmt = conn.prepareStatement(sqlCmd, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
|
||||
stmt.setFetchSize(1);
|
||||
stmt.setString(1, sqlParserVO.getApplicationName());
|
||||
rs = stmt.executeQuery();
|
||||
return rs.next();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
} finally {
|
||||
// 关闭连接
|
||||
close(conn, stmt, rs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#region get set method
|
||||
private String getStringFromResultSet(ResultSet rs, String field) throws SQLException {
|
||||
String data = rs.getString(field);
|
||||
if (StrUtil.isBlank(data)) {
|
||||
throw new ELSQLException(StrUtil.format("exist {} field value is empty", field));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
//#region get set method
|
||||
private String getStringFromResultSet(ResultSet rs, String field) throws SQLException {
|
||||
String data = rs.getString(field);
|
||||
if (StrUtil.isBlank(data)) {
|
||||
throw new ELSQLException(StrUtil.format("exist {} field value is empty", field));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private SQLParserVO getSqlParserVO() {
|
||||
return sqlParserVO;
|
||||
}
|
||||
private SQLParserVO getSqlParserVO() {
|
||||
return sqlParserVO;
|
||||
}
|
||||
|
||||
private void setSqlParserVO(SQLParserVO sqlParserVO) {
|
||||
this.sqlParserVO = sqlParserVO;
|
||||
}
|
||||
private void setSqlParserVO(SQLParserVO sqlParserVO) {
|
||||
this.sqlParserVO = sqlParserVO;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ package com.yomahub.liteflow.script.graaljs;
|
|||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.ScriptBeanManager;
|
||||
import com.yomahub.liteflow.script.ScriptExecuteWrap;
|
||||
import com.yomahub.liteflow.script.ScriptExecutor;
|
||||
|
@ -57,7 +60,13 @@ public class GraalJavaScriptExecutor implements ScriptExecutor {
|
|||
//比如你的自定义上下文为AbcContext,那么key就为:abcContext
|
||||
//这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
|
||||
DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
|
||||
String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
|
||||
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());
|
||||
}
|
||||
bindings.putMember(key, o);
|
||||
});
|
||||
|
||||
|
@ -103,4 +112,9 @@ public class GraalJavaScriptExecutor implements ScriptExecutor {
|
|||
public void cleanCache() {
|
||||
scriptMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.JS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.yomahub.liteflow.script.groovy;
|
||||
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
||||
|
||||
/**
|
||||
|
@ -10,7 +11,7 @@ import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
|||
public class GroovyScriptExecutor extends JSR223ScriptExecutor {
|
||||
|
||||
@Override
|
||||
protected String scriptEngineName() {
|
||||
return "groovy";
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.GROOVY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.yomahub.liteflow.script.javascript;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
||||
/**
|
||||
* JavaScript脚本语言的执行器实现
|
||||
|
@ -9,13 +10,13 @@ import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
|||
*/
|
||||
public class JavaScriptExecutor extends JSR223ScriptExecutor {
|
||||
|
||||
@Override
|
||||
protected String scriptEngineName() {
|
||||
return "javascript";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertScript(String script) {
|
||||
return StrUtil.format("function process(){{}} process();",script);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.JS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.yomahub.liteflow.script.lua;
|
|||
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -15,8 +16,8 @@ import java.util.stream.Collectors;
|
|||
*/
|
||||
public class LuaScriptExecutor extends JSR223ScriptExecutor {
|
||||
@Override
|
||||
protected String scriptEngineName() {
|
||||
return "luaj";
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.LUA;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.yomahub.liteflow.script.python;
|
|||
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.jsr223.JSR223ScriptExecutor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -15,8 +16,8 @@ import java.util.stream.Collectors;
|
|||
public class PythonScriptExecutor extends JSR223ScriptExecutor {
|
||||
|
||||
@Override
|
||||
protected String scriptEngineName() {
|
||||
return "python";
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.PYTHON;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,9 @@ import com.ql.util.express.DefaultContext;
|
|||
import com.ql.util.express.ExpressLoader;
|
||||
import com.ql.util.express.ExpressRunner;
|
||||
import com.ql.util.express.InstructionSet;
|
||||
import com.yomahub.liteflow.annotation.util.AnnoUtil;
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
import com.yomahub.liteflow.enums.ScriptTypeEnum;
|
||||
import com.yomahub.liteflow.script.ScriptBeanManager;
|
||||
import com.yomahub.liteflow.script.ScriptExecuteWrap;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
|
@ -69,7 +72,13 @@ public class QLExpressScriptExecutor implements ScriptExecutor {
|
|||
//比如你的自定义上下文为AbcContext,那么key就为:abcContext
|
||||
//这里不统一放一个map的原因是考虑到有些用户会调用上下文里的方法,而不是参数,所以脚本语言的绑定表里也是放多个上下文
|
||||
DataBus.getContextBeanList(wrap.getSlotIndex()).forEach(o -> {
|
||||
String key = StrUtil.lowerFirst(o.getClass().getSimpleName());
|
||||
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());
|
||||
}
|
||||
context.put(key, o);
|
||||
});
|
||||
|
||||
|
@ -108,4 +117,9 @@ public class QLExpressScriptExecutor implements ScriptExecutor {
|
|||
expressRunner.clearExpressCache();
|
||||
ReflectUtil.setFieldValue(expressRunner,"loader",new ExpressLoader(expressRunner));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTypeEnum scriptType() {
|
||||
return ScriptTypeEnum.QLEXPRESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.yomahub.liteflow.spi.solon;
|
|||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.stream.StreamUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.exception.ConfigErrorException;
|
||||
|
@ -10,17 +11,42 @@ import com.yomahub.liteflow.spi.PathContentParser;
|
|||
import org.noear.solon.Utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SolonPathContentParser implements PathContentParser {
|
||||
@Override
|
||||
public List<String> parseContent(List<String> pathList) throws Exception {
|
||||
if(CollectionUtil.isEmpty(pathList)){
|
||||
List<URL> allResource = getUrls(pathList);
|
||||
|
||||
//转换成内容List
|
||||
List<String> contentList = new ArrayList<>();
|
||||
for (URL resource : allResource) {
|
||||
String content = IoUtil.read(resource.openStream(), CharsetUtil.CHARSET_UTF_8);
|
||||
if (StrUtil.isNotBlank(content)) {
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return contentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
|
||||
List<URL> allResource = getUrls(pathList);
|
||||
return StreamUtil.of(allResource)
|
||||
.map(URL::getPath)
|
||||
.filter(FileUtil::isFile)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<URL> getUrls(List<String> pathList) throws MalformedURLException {
|
||||
if (CollectionUtil.isEmpty(pathList)) {
|
||||
throw new ConfigErrorException("rule source must not be null");
|
||||
}
|
||||
|
||||
|
@ -34,27 +60,19 @@ public class SolonPathContentParser implements PathContentParser {
|
|||
path = path.substring(ResourceUtils.CLASSPATH_URL_PREFIX.length());
|
||||
}
|
||||
|
||||
allResource.add(Utils.getResource(path));
|
||||
if (Utils.getResource(path) != null) {
|
||||
allResource.add(Utils.getResource(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//如果有多个资源,检查资源都是同一个类型,如果出现不同类型的配置,则抛出错误提示
|
||||
Set<String> fileTypeSet = new HashSet<>();
|
||||
allResource.forEach(resource -> fileTypeSet.add(FileUtil.extName(resource.getPath())));
|
||||
if (fileTypeSet.size() != 1) {
|
||||
if (fileTypeSet.size() > 1) {
|
||||
throw new ConfigErrorException("config error,please use the same type of configuration");
|
||||
}
|
||||
|
||||
//转换成内容List
|
||||
List<String> contentList = new ArrayList<>();
|
||||
for (URL resource : allResource) {
|
||||
String content = IoUtil.read(resource.openStream(), CharsetUtil.CHARSET_UTF_8);
|
||||
if (StrUtil.isNotBlank(content)){
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return contentList;
|
||||
return allResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -70,6 +70,17 @@ public class LiteflowProperty {
|
|||
//替补组件的class路径
|
||||
private String substituteCmpClass;
|
||||
|
||||
// 规则文件/脚本文件变更监听
|
||||
private Boolean enableMonitorFile;
|
||||
|
||||
public Boolean getEnableMonitorFile() {
|
||||
return enableMonitorFile;
|
||||
}
|
||||
|
||||
public void setEnableMonitorFile(Boolean enableMonitorFile) {
|
||||
this.enableMonitorFile = enableMonitorFile;
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return enable;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ public class LiteflowPropertyAutoConfiguration {
|
|||
liteflowConfig.setMainExecutorClass(property.getMainExecutorClass());
|
||||
liteflowConfig.setPrintExecutionLog(property.isPrintExecutionLog());
|
||||
liteflowConfig.setSubstituteCmpClass(property.getSubstituteCmpClass());
|
||||
liteflowConfig.setEnableMonitorFile(property.getEnableMonitorFile());
|
||||
return liteflowConfig;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,6 +158,13 @@
|
|||
"description": "Set period time to print monitor log.",
|
||||
"sourceType": "com.yomahub.liteflow.springboot.LiteflowMonitorProperty",
|
||||
"defaultValue": 300000
|
||||
},
|
||||
{
|
||||
"name": "liteflow.enable-monitor-file",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Set file change monitoring.",
|
||||
"sourceType": "com.yomahub.liteflow.springboot.LiteflowMonitorProperty",
|
||||
"defaultValue": false
|
||||
}
|
||||
]
|
||||
}
|
|
@ -18,3 +18,4 @@ liteflow.monitor.enable-log=false
|
|||
liteflow.monitor.queue-limit=200
|
||||
liteflow.monitor.delay=300000
|
||||
liteflow.monitor.period=300000
|
||||
liteflow.enable-monitor-file=false
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
com.yomahub.liteflow.springboot.config.LiteflowPropertyAutoConfiguration
|
||||
com.yomahub.liteflow.springboot.config.LiteflowMainAutoConfiguration
|
|
@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
|
|||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.stream.StreamUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
@ -13,15 +14,49 @@ import org.springframework.core.io.Resource;
|
|||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SpringPathContentParser implements PathContentParser {
|
||||
@Override
|
||||
public List<String> parseContent(List<String> pathList) throws Exception {
|
||||
if(CollectionUtil.isEmpty(pathList)){
|
||||
List<Resource> allResource = getResources(pathList);
|
||||
|
||||
//转换成内容List
|
||||
List<String> contentList = new ArrayList<>();
|
||||
for (Resource resource : allResource) {
|
||||
String content = IoUtil.read(resource.getInputStream(), CharsetUtil.CHARSET_UTF_8);
|
||||
if (StrUtil.isNotBlank(content)) {
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return contentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
|
||||
List<Resource> allResource = getResources(pathList);
|
||||
|
||||
return StreamUtil.of(allResource)
|
||||
// 过滤非 file 类型 Resource
|
||||
.filter(Resource::isFile)
|
||||
.map(r -> {
|
||||
try {
|
||||
return r.getFile().getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Resource> getResources(List<String> pathList) throws IOException {
|
||||
if (CollectionUtil.isEmpty(pathList)) {
|
||||
throw new ConfigErrorException("rule source must not be null");
|
||||
}
|
||||
|
||||
|
@ -30,12 +65,12 @@ public class SpringPathContentParser implements PathContentParser {
|
|||
String locationPattern;
|
||||
|
||||
//如果path是绝对路径且这个文件存在时,我们认为这是一个本地文件路径,而并非classpath路径
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)){
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
|
||||
locationPattern = ResourceUtils.FILE_URL_PREFIX + path;
|
||||
} else {
|
||||
if (!path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) && !path.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
|
||||
locationPattern = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||
}else{
|
||||
} else {
|
||||
locationPattern = path;
|
||||
}
|
||||
}
|
||||
|
@ -53,19 +88,10 @@ public class SpringPathContentParser implements PathContentParser {
|
|||
if (fileTypeSet.size() > 1) {
|
||||
throw new ConfigErrorException("config error,please use the same type of configuration");
|
||||
}
|
||||
|
||||
//转换成内容List
|
||||
List<String> contentList = new ArrayList<>();
|
||||
for (Resource resource : allResource) {
|
||||
String content = IoUtil.read(resource.getInputStream(), CharsetUtil.CHARSET_UTF_8);
|
||||
if (StrUtil.isNotBlank(content)){
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return contentList;
|
||||
return allResource;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.yomahub.liteflow.test.monitorFile;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/monitorFile/application.properties")
|
||||
@SpringBootTest(classes = MonitorFileELDeclMultiSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.monitorFile.cmp"})
|
||||
public class MonitorFileELDeclMultiSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testMonitor() throws Exception{
|
||||
String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
|
||||
String content = FileUtil.readUtf8String(absolutePath);
|
||||
String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
|
||||
FileUtil.writeString(newContent,new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
|
||||
Thread.sleep(2500);
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@LiteflowComponent
|
||||
public class CmpConfig {
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "a")
|
||||
public void processA(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b")
|
||||
public void processB(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c")
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
liteflow.rule-source=monitorFile/flow.el.xml
|
||||
liteflow.enable-monitor-file=true
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN(a, b, c);
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,40 @@
|
|||
package com.yomahub.liteflow.test.monitorFile;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/monitorFile/application.properties")
|
||||
@SpringBootTest(classes = MonitorFileELDeclSpringbootTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.monitorFile.cmp"})
|
||||
public class MonitorFileELDeclSpringbootTest extends BaseTest {
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testMonitor() throws Exception{
|
||||
String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
|
||||
String content = FileUtil.readUtf8String(absolutePath);
|
||||
String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
|
||||
FileUtil.writeString(newContent,new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
|
||||
Thread.sleep(2500);
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("a")
|
||||
public class ACmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("b")
|
||||
public class BCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp{
|
||||
|
||||
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
|
||||
public void process(NodeComponent bindCmp) {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -46,7 +46,7 @@ public class RefreshRuleELDeclSpringbootTest extends BaseTest {
|
|||
public void testRefresh2() throws Exception{
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(3000L);
|
||||
Thread.sleep(2000L);
|
||||
String content = ResourceUtil.readUtf8Str("classpath: /refreshRule/flow_update.el.xml");
|
||||
FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, content);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
liteflow.rule-source=monitorFile/flow.el.xml
|
||||
liteflow.enable-monitor-file=true
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<chain name="chain1">
|
||||
THEN(a, b, c);
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,40 @@
|
|||
package com.yomahub.liteflow.test.monitorFile;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
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.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class LiteflowMonitorFileTest extends BaseTest {
|
||||
|
||||
private static FlowExecutor flowExecutor;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
LiteflowConfig config = new LiteflowConfig();
|
||||
config.setRuleSource("monitorFile/flow.el.xml");
|
||||
config.setEnableMonitorFile(true);
|
||||
flowExecutor = FlowExecutorHolder.loadInstance(config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonitor() throws InterruptedException {
|
||||
String absolutePath = new ClassPathResource("classpath:/monitorFile/flow.el.xml").getAbsolutePath();
|
||||
String content = FileUtil.readUtf8String(absolutePath);
|
||||
String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
|
||||
FileUtil.writeString(newContent, new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
|
||||
Thread.sleep(2500);
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
|
||||
Assert.assertEquals("a==>c==>b", response.getExecuteStepStr());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class ACmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("ACmp executed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class BCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("BCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.monitorFile.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
<nodes>
|
||||
<node id="a" class="com.yomahub.liteflow.test.multipleType.cmp.ACmp"/>
|
||||
<node id="b" class="com.yomahub.liteflow.test.multipleType.cmp.BCmp"/>
|
||||
<node id="c" class="com.yomahub.liteflow.test.multipleType.cmp.CCmp"/>
|
||||
</nodes>
|
||||
|
||||
<chain name="chain1">
|
||||
THEN(a, b, c);
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,55 @@
|
|||
package com.yomahub.liteflow.test.script.graaljs.contextbean;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.CheckContext;
|
||||
import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.Order2Context;
|
||||
import com.yomahub.liteflow.test.script.graaljs.contextbean.bean.OrderContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/contextbean/application.properties")
|
||||
@SpringBootTest(classes = LiteFlowScriptContextbeanGraaljsTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.script.graaljs.contextbean.cmp","com.yomahub.liteflow.test.script.graaljs.contextbean.bean"})
|
||||
public class LiteFlowScriptContextbeanGraaljsTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testContextBean1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
OrderContext orderContext = response.getContextBean(OrderContext.class);
|
||||
CheckContext checkContext = response.getContextBean(CheckContext.class);
|
||||
Order2Context order2Context = response.getContextBean(Order2Context.class);
|
||||
Assert.assertEquals("order1", orderContext.getOrderNo());
|
||||
Assert.assertEquals("d", checkContext.getSign());
|
||||
Assert.assertEquals("order2", order2Context.getOrderNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextBean2() throws Exception{
|
||||
OrderContext orderContext = new OrderContext();
|
||||
orderContext.setOrderNo("order1");
|
||||
CheckContext checkContext = new CheckContext();
|
||||
checkContext.setSign("sign1");
|
||||
Order2Context orderContext2 = new Order2Context();
|
||||
orderContext2.setOrderNo("order2");
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", null, orderContext, checkContext, orderContext2);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.yomahub.liteflow.test.script.graaljs.contextbean.bean;
|
||||
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
|
||||
@ContextBean
|
||||
public class CheckContext {
|
||||
|
||||
private String sign;
|
||||
|
||||
private int randomId;
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
public int getRandomId() {
|
||||
return randomId;
|
||||
}
|
||||
|
||||
public void setRandomId(int randomId) {
|
||||
this.randomId = randomId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.yomahub.liteflow.test.script.graaljs.contextbean.bean;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Order2Context {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private int orderType;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
public String getOrderNo() {
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo) {
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public int getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
public void setOrderType(int orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.yomahub.liteflow.test.script.graaljs.contextbean.bean;
|
||||
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ContextBean("order")
|
||||
public class OrderContext {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private int orderType;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
public String getOrderNo() {
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo) {
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public int getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
public void setOrderType(int orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.graaljs.contextbean.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,21 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.graaljs.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,21 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.graaljs.contextbean.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=contextbean/flow.xml
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
|
||||
<nodes>
|
||||
<node id="d" type="script" language="js">
|
||||
<![CDATA[
|
||||
order.setOrderNo("order1")
|
||||
checkContext.setSign(_meta.get("nodeId"))
|
||||
order2Context.setOrderNo("order2")
|
||||
]]>
|
||||
</node>
|
||||
|
||||
<node id="e" type="script" language="js">
|
||||
<![CDATA[
|
||||
var orderNo = order.getOrderNo()
|
||||
var sign = checkContext.getSign()
|
||||
var orderNo2 = order2Context.getOrderNo()
|
||||
]]>
|
||||
</node>
|
||||
</nodes>
|
||||
|
||||
<chain name="chain1">
|
||||
THEN(a,b,c,d);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
THEN(a,b,c,e);
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,55 @@
|
|||
package com.yomahub.liteflow.test.script.groovy.contextbean;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.script.groovy.contextbean.bean.CheckContext;
|
||||
import com.yomahub.liteflow.test.script.groovy.contextbean.bean.Order2Context;
|
||||
import com.yomahub.liteflow.test.script.groovy.contextbean.bean.OrderContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/contextbean/application.properties")
|
||||
@SpringBootTest(classes = LiteFlowScriptContextbeanGroovyELTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.script.groovy.contextbean.cmp","com.yomahub.liteflow.test.script.groovy.contextbean.bean"})
|
||||
public class LiteFlowScriptContextbeanGroovyELTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testContextBean1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
OrderContext orderContext = response.getContextBean(OrderContext.class);
|
||||
CheckContext checkContext = response.getContextBean(CheckContext.class);
|
||||
Order2Context order2Context = response.getContextBean(Order2Context.class);
|
||||
Assert.assertEquals("order1", orderContext.getOrderNo());
|
||||
Assert.assertEquals("sign1", checkContext.getSign());
|
||||
Assert.assertEquals("order2", order2Context.getOrderNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextBean2() throws Exception{
|
||||
OrderContext orderContext = new OrderContext();
|
||||
orderContext.setOrderNo("order1");
|
||||
CheckContext checkContext = new CheckContext();
|
||||
checkContext.setSign("sign1");
|
||||
Order2Context orderContext2 = new Order2Context();
|
||||
orderContext2.setOrderNo("order2");
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", null, orderContext, checkContext, orderContext2);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.yomahub.liteflow.test.script.groovy.contextbean.bean;
|
||||
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
|
||||
@ContextBean
|
||||
public class CheckContext {
|
||||
|
||||
private String sign;
|
||||
|
||||
private int randomId;
|
||||
|
||||
public String getSign() {
|
||||
return sign;
|
||||
}
|
||||
|
||||
public void setSign(String sign) {
|
||||
this.sign = sign;
|
||||
}
|
||||
|
||||
public int getRandomId() {
|
||||
return randomId;
|
||||
}
|
||||
|
||||
public void setRandomId(int randomId) {
|
||||
this.randomId = randomId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.yomahub.liteflow.test.script.groovy.contextbean.bean;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class Order2Context {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private int orderType;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
public String getOrderNo() {
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo) {
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public int getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
public void setOrderType(int orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.yomahub.liteflow.test.script.groovy.contextbean.bean;
|
||||
|
||||
import com.yomahub.liteflow.context.ContextBean;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ContextBean("order")
|
||||
public class OrderContext {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private int orderType;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
public String getOrderNo() {
|
||||
return orderNo;
|
||||
}
|
||||
|
||||
public void setOrderNo(String orderNo) {
|
||||
this.orderNo = orderNo;
|
||||
}
|
||||
|
||||
public int getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
public void setOrderType(int orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.groovy.contextbean.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,21 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.groovy.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,21 @@
|
|||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.test.script.groovy.contextbean.cmp;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component("c")
|
||||
public class CCmp extends NodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
System.out.println("CCmp executed!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
liteflow.rule-source=contextbean/flow.xml
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flow>
|
||||
|
||||
<nodes>
|
||||
<node id="d" type="script" language="groovy">
|
||||
<![CDATA[
|
||||
order.setOrderNo("order1")
|
||||
checkContext.setSign("sign1")
|
||||
order2Context.setOrderNo("order2")
|
||||
]]>
|
||||
</node>
|
||||
|
||||
<node id="e" type="script" language="groovy">
|
||||
<![CDATA[
|
||||
def orderNo = order.getOrderNo()
|
||||
println orderNo
|
||||
def sign = checkContext.getSign()
|
||||
println sign
|
||||
def orderNo2 = order2Context.getOrderNo()
|
||||
println orderNo2
|
||||
]]>
|
||||
</node>
|
||||
</nodes>
|
||||
|
||||
<chain name="chain1">
|
||||
THEN(a,b,c,d);
|
||||
</chain>
|
||||
|
||||
<chain name="chain2">
|
||||
THEN(a,b,c,e);
|
||||
</chain>
|
||||
|
||||
</flow>
|
|
@ -0,0 +1,55 @@
|
|||
package com.yomahub.liteflow.test.script.javascript.contextbean;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.test.BaseTest;
|
||||
import com.yomahub.liteflow.test.script.javascript.contextbean.bean.CheckContext;
|
||||
import com.yomahub.liteflow.test.script.javascript.contextbean.bean.Order2Context;
|
||||
import com.yomahub.liteflow.test.script.javascript.contextbean.bean.OrderContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@TestPropertySource(value = "classpath:/contextbean/application.properties")
|
||||
@SpringBootTest(classes = LiteFlowScriptContextbeanJavaScriptTest.class)
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan({"com.yomahub.liteflow.test.script.javascript.contextbean.cmp","com.yomahub.liteflow.test.script.javascript.contextbean.bean"})
|
||||
public class LiteFlowScriptContextbeanJavaScriptTest extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
@Test
|
||||
public void testContextBean1() throws Exception{
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg", OrderContext.class, CheckContext.class, Order2Context.class);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
OrderContext orderContext = response.getContextBean(OrderContext.class);
|
||||
CheckContext checkContext = response.getContextBean(CheckContext.class);
|
||||
Order2Context order2Context = response.getContextBean(Order2Context.class);
|
||||
Assert.assertEquals("order1", orderContext.getOrderNo());
|
||||
Assert.assertEquals("sign1", checkContext.getSign());
|
||||
Assert.assertEquals("order2", order2Context.getOrderNo());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextBean2() throws Exception{
|
||||
OrderContext orderContext = new OrderContext();
|
||||
orderContext.setOrderNo("order1");
|
||||
CheckContext checkContext = new CheckContext();
|
||||
checkContext.setSign("sign1");
|
||||
Order2Context orderContext2 = new Order2Context();
|
||||
orderContext2.setOrderNo("order2");
|
||||
LiteflowResponse response = flowExecutor.execute2Resp("chain2", null, orderContext, checkContext, orderContext2);
|
||||
Assert.assertTrue(response.isSuccess());
|
||||
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue