feature #I54VBS 从设计上改善NodeComponent,使之变成声明式的组件

This commit is contained in:
bryan31 2022-05-16 11:58:18 +08:00
parent 3e6547b1e8
commit 935506a388
339 changed files with 8359 additions and 16 deletions

View File

@ -61,5 +61,9 @@
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,10 @@
package com.yomahub.liteflow.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LiteflowCmpDefine {
}

View File

@ -0,0 +1,10 @@
package com.yomahub.liteflow.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LiteflowCondCmpDefine {
}

View File

@ -0,0 +1,14 @@
package com.yomahub.liteflow.annotation;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LiteflowMethod {
LiteFlowMethodEnum value();
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.yomahub.liteflow.annotation.AliasFor;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;

View File

@ -64,6 +64,12 @@ public class LiteFlowNodeBuilder {
return this;
}
public LiteFlowNodeBuilder setClazz(Class<?> clazz){
assert clazz != null;
setClazz(clazz.getName());
return this;
}
// 设置节点组件的class
public LiteFlowNodeBuilder setNodeComponentClazz(Class<? extends NodeComponent> nodeComponentClass) {
assert nodeComponentClass != null;

View File

@ -35,7 +35,7 @@ import java.util.Map;
*/
public abstract class NodeComponent{
private static final Logger LOG = LoggerFactory.getLogger(NodeComponent.class);
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final TransmittableThreadLocal<Integer> slotIndexTL = new TransmittableThreadLocal<>();

View File

@ -0,0 +1,129 @@
package com.yomahub.liteflow.core.proxy;
import cn.hutool.core.util.*;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.exception.ComponentMethodDefineErrorException;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import com.yomahub.liteflow.util.SerialsUtil;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.InvocationHandlerAdapter;
import net.bytebuddy.matcher.ElementMatchers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 声明式组件的代理核心生成类
* @author Bryan.Zhang
* @since 2.6.14
*/
public class ComponentProxy {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final String nodeId;
private final Object bean;
private final Class<?> clazz;
public ComponentProxy(String nodeId, Object bean, Class<?> clazz) {
this.nodeId = nodeId;
this.bean = bean;
this.clazz = clazz;
}
public Object getProxy() throws Exception{
//这里要判断bean是否是spring代理过的bean如果是代理过的bean需要取到原class对象
Class<?> beanClazz;
if (LiteFlowProxyUtil.isCglibProxyClass(bean.getClass())){
beanClazz = LiteFlowProxyUtil.getUserClass(bean.getClass());
}else{
beanClazz = bean.getClass();
}
//得到当前bean里所覆盖的组件方法(一定是被@LiteFlowMethod修饰的)自己定义的不算
List<String> methodStrList = Arrays.stream(beanClazz.getDeclaredMethods()).filter(
m -> m.getAnnotation(LiteflowMethod.class) != null
).map(m -> {
LiteflowMethod liteflowMethod = m.getAnnotation(LiteflowMethod.class);
return liteflowMethod.value().getMethodName();
}).collect(Collectors.toList());
//创建对象
//这里package进行了重设放到了被代理对象的所在目录
//生成的对象也加了上被代理对象拥有的注解
//被拦截的对象也根据被代理对象根据@LiteFlowMethod所标注的进行了动态判断
return new ByteBuddy().subclass(clazz)
.name(StrUtil.format("{}.ByteBuddy${}${}",
ClassUtil.getPackage(bean.getClass()),
nodeId,
SerialsUtil.generateShortUUID()))
.method(ElementMatchers.namedOneOf(methodStrList.toArray(new String[]{})))
.intercept(InvocationHandlerAdapter.of(new AopInvocationHandler(bean)))
.annotateType(bean.getClass().getAnnotations())
.make()
.load(ComponentProxy.class.getClassLoader())
.getLoaded()
.newInstance();
}
public class AopInvocationHandler implements InvocationHandler {
private final Object bean;
public AopInvocationHandler(Object bean) {
this.bean = bean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//这里做了2件事情
//先是从普通的bean里过滤出含有@LiteFlowMethod这个标注的方法
//然后进行转换成LiteFlowMethodBean对象List,形成<methodName,Method>键值对的对象
List<LiteFlowMethodBean> liteFlowMethodBeanList = Arrays.stream(ReflectUtil.getMethods(bean.getClass())).filter(m -> {
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
return ObjectUtil.isNotNull(liteFlowMethod);
}).map(m -> {
LiteflowMethod liteFlowMethod = m.getAnnotation(LiteflowMethod.class);
return new LiteFlowMethodBean(liteFlowMethod.value().getMethodName(), m);
}).collect(Collectors.toList());
//获取当前调用方法是否在被代理的对象方法里面(根据@LiteFlowMethod这个标注去判断)
//如果在里面则返回那个LiteFlowMethodBean不在则返回null
LiteFlowMethodBean liteFlowMethodBean = liteFlowMethodBeanList.stream().filter(
liteFlowMethodBean1 -> liteFlowMethodBean1.getMethod().getName().equals(method.getName())
).findFirst().orElse(null);
//如果被代理的对象里有此标注标的方法则调用此被代理的对象里的方法如果没有则调用父类里的方法
if (liteFlowMethodBean != null){
//进行检查检查被代理的bean里是否有且仅有NodeComponent这个类型的参数
boolean checkFlag = liteFlowMethodBean.getMethod().getParameterTypes().length == 1
&& Arrays.asList(liteFlowMethodBean.getMethod().getParameterTypes()).contains(NodeComponent.class);
if (!checkFlag){
String errMsg = StrUtil.format("Method[{}.{}] must have NodeComponent parameter(and only one parameter)", bean.getClass().getName(), liteFlowMethodBean.getMethod().getName());
LOG.error(errMsg);
throw new ComponentMethodDefineErrorException(errMsg);
}
try{
return liteFlowMethodBean.getMethod().invoke(bean, proxy);
}catch (Exception e){
InvocationTargetException targetEx = (InvocationTargetException)e;
throw targetEx.getTargetException();
}
}else{
//理论上来说这句应该执行不到因为前面在设置拦截对象类型的时候已经根据当前bean所覆盖的方法进行了动态判断
return method.invoke(proxy, args);
}
}
}
}

View File

@ -0,0 +1,31 @@
package com.yomahub.liteflow.core.proxy;
import java.lang.reflect.Method;
public class LiteFlowMethodBean {
private String methodName;
private Method method;
public LiteFlowMethodBean(String methodName, Method method) {
this.methodName = methodName;
this.method = method;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}

View File

@ -0,0 +1,26 @@
package com.yomahub.liteflow.enums;
public enum LiteFlowMethodEnum {
PROCESS("process"),
PROCESS_COND("processCond"),
IS_ACCESS("isAccess"),
IS_END("isEnd"),
IS_CONTINUE_ON_ERROR("isContinueOnError"),
GET_NODE_EXECUTOR_CLASS("getNodeExecutorClass");
private String methodName;
LiteFlowMethodEnum(String methodName){
this.methodName = methodName;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
}

View File

@ -0,0 +1,22 @@
package com.yomahub.liteflow.exception;
public class ComponentMethodDefineErrorException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** 异常信息 */
private String message;
public ComponentMethodDefineErrorException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,22 @@
package com.yomahub.liteflow.exception;
public class ComponentProxyErrorException extends RuntimeException {
private static final long serialVersionUID = 1L;
/** 异常信息 */
private String message;
public ComponentProxyErrorException(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -28,8 +28,11 @@ import com.yomahub.liteflow.parser.LocalYmlFlowParser;
import com.yomahub.liteflow.script.ScriptExecutor;
import com.yomahub.liteflow.script.ScriptExecutorFactory;
import com.yomahub.liteflow.script.exception.ScriptSpiException;
import com.yomahub.liteflow.spi.ContextAware;
import com.yomahub.liteflow.spi.holder.ContextAwareHolder;
import com.yomahub.liteflow.spi.local.LocalContextAware;
import com.yomahub.liteflow.util.CopyOnWriteHashMap;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -82,8 +85,13 @@ public class FlowBus {
nodeMap.put(nodeId, new Node(ComponentInitializer.loadInstance().initComponent(nodeComponent, NodeTypeEnum.COMMON, null, nodeId)));
}
public static void addCommonNode(String nodeId, String name, String cmpClazzStr) throws Exception {
Class<NodeComponent> cmpClazz = (Class<NodeComponent>) Class.forName(cmpClazzStr);
public static void addCommonNode(String nodeId, String name, String cmpClazzStr){
Class<?> cmpClazz;
try{
cmpClazz = Class.forName(cmpClazzStr);
}catch (Exception e){
throw new ComponentCannotRegisterException(e.getMessage());
}
addNode(nodeId, name, NodeTypeEnum.COMMON, cmpClazz, null);
}
@ -99,18 +107,36 @@ public class FlowBus {
addNode(nodeId, name, NodeTypeEnum.COND_SCRIPT, ScriptCondComponent.class, script);
}
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<? extends NodeComponent> cmpClazz, String script) {
private static void addNode(String nodeId, String name, NodeTypeEnum type, Class<?> cmpClazz, String script) {
try {
//以node方式配置本质上是为了适配无spring的环境如果有spring环境其实不用这么配置
//这里的逻辑是判断是否能从spring上下文中取到如果没有spring则就是new instance了
//如果是script类型的节点因为class只有一个所以也不能注册进spring上下文注册的时候需要new Instance
//判断此类是否是声明式的组件如果是声明式的组件就用动态代理生成实例
//如果不是声明式的就用传统的方式进行判断
NodeComponent cmpInstance = null;
if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.COND_SCRIPT).contains(type)){
cmpInstance = ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz);
}
if (LiteFlowProxyUtil.isMarkedCmp(cmpClazz)){
//这里的逻辑要仔细看下
//如果是spring体系把原始的类往spring上下文中进行注册那么会走到ComponentScanner中
//由于ComponentScanner中已经对原始类进行了动态代理出来的对象已经变成了动态代理类所以这时候的bean已经是NodeComponent的子类了
//所以spring体系下无需再对这个bean做二次代理
//但是在非spring体系下这个bean依旧是原来那个bean所以需要对这个bean做一次代理
//这里用ContextAware的spi机制来判断是否spring体系
ContextAware contextAware = ContextAwareHolder.loadContextAware();
Object bean = ContextAwareHolder.loadContextAware().registerBean(nodeId, cmpClazz);
if (LocalContextAware.class.isAssignableFrom(contextAware.getClass())){
cmpInstance = LiteFlowProxyUtil.proxy2NodeComponent(bean, nodeId);
}else {
cmpInstance = (NodeComponent) bean;
}
}else{
//以node方式配置本质上是为了适配无spring的环境如果有spring环境其实不用这么配置
//这里的逻辑是判断是否能从spring上下文中取到如果没有spring则就是new instance了
//如果是script类型的节点因为class只有一个所以也不能注册进spring上下文注册的时候需要new Instance
if (!CollectionUtil.newArrayList(NodeTypeEnum.SCRIPT, NodeTypeEnum.COND_SCRIPT).contains(type)){
cmpInstance = (NodeComponent) ContextAwareHolder.loadContextAware().registerOrGet(nodeId, cmpClazz);
}
if (ObjectUtil.isNull(cmpInstance)) {
cmpInstance = cmpClazz.newInstance();
if (ObjectUtil.isNull(cmpInstance)) {
cmpInstance = (NodeComponent) cmpClazz.newInstance();
}
}
//进行初始化

View File

@ -16,5 +16,7 @@ public interface ContextAware extends SpiPriority {
<T> T registerBean(Class<T> clazz);
<T> T registerBean(String beanName, Object bean);
<T> T registerOrGet(String beanName, Class<T> clazz);
}

View File

@ -30,6 +30,11 @@ public class LocalContextAware implements ContextAware {
return registerBean(null, clazz);
}
@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);

View File

@ -0,0 +1,102 @@
package com.yomahub.liteflow.util;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.core.NodeCondComponent;
import com.yomahub.liteflow.core.proxy.ComponentProxy;
import com.yomahub.liteflow.exception.ComponentProxyErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
/**
* 组件代理类通用方法
* 主要用于声明式组件
* @author Bryan.Zhang
* @since 2.6.14
*/
public class LiteFlowProxyUtil {
private static final Logger LOG = LoggerFactory.getLogger(LiteFlowProxyUtil.class);
//判断一个bean是否是解耦式组件
public static boolean isMarkedCmp(Class<?> clazz){
//判断bean是否标记了@LiteflowCmpDefine或者@LiteflowCondCmpDefine这2个标注之一
boolean flag1 = clazz.getAnnotation(LiteflowCmpDefine.class) != null
|| clazz.getAnnotation(LiteflowCondCmpDefine.class) != null;
if (!flag1){
return false;
}
//看超类是否是NodeComponent和NodeCondComponent中的一个如果不是则说明满足条件是的话也不满足
boolean flag2 = !ListUtil.toList(NodeComponent.class, NodeCondComponent.class).contains(clazz.getSuperclass());
if (!flag2){
return false;
}
//查看bean里的method是否有方法标记了@LiteflowMethod标注
//这里的bean有可能是cglib加强过的class所以要先进行个判断
Class<?> targetClass;
if (isCglibProxyClass(clazz)){
targetClass = getUserClass(clazz);
}else{
targetClass = clazz;
}
boolean flag3 = Arrays.stream(targetClass.getMethods()).anyMatch(
method -> method.getAnnotation(LiteflowMethod.class) != null
);
return flag3;
}
//对一个满足声明式的bean进行代理
public static NodeComponent proxy2NodeComponent(Object bean, String nodeId){
try{
LiteflowCmpDefine liteflowCmpDefine = bean.getClass().getAnnotation(LiteflowCmpDefine.class);
LiteflowCondCmpDefine liteflowCondCmpDefine = bean.getClass().getAnnotation(LiteflowCondCmpDefine.class);
ComponentProxy proxy;
if (ObjectUtil.isNotNull(liteflowCmpDefine)){
proxy = new ComponentProxy(nodeId, bean, NodeComponent.class);
return (NodeComponent) proxy.getProxy();
}
if (ObjectUtil.isNotNull(liteflowCondCmpDefine)){
proxy = new ComponentProxy(nodeId, bean, NodeCondComponent.class);
return (NodeCondComponent) proxy.getProxy();
}
throw new RuntimeException();
}catch (Exception e){
String errMsg = StrUtil.format("Error while proxying bean[{}]",bean.getClass().getName());
LOG.error(errMsg, e);
throw new ComponentProxyErrorException(errMsg);
}
}
public static boolean isCglibProxyClass(Class<?> clazz) {
return (clazz != null && isCglibProxyClassName(clazz.getName()));
}
public static Class<?> getUserClass(Class<?> clazz) {
if (clazz.getName().contains("$$")) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && superclass != Object.class) {
return superclass;
}
}
return clazz;
}
private static boolean isCglibProxyClassName(String className) {
return (className != null && className.contains("$$"));
}
}

View File

@ -0,0 +1,192 @@
package com.yomahub.liteflow.util;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
public class SerialsUtil {
public static int serialInt = 1;
private static final DecimalFormat format8 = new DecimalFormat("00000000");
private static final DecimalFormat format12 = new DecimalFormat("000000000000");
private static final BigInteger divisor;
private static final BigInteger divisor12;
static {
divisor = BigInteger.valueOf(19999999L).multiply(BigInteger.valueOf(5));
divisor12 = BigInteger.valueOf(190000000097L).multiply(BigInteger.valueOf(5));
}
public static String genSerialNo(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String strNow = sdf.format(new Date());
// 生成3位随机数
Random random = new Random();
int intRandom = random.nextInt(999);
String strRandom = String.valueOf(intRandom);
int len = strRandom.length();
for (int i = 0; i < (3-len); i++) {
strRandom = "0" + strRandom;
}
String serialStr = SerialsUtil.nextSerial();
return (strNow + strRandom + serialStr) ;
}
public static synchronized String nextSerial(){
int serial = serialInt++;
if (serial > 999){
serialInt = 1;
serial=1;
}
String serialStr = serial + "";
int len = serialStr.length();
for (int i = 0; i < (3-len); i++) {
serialStr = "0" + serialStr;
}
return serialStr;
}
/**
* 生成一个12位随机数
*
* @param seed 种子
* @return
*/
public static String randomNum12(long seed) {
// 被除数
BigInteger dividend = BigDecimal.valueOf(seed).pow(5).toBigInteger();
return format12.format(dividend.remainder(divisor12));
}
/**
* 生成一个8位随机数
*
* @param seed 种子
* @return
*/
public static String randomNum8(long seed) {
// 被除数
BigInteger dividend = BigDecimal.valueOf(seed).pow(5).toBigInteger();
return format8.format(dividend.remainder(divisor));
}
/*
* 10进制转32进制(去除0,O,1,I)
*/
public static String from10To32(String numStr, int size){
long to=32;
long num = Long.parseLong(numStr);
String jg="";
while(num!=0){
switch (new Long(num%to).intValue()) {
case 0:jg="B"+jg;break; case 1:jg="R"+jg;break; case 2:jg="6"+jg;break; case 3:jg="U"+jg;break;
case 4:jg="M"+jg;break; case 5:jg="E"+jg;break; case 6:jg="H"+jg;break; case 7:jg="C"+jg;break;
case 8:jg="G"+jg;break; case 9:jg="Q"+jg;break; case 10:jg="A"+jg;break; case 11:jg="8"+jg;break;
case 12:jg="3"+jg;break; case 13:jg="S"+jg;break; case 14:jg="J"+jg;break; case 15:jg="Y"+jg;break;
case 16:jg="7"+jg;break; case 17:jg="5"+jg;break; case 18:jg="W"+jg;break; case 19:jg="9"+jg;break;
case 20:jg="F"+jg;break; case 21:jg="T"+jg;break; case 22:jg="D"+jg;break; case 23:jg="2"+jg;break;
case 24:jg="P"+jg;break; case 25:jg="Z"+jg;break; case 26:jg="N"+jg;break; case 27:jg="K"+jg;break;
case 28:jg="V"+jg;break; case 29:jg="X"+jg;break; case 30:jg="L"+jg;break; case 31:jg="4"+jg;break;
default: jg=String.valueOf(num%to)+jg;break;
}
num=num/to;
}
if (jg.length() < size){
int loop = size - jg.length();
for (int i = 0; i < loop; i++){
jg = "2" + jg;
}
}
return jg;
}
/*
* 10进制转32进制(去除0,O,1,I)
*/
public static String from10To24(String numStr, int size){
long to=24;
long num = Long.parseLong(numStr);
String jg="";
while(num!=0){
switch (new Long(num%to).intValue()) {
case 0:jg="B"+jg;break;
case 1:jg="R"+jg;break;
case 2:jg="U"+jg;break;
case 3:jg="M"+jg;break;
case 4:jg="E"+jg;break;
case 5:jg="H"+jg;break;
case 6:jg="C"+jg;break;
case 7:jg="G"+jg;break;
case 8:jg="Q"+jg;break;
case 9:jg="A"+jg;break;
case 10:jg="S"+jg;break;
case 11:jg="J"+jg;break;
case 12:jg="Y"+jg;break;
case 13:jg="W"+jg;break;
case 14:jg="F"+jg;break;
case 15:jg="T"+jg;break;
case 16:jg="D"+jg;break;
case 17:jg="P"+jg;break;
case 18:jg="Z"+jg;break;
case 19:jg="N"+jg;break;
case 20:jg="K"+jg;break;
case 21:jg="V"+jg;break;
case 22:jg="X"+jg;break;
case 23:jg="L"+jg;break;
default: jg=String.valueOf(num%to)+jg;break;
}
num=num/to;
}
if (jg.length() < size){
int loop = size - jg.length();
for (int i = 0; i < loop; i++){
jg = "B" + jg;
}
}
return jg;
}
/**
* 32位
* @return
*/
public static String getUUID() {
UUID uuid = UUID.randomUUID();
String str = uuid.toString();
// 去掉"-"符号
String temp = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
return temp;
}
public static String generateShortUUID() {
String str = randomNum8(System.nanoTime());
return from10To24(str, 6);
}
public static String generateFileUUID() {
String str = randomNum12(System.nanoTime());
return from10To32(str, 8);
}
public static String genToken(){
return from10To32(randomNum12(System.currentTimeMillis()),8) + from10To32(randomNum12(System.nanoTime()),8);
}
public static void main(String[] args) {
Set set = new HashSet();
String str;
for (int i = 0; i < 300; i++) {
str = generateShortUUID();
System.out.println(str);
set.add(str);
}
System.out.println(set.size());
}
}

View File

@ -4,11 +4,13 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.yomahub.liteflow.spi.ContextAware;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
/**
* 基于代码形式的spring上下文工具类
@ -64,6 +66,14 @@ public class SpringAware implements ApplicationContextAware, ContextAware {
return registerBean(c.getName(), c);
}
@Override
public <T> T registerBean(String beanName, Object bean) {
ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory();
defaultListableBeanFactory.registerSingleton(beanName,bean);
return (T) configurableApplicationContext.getBean(beanName);
}
public <T> T registerOrGet(String beanName, Class<T> clazz) {
if (ObjectUtil.isNull(applicationContext)){
return null;

View File

@ -12,6 +12,7 @@ import com.yomahub.liteflow.aop.ICmpAroundAspect;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.util.LOGOPrinter;
import com.yomahub.liteflow.util.LiteFlowProxyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@ -55,17 +56,29 @@ public class ComponentScanner implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class clazz = bean.getClass();
//判断是不是声明式组件
//如果是就缓存到类属性的map中
if (LiteFlowProxyUtil.isMarkedCmp(bean.getClass())){
LOG.info("proxy component[{}] has been found", beanName);
NodeComponent nodeComponent = LiteFlowProxyUtil.proxy2NodeComponent(bean, beanName);
nodeComponentMap.put(beanName, nodeComponent);
return nodeComponent;
}
// 组件的扫描发现扫到之后缓存到类属性map中
if (NodeComponent.class.isAssignableFrom(clazz)) {
LOG.info("component[{}] has been found", beanName);
NodeComponent nodeComponent = (NodeComponent) bean;
nodeComponentMap.put(beanName, nodeComponent);
return nodeComponent;
}
// 组件Aop的实现类加载
if (ICmpAroundAspect.class.isAssignableFrom(clazz)) {
LOG.info("component aspect implement[{}] has been found", beanName);
cmpAroundAspect = (ICmpAroundAspect) bean;
return cmpAroundAspect;
}
return bean;

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>liteflow</artifactId>
<groupId>com.yomahub</groupId>
<version>2.6.14</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>liteflow-testcase-declare-component</artifactId>
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-script-qlexpress</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,20 @@
package com.yomahub.liteflow.test;
import com.yomahub.liteflow.flow.FlowBus;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.spi.holder.SpiFactoryCleaner;
import com.yomahub.liteflow.spring.ComponentScanner;
import com.yomahub.liteflow.thread.ExecutorHelper;
import org.junit.AfterClass;
public class BaseTest {
@AfterClass
public static void cleanScanCache(){
ComponentScanner.cleanCache();
FlowBus.cleanCache();
ExecutorHelper.loadInstance().clearExecutorServiceMap();
SpiFactoryCleaner.clean();
LiteflowConfigGetter.clean();
}
}

View File

@ -0,0 +1,42 @@
package com.yomahub.liteflow.test.absoluteConfigPath;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* springboot环境下异步线程超时日志打印测试
* @author Bryan.Zhang
* @since 2.6.4
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/absoluteConfigPath/application.properties")
@SpringBootTest(classes = AbsoluteConfigPathSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.absoluteConfigPath.cmp"})
public class AbsoluteConfigPathSpringbootTest extends BaseTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Resource
private FlowExecutor flowExecutor;
@Test
public void testAbsoluteConfig() throws Exception{
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
}
}

View File

@ -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.absoluteConfigPath.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -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.absoluteConfigPath.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("BCmp executed!");
}
}

View File

@ -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.absoluteConfigPath.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,56 @@
package com.yomahub.liteflow.test.aop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.aop.aspect.CustomAspect;
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.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* 切面场景单元测试
* 在声明式组件场景中自定义aspect的aop不生效的因为生成的代理类并不是原类也不是原类的子类而是NodeComponent的子类
* 所以切不到暂且没有想出办法来解决这个测试类暂时不用
* @author Bryan.Zhang
*/
/*@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/aop/application.properties")
@SpringBootTest(classes = CustomAOPSpringbootTest.class)
@EnableAutoConfiguration
@Import(CustomAspect.class)
@ComponentScan({"com.yomahub.liteflow.test.aop.cmp1","com.yomahub.liteflow.test.aop.cmp2"})*/
public class CustomAOPSpringbootTest extends BaseTest {
/*@Resource
private FlowExecutor flowExecutor;
//测试自定义AOP串行场景
@Test
public void testCustomAopS() {
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("before_after", response.getSlot().getData("a"));
Assert.assertEquals("before_after", response.getSlot().getData("b"));
Assert.assertEquals("before_after", response.getSlot().getData("c"));
}
//测试自定义AOP并行场景
@Test
public void testCustomAopP() {
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain2", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("before_after", response.getSlot().getData("a"));
Assert.assertEquals("before_after", response.getSlot().getData("b"));
Assert.assertEquals("before_after", response.getSlot().getData("c"));
}*/
}

View File

@ -0,0 +1,76 @@
package com.yomahub.liteflow.test.aop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.spring.ComponentScanner;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.aop.aspect.CmpAspect;
import org.junit.AfterClass;
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.context.annotation.Import;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* 切面场景单元测试
* @author Bryan.Zhang
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/aop/application.properties")
@SpringBootTest(classes = GlobalAOPSpringbootTest.class)
@EnableAutoConfiguration
@Import(CmpAspect.class)
@ComponentScan({"com.yomahub.liteflow.test.aop.cmp1","com.yomahub.liteflow.test.aop.cmp2"})
public class GlobalAOPSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//测试全局AOP串行场景
@Test
public void testGlobalAopS() {
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain1", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("before_after", response.getSlot().getData("a"));
Assert.assertEquals("before_after", response.getSlot().getData("b"));
Assert.assertEquals("before_after", response.getSlot().getData("c"));
Assert.assertEquals("before_after", response.getSlot().getData("d"));
Assert.assertEquals("before_after", response.getSlot().getData("e"));
}
//测试全局AOP并行场景
@Test
public void testGlobalAopP() {
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain2", "it's a request");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("before_after", response.getSlot().getData("a"));
Assert.assertEquals("before_after", response.getSlot().getData("b"));
Assert.assertEquals("before_after", response.getSlot().getData("c"));
Assert.assertEquals("before_after", response.getSlot().getData("d"));
Assert.assertEquals("before_after", response.getSlot().getData("e"));
}
@Test
public void testGlobalAopException() {
LiteflowResponse<DefaultSlot> response= flowExecutor.execute2Resp("chain3", "it's a request");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("before_after", response.getSlot().getData("a"));
Assert.assertEquals("before_after", response.getSlot().getData("b"));
Assert.assertEquals("before_after", response.getSlot().getData("c"));
Assert.assertEquals("before_after", response.getSlot().getData("f"));
}
@AfterClass
public static void cleanScanCache(){
BaseTest.cleanScanCache();
ComponentScanner.cmpAroundAspect = null;
}
}

View File

@ -0,0 +1,17 @@
package com.yomahub.liteflow.test.aop.aspect;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.aop.ICmpAroundAspect;
import com.yomahub.liteflow.entity.data.Slot;
public class CmpAspect implements ICmpAroundAspect {
@Override
public void beforeProcess(String nodeId, Slot slot) {
slot.setData(nodeId, "before");
}
@Override
public void afterProcess(String nodeId, Slot slot) {
slot.setData(nodeId, StrUtil.format("{}_{}", slot.getData(nodeId), "after"));
}
}

View File

@ -0,0 +1,27 @@
package com.yomahub.liteflow.test.aop.aspect;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CustomAspect {
@Pointcut("execution(* com.yomahub.liteflow.test.aop.cmp1.*.process(*))")
public void cut() {
}
@Around("cut()")
public Object around(ProceedingJoinPoint jp) throws Throwable {
NodeComponent cmp = (NodeComponent) jp.getThis();
Slot slot = cmp.getSlot();
slot.setData(cmp.getNodeId(), "before");
Object returnObj = jp.proceed();
slot.setData(cmp.getNodeId(), StrUtil.format("{}_{}", slot.getData(cmp.getNodeId()), "after"));
return returnObj;
}
}

View File

@ -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.aop.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("Acomp executed!");
}
}

View File

@ -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.aop.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("Bcomp executed!");
}
}

