mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-23 00:28:10 +08:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
@@ -18,10 +18,16 @@ public @interface LiteflowMethod {
|
||||
|
||||
/**
|
||||
* 节点ID,用于区分节点 默认为空 则按照Spring模式下BeanName为准。
|
||||
* @return
|
||||
* @return nodeId
|
||||
*/
|
||||
String nodeId() default "";
|
||||
|
||||
/**
|
||||
* 节点Name
|
||||
* @return nodeName
|
||||
*/
|
||||
String nodeName() default "";
|
||||
|
||||
/**
|
||||
* CMP类型定义
|
||||
* @return AnnotationNodeTypeEnum
|
||||
|
||||
@@ -126,7 +126,7 @@ public abstract class NodeComponent {
|
||||
|
||||
stopWatch.stop();
|
||||
final long timeSpent = stopWatch.getTotalTimeMillis();
|
||||
LOG.debug("component[{}] finished in {} milliseconds", this.getDisplayName(), timeSpent);
|
||||
LOG.info("component[{}] finished in {} milliseconds", this.getDisplayName(), timeSpent);
|
||||
|
||||
// 往CmpStep中放入时间消耗信息
|
||||
cmpStep.setTimeSpent(timeSpent);
|
||||
|
||||
@@ -10,8 +10,10 @@ import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||
import com.yomahub.liteflow.exception.ComponentMethodDefineErrorException;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.exception.ProxyException;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.spi.holder.LiteflowComponentSupportHolder;
|
||||
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
||||
import com.yomahub.liteflow.util.SerialsUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
@@ -27,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -93,8 +96,23 @@ public class ComponentProxy {
|
||||
boolean legal = classes.size() == 1;
|
||||
if (!legal) {
|
||||
throw new LiteFlowException("The cmpClass of the same nodeId must be the same,you declared nodeId:"
|
||||
+ activeNodeId + ",cmpClass:" + classes);
|
||||
+ activeNodeId + ",cmpClass:" + clazz);
|
||||
}
|
||||
|
||||
|
||||
String activeNodeName;
|
||||
if (isMethodCreate){
|
||||
// 获取process上的LiteflowMethod
|
||||
LiteflowMethod mainliteflowMethod = methodList.stream().filter(liteflowMethod -> liteflowMethod.value().isMainMethod()).findFirst().orElse(null);
|
||||
if (mainliteflowMethod == null){
|
||||
String errMsg = StrUtil.format("you have not defined @LiteFlowMethod on the processXXX method in class {}", clazz.getName());
|
||||
throw new LiteFlowException(errMsg);
|
||||
}
|
||||
activeNodeName = mainliteflowMethod.nodeName();
|
||||
}else{
|
||||
activeNodeName = LiteflowComponentSupportHolder.loadLiteflowComponentSupport().getCmpName(bean);
|
||||
}
|
||||
|
||||
// 当前节点实际LiteflowRetry注解
|
||||
AtomicReference<LiteflowRetry> liteflowRetryAtomicReference = new AtomicReference<>(null);
|
||||
// 相同nodeId只能有一个LiteflowRetry定义方法,且必须再Process方法上
|
||||
@@ -150,10 +168,12 @@ public class ComponentProxy {
|
||||
NodeComponent nodeComponent = (NodeComponent) instance;
|
||||
// 重设nodeId
|
||||
nodeComponent.setNodeId(activeNodeId);
|
||||
// 重设nodeName
|
||||
nodeComponent.setName(activeNodeName);
|
||||
return nodeComponent;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new LiteFlowException(e);
|
||||
throw new ProxyException(e);
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -2,14 +2,19 @@ package com.yomahub.liteflow.enums;
|
||||
|
||||
public enum LiteFlowMethodEnum {
|
||||
|
||||
PROCESS("process", true), PROCESS_SWITCH("processSwitch", true), PROCESS_IF("processIf", true),
|
||||
PROCESS_FOR("processFor", true), PROCESS_WHILE("processWhile", true), PROCESS_BREAK("processBreak", true),
|
||||
PROCESS("process", true),
|
||||
PROCESS_SWITCH("processSwitch", true),
|
||||
PROCESS_IF("processIf", true),
|
||||
PROCESS_FOR("processFor", true),
|
||||
PROCESS_WHILE("processWhile", true),
|
||||
PROCESS_BREAK("processBreak", true),
|
||||
|
||||
PROCESS_ITERATOR("processIterator", true),
|
||||
|
||||
IS_ACCESS("isAccess", false),
|
||||
|
||||
IS_END("isEnd", false), IS_CONTINUE_ON_ERROR("isContinueOnError", false),
|
||||
IS_END("isEnd", false),
|
||||
IS_CONTINUE_ON_ERROR("isContinueOnError", false),
|
||||
|
||||
GET_NODE_EXECUTOR_CLASS("getNodeExecutorClass", false),
|
||||
|
||||
@@ -19,7 +24,10 @@ public enum LiteFlowMethodEnum {
|
||||
|
||||
BEFORE_PROCESS("beforeProcess", false),
|
||||
|
||||
AFTER_PROCESS("afterProcess", false);
|
||||
AFTER_PROCESS("afterProcess", false),
|
||||
|
||||
GET_DISPLAY_NAME("getDisplayName", false)
|
||||
;
|
||||
|
||||
private String methodName;
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
package com.yomahub.liteflow.exception;
|
||||
|
||||
/**
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ProxyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 异常信息 */
|
||||
private String message;
|
||||
|
||||
public ProxyException(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ProxyException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class FlowBus {
|
||||
}
|
||||
|
||||
nodeMap.put(nodeId,
|
||||
new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, type, null, nodeId)));
|
||||
new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, type, nodeComponent.getName(), nodeId)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.yomahub.liteflow.flow.element.condition;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.enums.ConditionTypeEnum;
|
||||
import com.yomahub.liteflow.exception.AndOrConditionException;
|
||||
@@ -11,7 +10,9 @@ import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.slot.DataBus;
|
||||
import com.yomahub.liteflow.slot.Slot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class AndOrCondition extends Condition {
|
||||
|
||||
@@ -23,21 +24,10 @@ public class AndOrCondition extends Condition {
|
||||
public void executeCondition(Integer slotIndex) throws Exception {
|
||||
List<Executable> itemList = this.getItem();
|
||||
|
||||
|
||||
if (CollUtil.isEmpty(itemList)){
|
||||
throw new AndOrConditionException("boolean item list is null");
|
||||
}
|
||||
|
||||
boolean[] booleanArray = new boolean[itemList.size()];
|
||||
|
||||
for (int i = 0; i < itemList.size(); i++) {
|
||||
Executable item = itemList.get(i);
|
||||
item.setCurrChainId(this.getCurrChainId());
|
||||
item.execute(slotIndex);
|
||||
booleanArray[i] = item.getItemResultMetaValue(slotIndex);
|
||||
LOG.info("the result of boolean component [{}] is [{}]", item.getId(), booleanArray[i]);
|
||||
}
|
||||
|
||||
BooleanConditionTypeEnum booleanConditionType = this.getBooleanConditionType();
|
||||
|
||||
Slot slot = DataBus.getSlot(slotIndex);
|
||||
@@ -45,16 +35,37 @@ public class AndOrCondition extends Condition {
|
||||
String resultKey = StrUtil.format("{}_{}",this.getClass().getName(),this.hashCode());
|
||||
switch (booleanConditionType) {
|
||||
case AND:
|
||||
slot.setAndOrResult(resultKey, BooleanUtil.and(booleanArray));
|
||||
slot.setAndOrResult(resultKey, itemList.stream().allMatch(new AndOrConditionPredicate(slotIndex)));
|
||||
break;
|
||||
case OR:
|
||||
slot.setAndOrResult(resultKey, BooleanUtil.or(booleanArray));
|
||||
slot.setAndOrResult(resultKey, itemList.stream().anyMatch(new AndOrConditionPredicate(slotIndex)));
|
||||
break;
|
||||
default:
|
||||
throw new AndOrConditionException("condition type must be 'AND' or 'OR'");
|
||||
}
|
||||
}
|
||||
|
||||
private class AndOrConditionPredicate implements Predicate<Executable> {
|
||||
|
||||
private final Integer slotIndex;
|
||||
|
||||
public AndOrConditionPredicate(Integer slotIndex) {
|
||||
this.slotIndex = slotIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Executable condition) {
|
||||
try {
|
||||
condition.setCurrChainId(getCurrChainId());
|
||||
condition.execute(slotIndex);
|
||||
return condition.getItemResultMetaValue(slotIndex);
|
||||
} catch (Exception e) {
|
||||
throw new AndOrConditionException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -63,13 +63,21 @@ public class MonitorFile {
|
||||
@Override
|
||||
public void onFileChange(File file) {
|
||||
LOG.info("file modify,filePath={}", file.getAbsolutePath());
|
||||
FlowExecutorHolder.loadInstance().reloadRule();
|
||||
this.reloadRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileDelete(File file) {
|
||||
LOG.info("file delete,filePath={}", file.getAbsolutePath());
|
||||
FlowExecutorHolder.loadInstance().reloadRule();
|
||||
this.reloadRule();
|
||||
}
|
||||
|
||||
private void reloadRule() {
|
||||
try {
|
||||
FlowExecutorHolder.loadInstance().reloadRule();
|
||||
} catch (Exception e) {
|
||||
LOG.error("reload rule error", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
// 创建文件变化监听器
|
||||
|
||||
@@ -140,6 +140,8 @@ public class ParserHelper {
|
||||
// 校验加载的 chainName 是否有重复的
|
||||
// TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = Optional.ofNullable(e.attributeValue(ID)).orElse(e.attributeValue(NAME));
|
||||
// 检查 chainName
|
||||
checkChainId(chainName, e.getText());
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
@@ -202,9 +204,11 @@ public class ParserHelper {
|
||||
JsonNode innerJsonObject = iterator.next();
|
||||
// 校验加载的 chainName 是否有重复的
|
||||
// TODO 这里是否有个问题,当混合格式加载的时候,2个同名的Chain在不同的文件里,就不行了
|
||||
String chainName = Optional.ofNullable(innerJsonObject.get(ID))
|
||||
.orElse(innerJsonObject.get(NAME))
|
||||
.textValue();
|
||||
JsonNode chainNameJsonNode = Optional.ofNullable(innerJsonObject.get(ID))
|
||||
.orElse(innerJsonObject.get(NAME));
|
||||
String chainName = Optional.ofNullable(chainNameJsonNode).map(JsonNode::textValue).orElse(null);
|
||||
// 检查 chainName
|
||||
checkChainId(chainName, innerJsonObject.toPrettyString());
|
||||
if (!chainNameSet.add(chainName)) {
|
||||
throw new ChainDuplicateException(String.format("[chain name duplicate] chainName=%s", chainName));
|
||||
}
|
||||
@@ -250,6 +254,17 @@ public class ParserHelper {
|
||||
chainELBuilder.setEL(el).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 chainId
|
||||
* @param chainId chainId
|
||||
* @param elData elData
|
||||
*/
|
||||
private static void checkChainId(String chainId, String elData) {
|
||||
if (StrUtil.isBlank(chainId)) {
|
||||
throw new ParseException("missing chain id in expression \r\n" + elData);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegexUtil {
|
||||
|
||||
// java 注释的正则表达式
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.yomahub.liteflow.script.proxy;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import com.yomahub.liteflow.exception.LiteFlowException;
|
||||
import com.yomahub.liteflow.exception.ProxyException;
|
||||
import com.yomahub.liteflow.exception.ScriptBeanMethodInvokeException;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
@@ -10,8 +11,18 @@ import com.yomahub.liteflow.script.annotation.ScriptBean;
|
||||
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
|
||||
import com.yomahub.liteflow.util.SerialsUtil;
|
||||
import net.bytebuddy.ByteBuddy;
|
||||
import net.bytebuddy.description.method.ParameterDescription;
|
||||
import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import net.bytebuddy.implementation.InvocationHandlerAdapter;
|
||||
import net.bytebuddy.implementation.MethodCall;
|
||||
import net.bytebuddy.implementation.MethodDelegation;
|
||||
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
@@ -56,19 +67,18 @@ public class ScriptBeanProxy {
|
||||
}
|
||||
|
||||
try {
|
||||
return new ByteBuddy().subclass(orignalClass)
|
||||
.name(StrUtil.format("{}.ByteBuddy${}", ClassUtil.getPackage(orignalClass),
|
||||
SerialsUtil.generateShortUUID()))
|
||||
Class<?> c = new ByteBuddy().subclass(orignalClass).name(StrUtil.format("{}.ByteBuddy${}", ClassUtil.getPackage(orignalClass),SerialsUtil.generateShortUUID()))
|
||||
.method(ElementMatchers.any())
|
||||
.intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean, methodNameList)))
|
||||
.annotateType(orignalClass.getAnnotations())
|
||||
.make()
|
||||
.load(ScriptBeanProxy.class.getClassLoader())
|
||||
.getLoaded()
|
||||
.newInstance();
|
||||
.getLoaded();
|
||||
|
||||
return ReflectUtil.newInstanceIfPossible(c);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new LiteFlowException(e);
|
||||
throw new ProxyException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.yomahub.liteflow.spi;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 环境容器SPI接口
|
||||
*
|
||||
@@ -8,18 +10,27 @@ package com.yomahub.liteflow.spi;
|
||||
*/
|
||||
public interface ContextAware extends SpiPriority {
|
||||
|
||||
<T> T getBean(String name);
|
||||
<T> T getBean(String name);
|
||||
|
||||
<T> T getBean(Class<T> clazz);
|
||||
<T> T getBean(Class<T> clazz);
|
||||
|
||||
<T> T registerBean(String beanName, Class<T> clazz);
|
||||
<T> T registerBean(String beanName, Class<T> clazz);
|
||||
|
||||
<T> T registerBean(Class<T> clazz);
|
||||
<T> T registerBean(Class<T> clazz);
|
||||
|
||||
<T> T registerBean(String beanName, Object bean);
|
||||
<T> T registerBean(String beanName, Object bean);
|
||||
|
||||
<T> T registerOrGet(String beanName, Class<T> clazz);
|
||||
<T> T registerOrGet(String beanName, Class<T> clazz);
|
||||
|
||||
boolean hasBean(String beanName);
|
||||
/**
|
||||
* 获取指定类型对应的所有Bean,包括子类
|
||||
*
|
||||
* @param <T> Bean类型
|
||||
* @param type 类、接口,null表示获取所有bean
|
||||
* @return 类型对应的bean,key是bean注册的name,value是Bean
|
||||
*/
|
||||
<T> Map<String, T> getBeansOfType(Class<T> type);
|
||||
|
||||
boolean hasBean(String beanName);
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ import com.yomahub.liteflow.core.NodeComponent;
|
||||
*/
|
||||
public interface LiteflowComponentSupport extends SpiPriority {
|
||||
|
||||
String getCmpName(NodeComponent nodeComponent);
|
||||
String getCmpName(Object nodeComponent);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.yomahub.liteflow.spi.local;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.yomahub.liteflow.spi.ContextAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 非Spring环境容器实现 其实非Spring没有环境容器,所以这是个空实现
|
||||
*
|
||||
@@ -11,44 +13,49 @@ import com.yomahub.liteflow.spi.ContextAware;
|
||||
*/
|
||||
public class LocalContextAware implements ContextAware {
|
||||
|
||||
@Override
|
||||
public <T> T getBean(String name) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public <T> T getBean(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getBean(Class<T> clazz) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public <T> T getBean(Class<T> clazz) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T registerBean(String beanName, Class<T> clazz) {
|
||||
return ReflectUtil.newInstance(clazz);
|
||||
}
|
||||
@Override
|
||||
public <T> T registerBean(String beanName, Class<T> clazz) {
|
||||
return ReflectUtil.newInstance(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T registerBean(Class<T> clazz) {
|
||||
return registerBean(null, clazz);
|
||||
}
|
||||
@Override
|
||||
public <T> T registerBean(Class<T> clazz) {
|
||||
return registerBean(null, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T registerBean(String beanName, Object bean) {
|
||||
return (T) bean;
|
||||
}
|
||||
@Override
|
||||
public <T> T registerBean(String beanName, Object bean) {
|
||||
return (T) bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T registerOrGet(String beanName, Class<T> clazz) {
|
||||
return registerBean(beanName, clazz);
|
||||
}
|
||||
@Override
|
||||
public <T> T registerOrGet(String beanName, Class<T> clazz) {
|
||||
return registerBean(beanName, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasBean(String beanName) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public <T> Map<String, T> getBeansOfType(Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 2;
|
||||
}
|
||||
@Override
|
||||
public boolean hasBean(String beanName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.yomahub.liteflow.spi.LiteflowComponentSupport;
|
||||
public class LocalLiteflowComponentSupport implements LiteflowComponentSupport {
|
||||
|
||||
@Override
|
||||
public String getCmpName(NodeComponent nodeComponent) {
|
||||
public String getCmpName(Object nodeComponent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user