diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java index 542974912..9321da703 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/builder/LiteFlowNodeBuilder.java @@ -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 scriptList = PathContentParserHolder.loadContextAware().parseContent(ListUtil.toList(filePath)); String script = CollUtil.getFirst(scriptList); setScript(script); + + // 添加脚本文件监听 + List 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); diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java index da831e266..655f1abef 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/core/FlowExecutor.java @@ -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 loader = ServiceLoader.load(ParserClassNameSpi.class); Iterator 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,9 @@ public class FlowExecutor { //支持多类型的配置文件,分别解析 if (BooleanUtil.isTrue(liteflowConfig.isSupportMultipleType())) { + // 添加监听文件路径 + addMonitorFilePaths(ListUtil.toList(path)); + // 解析文件 parser.parseMain(ListUtil.toList(path)); } } catch (CyclicDependencyException e) { @@ -148,6 +153,9 @@ public class FlowExecutor { //进行多个配置文件的一起解析 try { if (parser != null) { + // 添加监听文件路径 + addMonitorFilePaths(rulePathList); + // 解析文件 parser.parseMain(rulePathList); } else { throw new ConfigErrorException("parse error, please check liteflow config property"); @@ -167,30 +175,37 @@ 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()) { + MonitorFile.getInstance().create(); + } } //此方法就是从原有的配置源主动拉取新的进行刷新 //和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 +213,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 +255,7 @@ public class FlowExecutor { //调用一个流程并返回Future,允许多上下文的传入 public Future 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 +266,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 +284,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 +303,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 +326,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 +341,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 +366,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 +383,7 @@ public class FlowExecutor { //如果是隐式流程,则需要设置到隐式流程的exception属性里 if (innerChainType.equals(InnerChainTypeEnum.NONE)) { slot.setException(e); - }else{ + } else { slot.setSubException(chainId, e); } } finally { @@ -389,4 +404,15 @@ public class FlowExecutor { //把liteFlowConfig设到LiteFlowGetter中去 LiteflowConfigGetter.setLiteflowConfig(liteflowConfig); } + + /** + * 添加监听文件路径 + * + * @param pathList 文件路径 + */ + private void addMonitorFilePaths(List pathList) throws Exception { + // 添加规则文件监听 + List fileAbsolutePath = PathContentParserHolder.loadContextAware().getFileAbsolutePath(pathList); + MonitorFile.getInstance().addMonitorFilePaths(fileAbsolutePath); + } } \ No newline at end of file diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorFile.java b/liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorFile.java new file mode 100644 index 000000000..e9de20135 --- /dev/null +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/monitor/MonitorFile.java @@ -0,0 +1,74 @@ +package com.yomahub.liteflow.monitor; + +import cn.hutool.core.collection.CollUtil; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.util.ArrayList; +import java.util.List; + +/** + * 规则文件监听器 + * + * @author tangkc + */ +public class MonitorFile { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final List PATH_LIST = new ArrayList<>(); + + public static MonitorFile getInstance() { + return Singleton.get(MonitorFile.class); + } + + /** + * 添加监听文件路径 + * + * @param filePath 文件路径 + */ + public void addMonitorFilePath(String filePath) { + PATH_LIST.add(filePath); + } + + /** + * 添加监听文件路径 + * + * @param filePaths 文件路径 + */ + public void addMonitorFilePaths(List filePaths) { + PATH_LIST.addAll(filePaths); + } + + /** + * 创建文件监听 + */ + public void create() { + for (String filePath : CollUtil.distinct(PATH_LIST)) { + // 这里只监听两种类型,文件修改和文件覆盖 + WatchMonitor.createAll(filePath, new DelayWatcher(new SimpleWatcher() { + + @Override + public void onModify(WatchEvent event, Path currentPath) { + logger.info("file modify,filePath={}", filePath); + FlowExecutorHolder.loadInstance().reloadRule(); + } + + @Override + public void onOverflow(WatchEvent event, Path currentPath) { + logger.info("file over flow,filePath={}", filePath); + FlowExecutorHolder.loadInstance().reloadRule(); + } + // 在监听目录或文件时,如果这个文件有修改操作,JDK会多次触发modify方法,为了解决这个问题 + // 合并 500 毫秒内相同的变化 + }, 500)).start(); + } + } + +} diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java index c343b37c6..6c6aa1a91 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/parser/el/LocalJsonFlowELParser.java @@ -6,6 +6,7 @@ import java.util.List; /** * 基于本地的json方式EL表达式解析器 + * * @author Bryan.Zhang * @since 2.8.0 */ diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java index 072671d95..0f1179207 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/property/LiteflowConfig.java @@ -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; diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java index 10682a487..c39b4f74a 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/spi/PathContentParser.java @@ -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 parseContent(List pathList) throws Exception; + + /** + * 获取文件路径的绝对路径 + * + * @param pathList 文件路径(支持 classpath 路径和 file 绝对路径,spring 环境支持 PathMatchingResourcePatternResolver 规则) + * @return 返回文件绝对路径 + * @throws Exception ex + */ + List getFileAbsolutePath(List pathList) throws Exception; } diff --git a/liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java b/liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java index af7387b9e..d8d34d5ad 100644 --- a/liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java +++ b/liteflow-core/src/main/java/com/yomahub/liteflow/spi/local/LocalPathContentParser.java @@ -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 parseContent(List pathList) throws Exception { - if(CollectionUtil.isEmpty(pathList)){ + if (CollectionUtil.isEmpty(pathList)) { throw new ConfigErrorException("rule source must not be null"); } List 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 getFileAbsolutePath(List pathList) throws Exception { + if (CollectionUtil.isEmpty(pathList)) { + throw new ConfigErrorException("rule source must not be null"); + } + + List 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; diff --git a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java index b2774d0f1..e25dbe9ae 100644 --- a/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java +++ b/liteflow-solon-plugin/src/main/java/com/yomahub/liteflow/spi/solon/SolonPathContentParser.java @@ -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 parseContent(List pathList) throws Exception { - if(CollectionUtil.isEmpty(pathList)){ + List allResource = getUrls(pathList); + + //转换成内容List + List 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 getFileAbsolutePath(List pathList) throws Exception { + List allResource = getUrls(pathList); + return StreamUtil.of(allResource) + .map(URL::getPath) + .filter(FileUtil::isFile) + .collect(Collectors.toList()); + } + + private static List getUrls(List 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 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 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 diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java index 2b7f33c1c..6b0155465 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/LiteflowProperty.java @@ -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; } diff --git a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java index bd7d4efbe..8f2f51506 100644 --- a/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java +++ b/liteflow-spring-boot-starter/src/main/java/com/yomahub/liteflow/springboot/config/LiteflowPropertyAutoConfiguration.java @@ -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; } } diff --git a/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json index d20c0e939..5258f753d 100644 --- a/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/liteflow-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -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 } ] } \ No newline at end of file diff --git a/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties b/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties index 35a41afd5..b3f17ce32 100644 --- a/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties +++ b/liteflow-spring-boot-starter/src/main/resources/META-INF/liteflow-default.properties @@ -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 diff --git a/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java b/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java index 822aa411b..a0f433ce4 100644 --- a/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java +++ b/liteflow-spring/src/main/java/com/yomahub/liteflow/spi/spring/SpringPathContentParser.java @@ -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 parseContent(List pathList) throws Exception { - if(CollectionUtil.isEmpty(pathList)){ + List allResource = getResources(pathList); + + //转换成内容List + List 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 getFileAbsolutePath(List pathList) throws Exception { + List 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 getResources(List 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 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; diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclMultiSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclMultiSpringbootTest.java new file mode 100644 index 000000000..1d9caf64b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclMultiSpringbootTest.java @@ -0,0 +1,42 @@ +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 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 { + @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(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertEquals("a==>c==>b", response.getExecuteStepStr()); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CmpConfig.java b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CmpConfig.java new file mode 100644 index 000000000..d794c9053 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CmpConfig.java @@ -0,0 +1,44 @@ +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) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + + System.out.println("ACmp executed!"); + } + + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "b") + public void processB(NodeComponent bindCmp) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } + @LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "c") + public void process(NodeComponent bindCmp) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } +} + + diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/application.properties b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/application.properties new file mode 100644 index 000000000..361f7e90e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=monitorFile/flow.el.xml +liteflow.enable-monitor-file=true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..98c3cbae6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-multi-springboot/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, c); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclSpringbootTest.java new file mode 100644 index 000000000..b4bc848bc --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELDeclSpringbootTest.java @@ -0,0 +1,42 @@ +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(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertEquals("a==>c==>b", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java new file mode 100644 index 000000000..296b2f62e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java new file mode 100644 index 000000000..042853aa6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java new file mode 100644 index 000000000..2d80c88f5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java @@ -0,0 +1,30 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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) { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/application.properties b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/application.properties new file mode 100644 index 000000000..361f7e90e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=monitorFile/flow.el.xml +liteflow.enable-monitor-file=true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..98c3cbae6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-declare-springboot/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, c); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/LiteflowMonitorFileTest.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/LiteflowMonitorFileTest.java new file mode 100644 index 000000000..bda2f5f3b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/LiteflowMonitorFileTest.java @@ -0,0 +1,42 @@ +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 testMultipleType() 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(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertEquals("a==>c==>b", response.getExecuteStepStr()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java new file mode 100644 index 000000000..f022ab133 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java @@ -0,0 +1,18 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java new file mode 100644 index 000000000..8b108f065 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java new file mode 100644 index 000000000..6323f2318 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java @@ -0,0 +1,19 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @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!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..f436cc9cb --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-nospring/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,13 @@ + + + + + + + + + + THEN(a, b, c); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/MonitorFileGroovyELTest.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/MonitorFileGroovyELTest.java new file mode 100644 index 000000000..b3a3f66fe --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/MonitorFileGroovyELTest.java @@ -0,0 +1,47 @@ +package com.yomahub.liteflow.test.script.groovy.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.slot.DefaultContext; +import com.yomahub.liteflow.test.BaseTest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.io.File; + +@RunWith(SpringRunner.class) +@TestPropertySource(value = "classpath:/monitorFile/application.properties") +@SpringBootTest(classes = MonitorFileGroovyELTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.script.groovy.monitorFile.cmp"}) +public class MonitorFileGroovyELTest extends BaseTest { + + @Resource + private FlowExecutor flowExecutor; + + @Test + public void testMonitor() throws Exception{ + String absolutePath = new ClassPathResource("classpath:/monitorFile/s1.groovy").getAbsolutePath(); + String content = FileUtil.readUtf8String(absolutePath); + String newContent = content.replace("a=3", "a=2"); + FileUtil.writeString(newContent,new File(absolutePath), CharsetUtil.CHARSET_UTF_8); + + Thread.sleep(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + DefaultContext context = response.getFirstContextBean(); + Assert.assertTrue(response.isSuccess()); + Assert.assertEquals(Integer.valueOf(4), context.getData("s1")); + + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/ACmp.java new file mode 100644 index 000000000..fc46a1502 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/ACmp.java @@ -0,0 +1,20 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.script.groovy.monitorFile.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!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/BCmp.java new file mode 100644 index 000000000..39e6c75ac --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/BCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.script.groovy.monitorFile.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!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/CCmp.java new file mode 100644 index 000000000..2ff034c28 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/CCmp.java @@ -0,0 +1,21 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.script.groovy.monitorFile.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!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/DCmp.java b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/DCmp.java new file mode 100644 index 000000000..cb0453ee8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/java/com/yomahub/liteflow/test/script/groovy/monitorFile/cmp/DCmp.java @@ -0,0 +1,29 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.script.groovy.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import com.yomahub.liteflow.slot.DefaultContext; +import org.springframework.stereotype.Component; + +@Component("d") +public class DCmp extends NodeComponent { + + @Override + public void process() { + DefaultContext context = this.getFirstContextBean(); + String key = "test"; + if (context.hasData(key)){ + int count = context.getData(key); + context.setData(key, ++count); + }else{ + context.setData(key, 1); + } + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/application.properties b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/application.properties new file mode 100644 index 000000000..361f7e90e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=monitorFile/flow.el.xml +liteflow.enable-monitor-file=true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..8cb2b8655 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,12 @@ + + + + + + + + + THEN(a, b, c, s1); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/s1.groovy b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/s1.groovy new file mode 100644 index 000000000..02ae4756f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-script-groovy-springboot/src/test/resources/monitorFile/s1.groovy @@ -0,0 +1,3 @@ +Integer a=3 +Integer b=2 +defaultContext.setData("s1",a*b) \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java new file mode 100644 index 000000000..b1e45fa39 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java @@ -0,0 +1,36 @@ +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 org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.noear.solon.annotation.Inject; +import org.noear.solon.test.SolonJUnit4ClassRunner; +import org.noear.solon.test.annotation.TestPropertySource; + +import java.io.File; + +@RunWith(SolonJUnit4ClassRunner.class) +@TestPropertySource("classpath:/monitorFile/application.properties") +public class MonitorFileELSpringbootTest { + + @Inject + 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(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertEquals("a==>c==>b", response.getExecuteStepStr()); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java new file mode 100644 index 000000000..e56e014b5 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java new file mode 100644 index 000000000..08608f56b --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java new file mode 100644 index 000000000..f39944edf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.noear.solon.annotation.Component; + +import java.util.Random; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/application.properties b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/application.properties new file mode 100644 index 000000000..361f7e90e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=monitorFile/flow.el.xml +liteflow.enable-monitor-file=true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..98c3cbae6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-solon/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, c); + + + \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java new file mode 100644 index 000000000..c9a403bf8 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/MonitorFileELSpringbootTest.java @@ -0,0 +1,43 @@ +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 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 = MonitorFileELSpringbootTest.class) +@EnableAutoConfiguration +@ComponentScan({"com.yomahub.liteflow.test.monitorFile.cmp"}) +public class MonitorFileELSpringbootTest { + + @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(1000); + + LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg"); + Assert.assertEquals("a==>c==>b", response.getExecuteStepStr()); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java new file mode 100644 index 000000000..fa8d164cf --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/ACmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +import java.util.Random; + +@Component("a") +public class ACmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + + System.out.println("ACmp executed!"); + } +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java new file mode 100644 index 000000000..5a43cdda7 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/BCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +import java.util.Random; + +@Component("b") +public class BCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("BCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java new file mode 100644 index 000000000..71b96537f --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/java/com/yomahub/liteflow/test/monitorFile/cmp/CCmp.java @@ -0,0 +1,28 @@ +/** + *

Title: liteflow

+ *

Description: 轻量级的组件式流程框架

+ * @author Bryan.Zhang + * @email weenyc31@163.com + * @Date 2020/4/1 + */ +package com.yomahub.liteflow.test.monitorFile.cmp; + +import com.yomahub.liteflow.core.NodeComponent; +import org.springframework.stereotype.Component; + +import java.util.Random; + +@Component("c") +public class CCmp extends NodeComponent { + + @Override + public void process() { + try { + Thread.sleep(new Random().nextInt(2000)); + }catch (Exception e){ + e.printStackTrace(); + } + System.out.println("CCmp executed!"); + } + +} diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/application.properties b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/application.properties new file mode 100644 index 000000000..361f7e90e --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/application.properties @@ -0,0 +1,2 @@ +liteflow.rule-source=monitorFile/flow.el.xml +liteflow.enable-monitor-file=true \ No newline at end of file diff --git a/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/flow.el.xml b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/flow.el.xml new file mode 100644 index 000000000..98c3cbae6 --- /dev/null +++ b/liteflow-testcase-el/liteflow-testcase-el-springboot/src/test/resources/monitorFile/flow.el.xml @@ -0,0 +1,7 @@ + + + + THEN(a, b, c); + + + \ No newline at end of file