View File

@ -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.aop.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("Ccomp executed!");
}
}

View File

@ -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.aop.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("d")
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("Dcomp executed!");
}
}

View File

@ -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.aop.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("e")
@LiteflowCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("Ecomp executed!");
}
}

View File

@ -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.aop.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("f")
@LiteflowCmpDefine
public class FCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
throw new RuntimeException("test error");
}
}

View File

@ -0,0 +1,134 @@
package com.yomahub.liteflow.test.asyncNode;
import cn.hutool.core.collection.ListUtil;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.asyncNode.exception.TestException;
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;
/**
* 测试隐式调用子流程
* 单元测试
*
* @author ssss
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/asyncNode/application.properties")
@SpringBootTest(classes = AsyncNodeSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.asyncNode.cmp"})
public class AsyncNodeSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
/*****
* 标准chain 嵌套选择 嵌套子chain进行执行
* 验证了when情况下 多个node是并行执行
* 验证了默认参数情况下 when可以加载执行
* **/
@Test
public void testAsyncFlow1() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "it's a base request");
Assert.assertTrue(response.isSuccess());
System.out.println(response.getSlot().getExecuteStepStr());
}
//这个和test1有点类似只不过进一步验证了步骤
@Test
public void testAsyncFlow2() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", "it's a base request");
Assert.assertTrue(ListUtil.toList("b==>j==>g==>f==>h","b==>j==>g==>h==>f",
"b==>j==>h==>g==>f","b==>j==>h==>f==>g",
"b==>j==>f==>h==>g","b==>j==>f==>g==>h"
).contains(response.getSlot().getExecuteStepStr()));
}
//测试errorResume,默认的errorResume为false这里测试默认的
@Test
public void testAsyncFlow3_1() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3-1", "it's a base request");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals(response.getSlot().getException().getClass(), TestException.class);
}
//测试errorResume,默认的errorResume为false这里设置为true
@Test
public void testAsyncFlow3_2() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3-2", "it's a base request");
Assert.assertTrue(response.isSuccess());
}
//相同group的并行组会合并并且errorResume根据第一个when来这里第一个when配置了不抛错
@Test
public void testAsyncFlow4() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "it's a base request");
//因为不记录错误所以最终结果是true
Assert.assertTrue(response.isSuccess());
//因为是并行组所以即便抛错了其他组件也会执行i在流程里配置了2遍i抛错但是也执行了2遍这里验证下
Integer count = response.getSlot().getData("count");
Assert.assertEquals(new Integer(2), count);
//因为配置了不抛错所以response里的cause应该为null
Assert.assertNull(response.getCause());
}
//相同group的并行组会合并并且errorResume根据第一个when来这里第一个when配置了会抛错
@Test
public void testAsyncFlow5() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain5", "it's a base request");
//整个并行组是报错的所以最终结果是false
Assert.assertFalse(response.isSuccess());
//因为是并行组所以即便抛错了其他组件也会执行i在流程里配置了2遍i抛错但是也执行了2遍这里验证下
Integer count = response.getSlot().getData("count");
Assert.assertEquals(new Integer(2), count);
//因为第一个when配置了会报错所以response里的cause里应该会有TestException
Assert.assertEquals(TestException.class, response.getCause().getClass());
}
//不同group的并行组不会合并第一个when的errorResume是false会抛错那第二个when就不会执行
@Test
public void testAsyncFlow6() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain6", "it's a base request");
//第一个when会抛错所以最终结果是false
Assert.assertFalse(response.isSuccess());
//因为是不同组并行组第一组的when里的i就抛错了所以i就执行了1遍
Integer count = response.getSlot().getData("count");
Assert.assertEquals(new Integer(1), count);
//第一个when会报错所以最终response的cause里应该会有TestException
Assert.assertEquals(TestException.class, response.getCause().getClass());
}
//不同group的并行组不会合并第一个when的errorResume是true不会报错那第二个when还会继续执行但是第二个when的errorResume是false所以第二个when会报错
@Test
public void testAsyncFlow7() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain7", "it's a base request");
//第二个when会抛错所以最终结果是false
Assert.assertFalse(response.isSuccess());
// 传递了slotIndex则set的size==2
Integer count = response.getSlot().getData("count");
Assert.assertEquals(new Integer(2), count);
//第一个when会报错所以最终response的cause里应该会有TestException
Assert.assertEquals(TestException.class, response.getCause().getClass());
}
//测试任意异步一个执行完即继续的场景
//d g h并行配置了any=true其中d耗时1秒g耗时0.5秒其他都不设耗时
//最终执行效果应该是h先返回然后执行abc,最后gd
//这里要注意的是由于step是先加入所以step的打印顺序并不是这样的但是实际执行是正确的
@Test
public void testAsyncFlow8() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain8", "it's a base request");
Assert.assertTrue(response.isSuccess());
Assert.assertTrue(response.getSlot().getData("check").toString().startsWith("habc"));
}
}

