enhancement #I5VJ85 循环组件支持获取当前循环的下标

This commit is contained in:
everywhere.z 2022-12-18 16:41:02 +08:00
parent ea5c828078
commit 40560647e7
21 changed files with 400 additions and 3 deletions

View File

@ -34,7 +34,7 @@ public class ForOperator extends BaseOperator<ForCondition> {
node = new Node();
NodeForComponent nodeForComponent = new NodeForComponent() {
@Override
public int processFor() throws Exception {
public int processFor() {
return forCount;
}
};

View File

@ -60,9 +60,14 @@ public abstract class NodeComponent{
private Class<? extends NodeExecutor> nodeExecutorClass = DefaultNodeExecutor.class;
/**当前对象为单例注册进spring上下文但是node实例不是单例这里通过对node实例的引用来获得一些链路属性**/
private final TransmittableThreadLocal<Node> refNodeTL = new TransmittableThreadLocal<>();
/********************以下的属性为线程附加属性********************/
/**
*******************以下的属性为线程附加属性********************
* 线程属性是指每一个request的值都是不一样的
* 这里NodeComponent是单例所以要用ThreadLocal来修饰
*/
//当前slot的index
private final TransmittableThreadLocal<Integer> slotIndexTL = new TransmittableThreadLocal<>();
@ -340,6 +345,10 @@ public abstract class NodeComponent{
return JsonUtil.parseObject(cmpData, clazz);
}
public Integer getLoopIndex(){
return this.refNodeTL.get().getLoopIndex();
}
@Deprecated
public void invoke(String chainId, Object param) throws Exception {
FlowExecutorHolder.loadInstance().invoke(chainId, param, this.getSlotIndex());

View File

@ -12,6 +12,7 @@ import java.text.MessageFormat;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.property.LiteflowConfigGetter;
@ -28,6 +29,7 @@ import org.slf4j.LoggerFactory;
/**
* Node节点实现可执行器
* Node节点并不是单例的每构建一次都会copy出一个新的实例
* @author Bryan.Zhang
*/
public class Node implements Executable,Cloneable{
@ -52,6 +54,8 @@ public class Node implements Executable,Cloneable{
private String currChainId;
private TransmittableThreadLocal<Integer> loopIndexTL = new TransmittableThreadLocal<>();
public Node(){
}
@ -150,6 +154,7 @@ public class Node implements Executable,Cloneable{
instance.removeSlotIndex();
instance.removeIsEnd();
instance.removeRefNode();
removeLoopIndex();
}
}
@ -224,4 +229,16 @@ public class Node implements Executable,Cloneable{
public String getCurrChainId() {
return currChainId;
}
public void setLoopIndex(int index){
this.loopIndexTL.set(index);
}
public Integer getLoopIndex(){
return this.loopIndexTL.get();
}
public void removeLoopIndex(){
this.loopIndexTL.remove();
}
}

View File

@ -42,6 +42,9 @@ public class ForCondition extends LoopCondition{
//循环执行
for (int i = 0; i < forCount; i++) {
executableItem.setCurrChainId(this.getCurrChainId());
//设置循环index
setLoopIndex(executableItem, i);
executableItem.execute(slotIndex);
//如果break组件不为空则去执行
if (ObjectUtil.isNotNull(breakNode)){
@ -54,7 +57,6 @@ public class ForCondition extends LoopCondition{
}
}
}
}
@Override

View File

@ -1,5 +1,7 @@
package com.yomahub.liteflow.flow.element.condition;
import com.yomahub.liteflow.flow.element.Chain;
import com.yomahub.liteflow.flow.element.Executable;
import com.yomahub.liteflow.flow.element.Node;
/**
@ -20,4 +22,14 @@ public abstract class LoopCondition extends Condition {
public void setBreakNode(Node breakNode) {
this.breakNode = breakNode;
}
protected void setLoopIndex(Executable executableItem, int index){
if (executableItem instanceof Chain){
((Chain)executableItem).getConditionList().forEach(condition -> setLoopIndex(condition, index));
}else if(executableItem instanceof Condition){
((Condition)executableItem).getExecutableList().forEach(executable -> setLoopIndex(executable, index));
}else if(executableItem instanceof Node){
((Node)executableItem).setLoopIndex(index);
}
}
}

View File

@ -32,7 +32,10 @@ public class WhileCondition extends LoopCondition{
Executable executableItem = this.getDoExecutor();
//循环执行
int index = 0;
while(getWhileResult(slotIndex)){
executableItem.setCurrChainId(this.getCurrChainId());
setLoopIndex(executableItem, index++);
executableItem.execute(slotIndex);
//如果break组件不为空则去执行
if (ObjectUtil.isNotNull(breakNode)){

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.test.loop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
@ -68,4 +69,26 @@ public class LoopELDeclMultiSpringbootTest extends BaseTest {
Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr());
}
//测试FOR循环中的index
@Test
public void testLoop6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
//测试WHILE循环中的index
@Test
public void testLoop7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
}

View File

@ -1,5 +1,6 @@
package com.yomahub.liteflow.test.loop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
@ -38,6 +39,19 @@ public class CmpConfig {
}
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS,nodeId = "e")
public void processE(NodeComponent bindCmp) {
DefaultContext context = bindCmp.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", bindCmp.getTag());
if (context.hasData(key)){
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, bindCmp.getLoopIndex());
context.setData(key, loopStrReturn);
}else{
context.setData(key, bindCmp.getLoopIndex().toString());
}
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS_FOR, nodeId = "x", nodeType = NodeTypeEnum.FOR)
public int processX(NodeComponent bindCmp){
return 3;

View File

@ -19,4 +19,24 @@
<chain name="chain5">
WHILE(z).DO(THEN(a,d)).BREAK(y);
</chain>
<chain name="chain6">
FOR(5).DO(
WHEN(
THEN(a,e.tag("e1")),
THEN(c,e.tag("e2")),
THEN(b,e.tag("e3"))
)
);
</chain>
<chain name="chain7">
WHILE(z).DO(
WHEN(
THEN(d, e.tag("e1")),
THEN(a, e.tag("e2")),
THEN(c, e.tag("e3"))
)
);
</chain>
</flow>

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.test.loop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
@ -66,4 +67,26 @@ public class LoopELDeclSpringbootTest extends BaseTest {
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr());
}
//测试FOR循环中的index
@Test
public void testLoop6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
//测试WHILE循环中的index
@Test
public void testLoop7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
}

View File

@ -0,0 +1,33 @@
/**
* <p>Title: liteflow</p>
* <p>Description: 轻量级的组件式流程框架</p>
* @author Bryan.Zhang
* @email weenyc31@163.com
* @Date 2020/4/1
*/
package com.yomahub.liteflow.test.loop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("e")
public class ECmp{
@LiteflowMethod(LiteFlowMethodEnum.PROCESS)
public void process(NodeComponent bindCmp) {
DefaultContext context = bindCmp.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", bindCmp.getTag());
if (context.hasData(key)){
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, bindCmp.getLoopIndex());
context.setData(key, loopStrReturn);
}else{
context.setData(key, bindCmp.getLoopIndex().toString());
}
}
}

View File

@ -19,4 +19,24 @@
<chain name="chain5">
WHILE(z).DO(THEN(a,d)).BREAK(y);
</chain>
<chain name="chain6">
FOR(5).DO(
WHEN(
THEN(a,e.tag("e1")),
THEN(c,e.tag("e2")),
THEN(b,e.tag("e3"))
)
);
</chain>
<chain name="chain7">
WHILE(z).DO(
WHEN(
THEN(d, e.tag("e1")),
THEN(a, e.tag("e2")),
THEN(c, e.tag("e3"))
)
);
</chain>
</flow>

View File

@ -4,6 +4,7 @@ import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.FlowExecutorHolder;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.property.LiteflowConfig;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.BeforeClass;
@ -58,4 +59,26 @@ public class LoopTest extends BaseTest{
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr());
}
//测试FOR循环中的index
@Test
public void testLoop6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
//测试WHILE循环中的index
@Test
public void testLoop7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
}

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.loop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
public class ECmp extends NodeComponent {
@Override
public void process() {
DefaultContext context = this.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", this.getTag());
if (context.hasData(key)){
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, this.getLoopIndex());
context.setData(key, loopStrReturn);
}else{
context.setData(key, this.getLoopIndex().toString());
}
}
}

View File

@ -5,6 +5,7 @@
<node id="b" class="com.yomahub.liteflow.test.loop.cmp.BCmp"/>
<node id="c" class="com.yomahub.liteflow.test.loop.cmp.CCmp"/>
<node id="d" class="com.yomahub.liteflow.test.loop.cmp.DCmp"/>
<node id="e" class="com.yomahub.liteflow.test.loop.cmp.ECmp"/>
<node id="x" class="com.yomahub.liteflow.test.loop.cmp.XCmp"/>
<node id="y" class="com.yomahub.liteflow.test.loop.cmp.YCmp"/>
<node id="z" class="com.yomahub.liteflow.test.loop.cmp.ZCmp"/>
@ -29,4 +30,24 @@
<chain name="chain5">
WHILE(z).DO(THEN(a,d)).BREAK(y);
</chain>
<chain name="chain6">
FOR(5).DO(
WHEN(
THEN(a, e.tag("e1")),
THEN(c, e.tag("e2")),
THEN(b, e.tag("e3"))
)
);
</chain>
<chain name="chain7">
WHILE(z).DO(
WHEN(
THEN(d, e.tag("e1")),
THEN(a, e.tag("e2")),
THEN(c, e.tag("e3"))
)
);
</chain>
</flow>

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.test.loop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
@ -66,4 +67,26 @@ public class LoopELSpringbootTest extends BaseTest {
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr());
}
//测试FOR循环中的index
@Test
public void testLoop6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
//测试WHILE循环中的index
@Test
public void testLoop7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
}

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.loop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("e")
public class ECmp extends NodeComponent {
@Override
public void process() {
DefaultContext context = this.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", this.getTag());
if (context.hasData(key)){
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, this.getLoopIndex());
context.setData(key, loopStrReturn);
}else{
context.setData(key, this.getLoopIndex().toString());
}
}
}

