支持绝对路径的模糊匹配

This commit is contained in:
rain 2023-10-06 15:38:39 +08:00
parent 9fa94af5a8
commit 70954b4ae2
18 changed files with 175 additions and 58 deletions

View File

@ -9,6 +9,7 @@ import cn.hutool.core.util.ClassLoaderUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.exception.ConfigErrorException;
import com.yomahub.liteflow.spi.PathContentParser;
import com.yomahub.liteflow.util.PathMatchUtil;
import java.util.ArrayList;
import java.util.List;
@ -24,10 +25,11 @@ public class LocalPathContentParser implements PathContentParser {
if (CollectionUtil.isEmpty(pathList)) {
throw new ConfigErrorException("rule source must not be null");
}
List<String> absolutePathList = PathMatchUtil.searchAbsolutePath(pathList);
List<String> contentList = new ArrayList<>();
for (String path : pathList) {
for (String path : absolutePathList) {
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
path = FILE_URL_PREFIX + path;
}
@ -50,10 +52,10 @@ public class LocalPathContentParser implements PathContentParser {
if (CollectionUtil.isEmpty(pathList)) {
throw new ConfigErrorException("rule source must not be null");
}
List<String> absolutePathList = PathMatchUtil.searchAbsolutePath(pathList);
List<String> result = new ArrayList<>();
for (String path : pathList) {
for (String path : absolutePathList) {
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)) {
path = FILE_URL_PREFIX + path;
result.add(new FileResource(path).getFile().getAbsolutePath());

View File

@ -0,0 +1,73 @@
package com.yomahub.liteflow.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.AntPathMatcher;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用于获取模糊匹配的路径
*
* @author Rain
* @since 2.11.1
*/
public class PathMatchUtil {
public static List<String> searchAbsolutePath(List<String> pathList) {
List<String> absolutePathList = new ArrayList<>();
for (String path : pathList) {
// 只对绝对路径进行处理
if(FileUtil.isAbsolutePath(path)) {
if(!path.contains("*")) {
absolutePathList.add(path);
}
else {
String[] pathSegments = path.split("/");
StringBuilder baseDir = new StringBuilder();
// 找到最大基础路径
for(int i = 0; i < pathSegments.length; i ++) {
if(!pathSegments[i].contains("*")) {
baseDir.append(pathSegments[i]).append(File.separator);
} else {
baseDir.deleteCharAt(baseDir.length() - 1);
searchAbsolutePath(baseDir.toString(), path, absolutePathList);
break;
}
}
}
} else {
absolutePathList.add(path);
}
}
// 路径去重
List<String> newAbsolutePathList = absolutePathList.stream()
.distinct()
.collect(Collectors.toList());
return newAbsolutePathList;
}
private static void searchAbsolutePath(String baseDir, String path, List<String> absolutePathList) {
AntPathMatcher pathMatcher = new AntPathMatcher();
File dir = new File(baseDir);
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
searchAbsolutePath(file.getAbsolutePath(), path, absolutePathList);
} else {
String absolutePath = file.getAbsolutePath().replace("\\", "/");
if (pathMatcher.match(path, absolutePath)) {
absolutePathList.add(absolutePath);
}
}
}
}
}
}

View File

@ -1,8 +1,11 @@
package com.yomahub.liteflow.solon.config;
import cn.hutool.core.io.FileUtil;
import com.yomahub.liteflow.util.PathMatchUtil;
import org.noear.solon.core.util.ScanUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
@ -17,51 +20,55 @@ public class PathsUtils {
public static Collection<String> resolvePaths(String pathExpr) {
List<String> paths = new ArrayList<>();
if(!FileUtil.isAbsolutePath(pathExpr)) {
if (pathExpr.contains("/*") == false) { // 说明没有*
paths.add(pathExpr);
return paths;
}
if (pathExpr.contains("/*") == false) { // 说明没有*
paths.add(pathExpr);
return paths;
// 确定目录
int dirIdx = pathExpr.indexOf("/*");
String dir = pathExpr.substring(0, dirIdx);
// 确定后缀
int sufIdx = pathExpr.lastIndexOf(".");
String suf = null;
if (sufIdx > 0) {
suf = pathExpr.substring(sufIdx);
if (suf.contains("*")) {
sufIdx = -1;
suf = null;
}
}
int sufIdx2 = sufIdx;
String suf2 = suf;
// 匹配表达式
String expr = pathExpr.replaceAll("/\\*\\.", "/[^\\.]*\\.");
expr = expr.replaceAll("/\\*\\*/", "(/[^/]*)*/");
Pattern pattern = Pattern.compile(expr);
List<String> finalPaths = paths;
ScanUtil.scan(dir, n -> {
// 进行后缀过滤相对比较快
if (sufIdx2 > 0) {
return n.endsWith(suf2);
}
else {
return true;
}
}).forEach(uri -> {
// 再进行表达式过滤
if (pattern.matcher(uri).find()) {
finalPaths.add(uri);
}
});
} else {
String[] pathExprs = pathExpr.split(",");
paths = PathMatchUtil.searchAbsolutePath(Arrays.asList(pathExprs));
}
// 确定目录
int dirIdx = pathExpr.indexOf("/*");
String dir = pathExpr.substring(0, dirIdx);
// 确定后缀
int sufIdx = pathExpr.lastIndexOf(".");
String suf = null;
if (sufIdx > 0) {
suf = pathExpr.substring(sufIdx);
if (suf.contains("*")) {
sufIdx = -1;
suf = null;
}
}
int sufIdx2 = sufIdx;
String suf2 = suf;
// 匹配表达式
String expr = pathExpr.replaceAll("/\\*\\.", "/[^\\.]*\\.");
expr = expr.replaceAll("/\\*\\*/", "(/[^/]*)*/");
Pattern pattern = Pattern.compile(expr);
ScanUtil.scan(dir, n -> {
// 进行后缀过滤相对比较快
if (sufIdx2 > 0) {
return n.endsWith(suf2);
}
else {
return true;
}
}).forEach(uri -> {
// 再进行表达式过滤
if (pattern.matcher(uri).find()) {
paths.add(uri);
}
});
return paths;
}

View File

@ -10,6 +10,7 @@ import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.exception.ConfigErrorException;
import com.yomahub.liteflow.spi.PathContentParser;
import com.yomahub.liteflow.util.PathMatchUtil;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
@ -26,7 +27,8 @@ public class SpringPathContentParser implements PathContentParser {
@Override
public List<String> parseContent(List<String> pathList) throws Exception {
List<Resource> allResource = getResources(pathList);
List<String> absolutePathList = PathMatchUtil.searchAbsolutePath(pathList);
List<Resource> allResource = getResources(absolutePathList);
// 转换成内容List
List<String> contentList = new ArrayList<>();
@ -42,7 +44,8 @@ public class SpringPathContentParser implements PathContentParser {
@Override
public List<String> getFileAbsolutePath(List<String> pathList) throws Exception {
List<Resource> allResource = getResources(pathList);
List<String> absolutePathList = PathMatchUtil.searchAbsolutePath(pathList);
List<Resource> allResource = getResources(absolutePathList);
return StreamUtil.of(allResource)
// 过滤非 file 类型 Resource

View File

@ -1 +1,2 @@
liteflow.rule-source=/usr/local/flow.el.xml
liteflow.rule-source=/usr/local/flow.el.xml
#liteflow.rule-source=/usr/**/*.xml

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<chain name="chain1">
WHEN(a,b,c);

View File

@ -1 +1,2 @@
liteflow.rule-source=/usr/local/flow.el.xml
liteflow.rule-source=/usr/local/flow.el.xml
#liteflow.rule-source=/usr/**/*.xml

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<chain name="chain1">
WHEN(a,b,c);

View File

@ -23,6 +23,7 @@ public class AbsoluteConfigPathTest extends BaseTest {
public static void init() {
LiteflowConfig config = new LiteflowConfig();
config.setRuleSource("/usr/local/flow2.xml");
// config.setRuleSource("/usr/**/*.xml");
flowExecutor = FlowExecutorHolder.loadInstance(config);
}

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<nodes>
<node id="a" class="com.yomahub.liteflow.test.absoluteConfigPath.cmp.ACmp"/>
<node id="b" class="com.yomahub.liteflow.test.absoluteConfigPath.cmp.BCmp"/>
<node id="c" class="com.yomahub.liteflow.test.absoluteConfigPath.cmp.CCmp"/>
</nodes>
<chain name="chain1">
WHEN(a,b,c);
</chain>

View File

@ -1 +1,2 @@
liteflow.rule-source=/usr/local/flow.el.xml
liteflow.rule-source=/usr/local/flow.el.xml
#liteflow.rule-source=/usr/**/*.xml

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<chain name="chain1">
WHEN(a,b,c);

View File

@ -38,6 +38,22 @@ public class MonitorFileELSpringbootTest extends BaseTest {
Assertions.assertEquals("a==>c==>b", response.getExecuteStepStr());
}
/**
* 对绝对路径模糊匹配功能的测试
*/
@Test
public void testMonitorAbsolutePath() throws Exception {
String absolutePath = "/your/path/dir";
FileUtil.writeString("<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow><chain name=\"chain1\">THEN(a, b, c);</chain></flow>", new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
String content = FileUtil.readUtf8String(absolutePath);
String newContent = content.replace("THEN(a, b, c);", "THEN(a, c, b);");
Thread.sleep(1000);
FileUtil.writeString(newContent, new File(absolutePath), CharsetUtil.CHARSET_UTF_8);
Thread.sleep(3000);
LiteflowResponse response = flowExecutor.execute2Resp("chain1", "arg");
Assertions.assertEquals("a==>c==>b", response.getExecuteStepStr());
}
/**
* 测试文件变更但是 EL 规则错误情况
* 输出 ERROR 日志异常信息但是不会停止监听线程当下一次变更正确后替换为新规则

View File

@ -1 +1,2 @@
liteflow.rule-source=/usr/local/flow.el.xml
liteflow.rule-source=/usr/local/flow.el.xml
#liteflow.rule-source=/usr/**/*.xml

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<chain name="chain1">
WHEN(a,b,c);

View File

@ -1,2 +1,3 @@
liteflow.rule-source=monitorFile/flow.el.xml
#liteflow.rule-source=/usr/**/*.xml
liteflow.enable-monitor-file=true

View File

@ -17,6 +17,10 @@
<property name="ruleSource" value="/usr/local/flow.el.xml"/>
</bean>
<!-- <bean id="liteflowConfig" class="com.yomahub.liteflow.property.LiteflowConfig">-->
<!-- <property name="ruleSource" value="/usr/**/*.xml"/>-->
<!-- </bean>-->
<bean id="flowExecutor" class="com.yomahub.liteflow.core.FlowExecutor">
<constructor-arg name="liteflowConfig" ref="liteflowConfig"/>
</bean>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.el.xml中-->
<!--这里只是内容,在这个测试用例中这个文件请移到/usr/local/flow.el.xml中,文件目录支持绝对路径的模糊匹配,也可以将此文件移入任意/usr/**/*.xml中-->
<flow>
<chain name="chain1">
WHEN(a,b,c);