View File

@ -0,0 +1,28 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Acomp executed!");
}
}

View File

@ -0,0 +1,28 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Bcomp executed!");
}
}

View File

@ -0,0 +1,28 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Ccomp executed!");
}
}

View File

@ -0,0 +1,29 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("d")
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
Thread.sleep(1000);
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Dcomp executed!");
}
}

View File

@ -0,0 +1,20 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.core.NodeCondComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("e")
@LiteflowCondCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
public String processCond(NodeComponent bindCmp) throws Exception {
System.out.println("Ecomp executed!");
return "g";
}
}

View File

@ -0,0 +1,18 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("f")
@LiteflowCmpDefine
public class FCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
System.out.println("Fcomp executed!");
}
}

View File

@ -0,0 +1,30 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("g")
@LiteflowCmpDefine
public class GCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
Thread.sleep(500);
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Gcomp executed!");
}
}

View File

@ -0,0 +1,30 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("h")
@LiteflowCmpDefine
public class HCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
Slot slot = bindCmp.getSlot();
synchronized (NodeComponent.class){
if (slot.hasData("check")){
String str = slot.getData("check");
str += bindCmp.getNodeId();
slot.setData("check", str);
}else{
slot.setData("check", bindCmp.getNodeId());
}
}
System.out.println("Hcomp executed!");
}
}