View File

@ -19,4 +19,24 @@
<chain name="chain5">
WHILE(z).DO(THEN(a,d)).BREAK(y);
</chain>
<chain name="chain6">
FOR(5).DO(
WHEN(
THEN(a,e.tag("e1")),
THEN(c,e.tag("e2")),
THEN(b,e.tag("e3"))
)
);
</chain>
<chain name="chain7">
WHILE(z).DO(
WHEN(
THEN(d, e.tag("e1")),
THEN(a, e.tag("e2")),
THEN(c, e.tag("e3"))
)
);
</chain>
</flow>

View File

@ -2,6 +2,7 @@ package com.yomahub.liteflow.test.loop;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.slot.DefaultContext;
import com.yomahub.liteflow.test.BaseTest;
import org.junit.Assert;
import org.junit.Test;
@ -56,4 +57,26 @@ public class LoopELSpringTest extends BaseTest {
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y==>z==>a==>d==>y", response.getExecuteStepStr());
}
//测试FOR循环中的index
@Test
public void testLoop6() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain6", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
//测试WHILE循环中的index
@Test
public void testLoop7() throws Exception{
LiteflowResponse response = flowExecutor.execute2Resp("chain7", "arg");
DefaultContext context = response.getFirstContextBean();
Assert.assertTrue(response.isSuccess());
Assert.assertEquals("01234", context.getData("loop_e1"));
Assert.assertEquals("01234", context.getData("loop_e2"));
Assert.assertEquals("01234", context.getData("loop_e3"));
}
}

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.loop.cmp;
import cn.hutool.core.util.StrUtil;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.slot.DefaultContext;
import org.springframework.stereotype.Component;
@Component("e")
public class ECmp extends NodeComponent {
@Override
public void process() {
DefaultContext context = this.getFirstContextBean();
String key = StrUtil.format("{}_{}", "loop", this.getTag());
if (context.hasData(key)){
String loopStr = context.getData(key);
String loopStrReturn = StrUtil.format("{}{}", loopStr, this.getLoopIndex());
context.setData(key, loopStrReturn);
}else{
context.setData(key, this.getLoopIndex().toString());
}
}
}

View File

@ -19,4 +19,24 @@
<chain name="chain5">
WHILE(z).DO(THEN(a,d)).BREAK(y);
</chain>
<chain name="chain6">
FOR(5).DO(
WHEN(
THEN(a,e.tag("e1")),
THEN(c,e.tag("e2")),
THEN(b,e.tag("e3"))
)
);
</chain>
<chain name="chain7">
WHILE(z).DO(
WHEN(
THEN(d, e.tag("e1")),
THEN(a, e.tag("e2")),
THEN(c, e.tag("e3"))
)
);
</chain>
</flow>