View File

@ -0,0 +1,28 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.entity.data.Slot;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.test.asyncNode.exception.TestException;
import org.springframework.stereotype.Component;
@Component("i")
@LiteflowCmpDefine
public class ICmp {
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
Slot slot = bindCmp.getSlot();
if (slot.hasData("count")){
Integer count = slot.getData("count");
slot.setData("count", ++count);
} else{
slot.setData("count", 1);
}
System.out.println("Icomp executed! throw Exception!");
throw new TestException();
}
}

View File

@ -0,0 +1,21 @@
package com.yomahub.liteflow.test.asyncNode.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.core.NodeCondComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("j")
@LiteflowCondCmpDefine
public class JCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
public String processCond(NodeComponent bindCmp) throws Exception {
System.out.println("Jcomp executed!");
return "chain3";
}
}

View File

@ -0,0 +1,4 @@
package com.yomahub.liteflow.test.asyncNode.exception;
public class TestException extends Exception{
}

View File

@ -0,0 +1,39 @@
package com.yomahub.liteflow.test.base;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.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;
/**
* springboot环境最普通的例子测试
* @author Bryan.Zhang
* @since 2.6.4
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/base/application.properties")
@SpringBootTest(classes = BaseSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.base.cmp"})
public class BaseSpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
@Test
public void testBase() throws Exception{
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
}
}

View File

@ -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.base.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -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.base.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("BCmp executed!");
}
}

View File

@ -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.base.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,31 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.base.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component("d")
@LiteflowCmpDefine
public class DCmp{
@Resource
private TestDomain testDomain;
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
testDomain.sayHi();
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,10 @@
package com.yomahub.liteflow.test.base.cmp;
import org.springframework.stereotype.Component;
@Component
public class TestDomain {
public void sayHi(){
System.out.println("hello");
}
}

View File

@ -0,0 +1,217 @@
package com.yomahub.liteflow.test.builder;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.ExecutableEntity;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.enums.NodeTypeEnum;
import com.yomahub.liteflow.test.BaseTest;
import com.yomahub.liteflow.test.builder.cmp1.*;
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.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
//基于builder模式的单元测试
//这里只是最基本的builder模式的测试只是为了验证在springboot模式下的正常性
//更详细的builder模式测试用例会单独拉testcase去做
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BuilderSpringbootTest1.class)
@EnableAutoConfiguration
public class BuilderSpringbootTest1 extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//基于普通组件的builder模式测试
@Test
public void testBuilder() throws Exception {
LiteFlowNodeBuilder.createNode().setId("a")
.setName("组件A")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.ACmp")
.build();
LiteFlowNodeBuilder.createNode().setId("b")
.setName("组件B")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.BCmp")
.build();
LiteFlowNodeBuilder.createNode().setId("c")
.setName("组件C")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.CCmp")
.build();
LiteFlowNodeBuilder.createNode().setId("d")
.setName("组件D")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.DCmp")
.build();
LiteFlowNodeBuilder.createNode().setId("e")
.setName("组件E")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.ECmp")
.build();
LiteFlowNodeBuilder.createNode().setId("f")
.setName("组件F")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.FCmp")
.build();
LiteFlowNodeBuilder.createNode().setId("g")
.setName("组件G")
.setType(NodeTypeEnum.COMMON)
.setClazz("com.yomahub.liteflow.test.builder.cmp1.GCmp")
.build();
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
).build();
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
LiteFlowConditionBuilder
.createThenCondition()
.setValue("a,b").build()
).setCondition(
LiteFlowConditionBuilder.createWhenCondition()
.setValue("e(f|g|chain2)").build()
).build();
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
}
//基于普通组件的builder模式测试
@Test
public void testBuilderForClassAndCode() throws Exception {
LiteFlowNodeBuilder.createNode().setId("a")
.setName("组件A")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(ACmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("b")
.setName("组件B")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(BCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("c")
.setName("组件C")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(CCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("d")
.setName("组件D")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(DCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("e")
.setName("组件E")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(ECmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("f")
.setName("组件F")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(FCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("g")
.setName("组件G")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(GCmp.class)
.build();
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
LiteFlowConditionBuilder.createThenCondition().setValue("c,d").build()
).build();
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
LiteFlowConditionBuilder
.createThenCondition()
.setValue("a,b").build()
).setCondition(
LiteFlowConditionBuilder.createWhenCondition()
.setValue("e(f|g|chain2)").build()
).build();
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
}
//基于普通组件的builder模式测试
@Test
public void testBuilderForConditionNode() throws Exception {
LiteFlowNodeBuilder.createNode().setId("a")
.setName("组件A")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(ACmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("b")
.setName("组件B")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(BCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("c")
.setName("组件C")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(CCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("d")
.setName("组件D")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(DCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("e")
.setName("组件E")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(ECmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("f")
.setName("组件F")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(FCmp.class)
.build();
LiteFlowNodeBuilder.createNode().setId("g")
.setName("组件G")
.setTypeCode(NodeTypeEnum.COMMON.getCode())
.setClazz(GCmp.class)
.build();
LiteFlowChainBuilder.createChain().setChainName("chain2").setCondition(
LiteFlowConditionBuilder.createThenCondition()
.setExecutable(new ExecutableEntity().setId("c"))
.setExecutable(new ExecutableEntity().setId("d"))
.build()
).build();
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
LiteFlowConditionBuilder
.createThenCondition()
.setExecutable(new ExecutableEntity().setId("a").setTag("hello"))
.setExecutable(new ExecutableEntity().setId("b"))
.build()
).setCondition(
LiteFlowConditionBuilder.createWhenCondition()
.setExecutable(
new ExecutableEntity().setId("e")
.addNodeCondComponent(new ExecutableEntity().setId("f").setTag("FHello"))
.addNodeCondComponent(new ExecutableEntity().setId("g"))
.addNodeCondComponent(new ExecutableEntity().setId("chain2")
)).build()
).build();
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a[组件A]==>b[组件B]==>e[组件E]==>c[组件C]==>d[组件D]", response.getSlot().getExecuteStepStr());
}
}

View File

@ -0,0 +1,41 @@
package com.yomahub.liteflow.test.builder;
import com.yomahub.liteflow.builder.LiteFlowChainBuilder;
import com.yomahub.liteflow.builder.LiteFlowConditionBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.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.junit4.SpringRunner;
import javax.annotation.Resource;
//基于builder模式的单元测试
//这里测试的是通过spring去扫描但是通过代码去构建chain的用例
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BuilderSpringbootTest2.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.builder.cmp2"})
public class BuilderSpringbootTest2 extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//通过spring去扫描组件通过代码去构建chain
@Test
public void testBuilder() throws Exception {
LiteFlowChainBuilder.createChain().setChainName("chain1").setCondition(
LiteFlowConditionBuilder.createThenCondition().setValue("h,i,j").build()
).build();
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("h==>i==>j", response.getSlot().getExecuteStepStr());
}
}

View File

@ -0,0 +1,22 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("BCmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("DCmp executed!");
}
}

View File

@ -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.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCondCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
public String processCond(NodeComponent bindCmp) throws Exception {
System.out.println("ECmp executed!");
return "chain2";
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class FCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("FCmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.builder.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class GCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("GCmp executed!");
}
}

View File

@ -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.builder.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("h")
@LiteflowCmpDefine
public class HCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("HCmp executed!");
}
}

View File

@ -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.builder.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("i")
@LiteflowCmpDefine
public class ICmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ICmp executed!");
}
}

View File

@ -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.builder.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("j")
@LiteflowCmpDefine
public class JCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("JCmp executed!");
}
}

View File

@ -0,0 +1,64 @@
package com.yomahub.liteflow.test.cmpRetry;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.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;
/**
* 测试springboot下的节点执行器
* @author Bryan.Zhang
* @since 2.5.10
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/cmpRetry/application.properties")
@SpringBootTest(classes = LiteflowRetrySpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.cmpRetry.cmp"})
public class LiteflowRetrySpringbootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
//全局重试配置测试
@Test
public void testRetry1() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("a==>b==>b==>b", response.getSlot().getExecuteStepStr());
}
//单个组件重试配置测试
@Test
public void testRetry2() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", "arg");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("c==>c==>c==>c==>c==>c", response.getSlot().getExecuteStepStr());
}
//单个组件指定异常但抛出的并不是指定异常的场景测试
@Test
public void testRetry3() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3", "arg");
Assert.assertFalse(response.isSuccess());
}
//单个组件指定异常重试抛出的是指定异常或者
@Test
public void testRetry4() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "arg");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("e==>e==>e==>e==>e==>e", response.getSlot().getExecuteStepStr());
}
}

View File

@ -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.cmpRetry.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -0,0 +1,31 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.cmpRetry.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("b")
@LiteflowCmpDefine
public class BCmp {
private int flag = 0;
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("BCmp executed!");
if (flag < 2){
flag++;
throw new RuntimeException("demo exception");
}
}
}

View File

@ -0,0 +1,28 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.cmpRetry.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.annotation.LiteflowRetry;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("c")
@LiteflowRetry(5)
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
throw new RuntimeException("demo exception");
}
}

View File

@ -0,0 +1,28 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.cmpRetry.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.annotation.LiteflowRetry;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("d")
@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("DCmp executed!");
throw new RuntimeException("demo exception");
}
}

View File

@ -0,0 +1,28 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.cmpRetry.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.annotation.LiteflowRetry;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowComponent("e")
@LiteflowRetry(retry = 5, forExceptions = {NullPointerException.class})
@LiteflowCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ECmp executed!");
throw new NullPointerException("demo null exception");
}
}

View File

@ -0,0 +1,94 @@
package com.yomahub.liteflow.test.component;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 org.springframework.util.ReflectionUtils;
import javax.annotation.Resource;
/**
* 组件功能点测试
* 单元测试
*
* @author donguo.tao
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/component/application.properties")
@SpringBootTest(classes = FlowExecutorSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.component.cmp1","com.yomahub.liteflow.test.component.cmp2"})
public class FlowExecutorSpringbootTest extends BaseTest {
private static final Logger LOG = LoggerFactory.getLogger(FlowExecutorSpringbootTest.class);
@Resource
private FlowExecutor flowExecutor;
//isAccess方法的功能测试
@Test
public void testIsAccess() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", 101);
Assert.assertTrue(response.isSuccess());
Assert.assertNotNull(response.getSlot().getResponseData());
}
//组件抛错的功能点测试
@Test(expected = ArithmeticException.class)
public void testComponentException() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain2", 0);
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("/ by zero", response.getMessage());
ReflectionUtils.rethrowException(response.getCause());
}
//isContinueOnError方法的功能点测试
@Test
public void testIsContinueOnError() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain3", 0);
Assert.assertTrue(response.isSuccess());
Assert.assertNull(response.getCause());
}
//isEnd方法的功能点测试
@Test
public void testIsEnd() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", 10);
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("d",response.getSlot().getExecuteStepStr());
}
//setIsEnd方法的功能点测试
@Test
public void testSetIsEnd1() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain5", 10);
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("e",response.getSlot().getExecuteStepStr());
}
//条件组件的功能点测试
@Test
public void testNodeCondComponent() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain6", 0);
Assert.assertTrue(response.isSuccess());
}
//测试setIsEnd如果为truecontinueError也为true那不应该continue了
@Test
public void testSetIsEnd2() throws Exception {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain7", 10);
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("g",response.getSlot().getExecuteStepStr());
}
}

View File

@ -0,0 +1,30 @@
package com.yomahub.liteflow.test.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
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.Objects;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("AComp executed!");
bindCmp.getSlot().setResponseData("AComp executed!");
}
@LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)
public boolean isAccess(NodeComponent bindCmp) {
Integer requestData = bindCmp.getSlot().getRequestData();
if (Objects.nonNull(requestData) && requestData > 100){
return true;
}
System.out.println("AComp isAccess false.");
return false;
}
}

View File

@ -0,0 +1,33 @@
package com.yomahub.liteflow.test.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
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.Objects;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("BComp executed!");
Integer requestData = bindCmp.getSlot().getRequestData();
Integer divisor = 130;
Integer result = divisor / requestData;
bindCmp.getSlot().setResponseData(result);
}
@LiteflowMethod(LiteFlowMethodEnum.IS_ACCESS)
public boolean isAccess(NodeComponent bindCmp) {
Integer requestData = bindCmp.getSlot().getRequestData();
if (Objects.nonNull(requestData)){
return true;
}
return false;
}
}

View File

@ -0,0 +1,33 @@
package com.yomahub.liteflow.test.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
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.Objects;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CComp executed!");
Integer requestData = bindCmp.getSlot().getRequestData();
Integer divisor = 130;
Integer result = divisor / requestData;
bindCmp.getSlot().setResponseData(result);
System.out.println("responseData="+Integer.parseInt(bindCmp.getSlot().getResponseData()));
}
@LiteflowMethod(LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR)
public boolean isContinueOnError(NodeComponent bindCmp) {
Integer requestData = bindCmp.getSlot().getRequestData();
if (Objects.nonNull(requestData)){
return true;
}
return false;
}
}

View File

@ -0,0 +1,30 @@
package com.yomahub.liteflow.test.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
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.Objects;
@Component("d")
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
System.out.println("DComp executed!");
}
@LiteflowMethod(LiteFlowMethodEnum.IS_END)
public boolean isEnd(NodeComponent bindCmp) {
//组件的process执行完之后才会执行isEnd
Object requestData = bindCmp.getSlot().getResponseData();
if (Objects.isNull(requestData)){
System.out.println("DComp flow isEnd, because of responseData is null.");
return true;
}
return false;
}
}

View File

@ -0,0 +1,28 @@
package com.yomahub.liteflow.test.component.cmp1;
import com.alibaba.fastjson.JSON;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
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.Objects;
@Component("e")
@LiteflowCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) throws Exception {
System.out.println("EComp executed!");
Object responseData = bindCmp.getSlot().getResponseData();
if (Objects.isNull(responseData)){
System.out.println("EComp responseData flow must be set end .");
//执行到某个条件时手动结束流程
bindCmp.setIsEnd(true);
}
System.out.println("EComp responseData responseData=" + JSON.toJSONString(responseData));
}
}

View File

@ -0,0 +1,30 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("g")
@LiteflowCmpDefine
public class GCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("GCmp executed!");
bindCmp.setIsEnd(true);
}
@LiteflowMethod(LiteFlowMethodEnum.IS_CONTINUE_ON_ERROR)
public boolean isContinueOnError(NodeComponent bindCmp) {
return true;
}
}

View File

@ -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.component.cmp1;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("h")
@LiteflowCmpDefine
public class HCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("HCmp executed!");
}
}

View File

@ -0,0 +1,27 @@
package com.yomahub.liteflow.test.component.cmp2;
import com.yomahub.liteflow.annotation.LiteflowCondCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.core.NodeCondComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Component("f")
@LiteflowCondCmpDefine
public class FCondCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS_COND)
public String processCond(NodeComponent bindCmp) {
Integer requestData = bindCmp.getSlot().getRequestData();
if (Objects.isNull(requestData)){
return "d";
} else if(requestData == 0){
return "c";
} else {
return "b";
}
}
}

View File

@ -0,0 +1,45 @@
package com.yomahub.liteflow.test.customNodes;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* springboot环境下自定义声明节点的测试
* 不通过spring扫描的方式通过在配置文件里定义nodes的方式
* @author Bryan.Zhang
* @since 2.6.4
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/customNodes/application.properties")
@SpringBootTest(classes = CustomNodesSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.customNodes.domain"})
public class CustomNodesSpringbootTest extends BaseTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Resource
private FlowExecutor flowExecutor;
@Test
public void testCustomNodes() throws Exception{
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response.isSuccess());
response = flowExecutor.execute2Resp("chain2", "arg");
Assert.assertTrue(response.isSuccess());
}
}

View File

@ -0,0 +1,22 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -0,0 +1,29 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
import javax.annotation.Resource;
@LiteflowCmpDefine
public class BCmp{
@Resource
private DemoDomain demoDomain;
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
demoDomain.sayHi();
System.out.println("BCmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("DCmp executed!");
}
}

View File

@ -0,0 +1,30 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.test.customNodes.domain.DemoDomain;
import javax.annotation.Resource;
@LiteflowCmpDefine
public class ECmp{
@Resource
private DemoDomain demoDomain;
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
demoDomain.sayHi();
System.out.println("ECmp executed!");
}
}

View File

@ -0,0 +1,23 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customNodes.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
@LiteflowCmpDefine
public class FCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("FCmp executed!");
}
}

View File

@ -0,0 +1,11 @@
package com.yomahub.liteflow.test.customNodes.domain;
import org.springframework.stereotype.Component;
@Component
public class DemoDomain {
public void sayHi(){
System.out.println("hi");
}
}

View File

@ -0,0 +1,25 @@
package com.yomahub.liteflow.test.customWhenThreadPool;
import cn.hutool.core.util.ObjectUtil;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.thread.ExecutorBuilder;
import java.util.concurrent.ExecutorService;
public class CustomThreadExecutor1 implements ExecutorBuilder {
@Override
public ExecutorService buildExecutor() {
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
//只有在非spring的场景下liteflowConfig才会为null
if (ObjectUtil.isNull(liteflowConfig)) {
liteflowConfig = new LiteflowConfig();
}
return buildDefaultExecutor(
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenQueueLimit(),
"customer-when-1-thead-");
}
}

View File

@ -0,0 +1,24 @@
package com.yomahub.liteflow.test.customWhenThreadPool;
import cn.hutool.core.util.ObjectUtil;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.thread.ExecutorBuilder;
import java.util.concurrent.ExecutorService;
public class CustomThreadExecutor2 implements ExecutorBuilder {
@Override
public ExecutorService buildExecutor() {
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
//只有在非spring的场景下liteflowConfig才会为null
if (ObjectUtil.isNull(liteflowConfig)) {
liteflowConfig = new LiteflowConfig();
}
return buildDefaultExecutor(
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenQueueLimit(),
"customer-when-2-thead-");
}
}

View File

@ -0,0 +1,24 @@
package com.yomahub.liteflow.test.customWhenThreadPool;
import cn.hutool.core.util.ObjectUtil;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
import com.yomahub.liteflow.thread.ExecutorBuilder;
import java.util.concurrent.ExecutorService;
public class CustomThreadExecutor3 implements ExecutorBuilder {
@Override
public ExecutorService buildExecutor() {
LiteflowConfig liteflowConfig = LiteflowConfigGetter.get();
//只有在非spring的场景下liteflowConfig才会为null
if (ObjectUtil.isNull(liteflowConfig)) {
liteflowConfig = new LiteflowConfig();
}
return buildDefaultExecutor(
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenMaxWorkers(),
liteflowConfig.getWhenQueueLimit(),
"customer-when-3-thead-");
}
}

View File

@ -0,0 +1,72 @@
package com.yomahub.liteflow.test.customWhenThreadPool;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* springboot环境下异步线程超时日志打印测试
*
* @author Bryan.Zhang
* @since 2.6.4
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/customWhenThreadPool/application.properties")
@SpringBootTest(classes = CustomWhenThreadPoolSpringbootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.customWhenThreadPool.cmp"})
public class CustomWhenThreadPoolSpringbootTest extends BaseTest {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Resource
private FlowExecutor flowExecutor;
/**
* 测试全局线程池配置
*/
@Test
public void testGlobalThreadPool() {
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain", "arg");
Assert.assertTrue(response.isSuccess());
Assert.assertTrue(response.getSlot().getData("threadName").toString().startsWith("lf-when-thead"));
}
/**
* 测试全局和when上自定义线程池-优先以when上为准
*/
@Test
public void testGlobalAndCustomWhenThreadPool() {
LiteflowResponse<DefaultSlot> response1 = flowExecutor.execute2Resp("chain1", "arg");
Assert.assertTrue(response1.isSuccess());
Assert.assertTrue(response1.getSlot().getData("threadName").toString().startsWith("customer-when-1-thead"));
}
/**
* when配置的线程池可以共用
*/
@Test
public void testCustomWhenThreadPool() {
// 使用when - thread1
testGlobalAndCustomWhenThreadPool();
// chain配置同一个thead1
LiteflowResponse<DefaultSlot> response2 = flowExecutor.execute2Resp("chain2", "arg");
Assert.assertTrue(response2.isSuccess());
Assert.assertTrue(response2.getSlot().getData("threadName").toString().startsWith("customer-when-1-thead"));
}
}

View File

@ -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.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
System.out.println("ACmp executed!");
}
}

View File

@ -0,0 +1,26 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("b")
@LiteflowCmpDefine
public class BCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
System.out.println("BCmp executed!");
}
}

View File

@ -0,0 +1,26 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("c")
@LiteflowCmpDefine
public class CCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
System.out.println("CCmp executed!");
}
}

View File

@ -0,0 +1,26 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("d")
@LiteflowCmpDefine
public class DCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
System.out.println("DCmp executed!");
}
}

View File

@ -0,0 +1,26 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("e")
@LiteflowCmpDefine
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
System.out.println("ECmp executed!");
}
}

View File

@ -0,0 +1,26 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.customWhenThreadPool.cmp;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.springframework.stereotype.Component;
@Component("f")
@LiteflowCmpDefine
public class FCmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
bindCmp.getSlot().setData("threadName", Thread.currentThread().getName());
System.out.println("FCmp executed!");
}
}

View File

@ -0,0 +1,83 @@
package com.yomahub.liteflow.test.exception;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.entity.data.DefaultSlot;
import com.yomahub.liteflow.entity.data.LiteflowResponse;
import com.yomahub.liteflow.exception.ChainNotFoundException;
import com.yomahub.liteflow.exception.ConfigErrorException;
import com.yomahub.liteflow.exception.FlowExecutorNotInitException;
import com.yomahub.liteflow.exception.FlowSystemException;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ReflectionUtils;
import javax.annotation.Resource;
/**
* 流程执行异常
* 单元测试
*
* @author zendwang
*/
@RunWith(SpringRunner.class)
@TestPropertySource(value = "classpath:/exception/application.properties")
@SpringBootTest(classes = ExceptionSpringBootTest.class)
@EnableAutoConfiguration
@ComponentScan({"com.yomahub.liteflow.test.exception.cmp"})
public class ExceptionSpringBootTest extends BaseTest {
@Resource
private FlowExecutor flowExecutor;
@Autowired
private ApplicationContext context;
@Test(expected = ConfigErrorException.class)
public void testConfigErrorException() {
flowExecutor.setLiteflowConfig(null);
flowExecutor.init();
}
@Test(expected = FlowExecutorNotInitException.class)
public void testFlowExecutorNotInitException() {
LiteflowConfig config = context.getBean(LiteflowConfig.class);
config.setRuleSource("error/flow.txt");
flowExecutor.init();
}
@Test(expected = ChainNotFoundException.class)
public void testChainNotFoundException() throws Exception {
flowExecutor.execute("chain0", "it's a request");
}
@Test(expected = RuntimeException.class)
public void testComponentCustomException() throws Exception {
flowExecutor.execute("chain1", "exception");
}
@Test(expected = FlowSystemException.class)
public void testNoConditionInChainException() throws Exception {
LiteflowResponse response = flowExecutor.execute2Resp("chain2", "test");
Assert.assertFalse(response.isSuccess());
Assert.assertEquals("no conditionList in this chain[chain2]", response.getMessage());
ReflectionUtils.rethrowException(response.getCause());
}
@Test
public void testGetSlotFromResponseWhenException() throws Exception{
LiteflowResponse<DefaultSlot> response = flowExecutor.execute2Resp("chain4", "test");
Assert.assertFalse(response.isSuccess());
Assert.assertNotNull(response.getCause());
Assert.assertNotNull(response.getSlot());
}
}

View File

@ -0,0 +1,34 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.exception.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.annotation.LiteflowCmpDefine;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component("a")
@LiteflowCmpDefine
public class ACmp{
private static final Logger LOG = LoggerFactory.getLogger(ACmp.class);
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
String str = bindCmp.getSlot().getRequestData();
if(StrUtil.isNotBlank(str) && str.equals("exception")) {
throw new RuntimeException("chain execute execption");
}
LOG.info("Acomp executed!");
}
}

Some files were not shown because too many files have changed in this diff Show More