From 4b7e0966009663acf34cd12fa442886653c065d3 Mon Sep 17 00:00:00 2001 From: PTYin Date: Tue, 11 Jul 2023 14:09:01 +0800 Subject: [PATCH 01/10] feature: stream-based saga state machine orchestration --- .../statelang/builder/BuildException.java | 26 +++++++ .../statelang/builder/ChoiceStateBuilder.java | 13 ++++ .../builder/ScriptTaskStateBuilder.java | 11 +++ .../builder/ServiceTaskStateBuilder.java | 28 ++++++++ .../saga/statelang/builder/StateBuilder.java | 51 +++++++++++++ .../builder/StateBuilderFactory.java | 45 ++++++++++++ .../builder/StateMachineBuilder.java | 72 +++++++++++++++++++ .../statelang/builder/StatesConfigurer.java | 35 +++++++++ .../builder/impl/BaseStateBuilder.java | 71 ++++++++++++++++++ .../builder/impl/ChoiceStateBuilderImpl.java | 58 +++++++++++++++ .../impl/ServiceTaskStateBuilderImpl.java | 55 ++++++++++++++ .../builder/impl/StateMachineBuilderImpl.java | 69 ++++++++++++++++++ .../builder/impl/StatesConfigurerImpl.java | 68 ++++++++++++++++++ .../statelang/builder/StateBuilderTests.java | 55 ++++++++++++++ 14 files changed, 657 insertions(+) create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java create mode 100644 saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java new file mode 100644 index 00000000000..e435c4e51d5 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +/** + * Build exception. + * + * @author ptyin + */ +public class BuildException extends RuntimeException { + +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java new file mode 100644 index 00000000000..78a2aa02cee --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java @@ -0,0 +1,13 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.ChoiceState; + +/*** + * + * @author ptyin + */ +public interface ChoiceStateBuilder extends StateBuilder { + + ChoiceStateBuilder put(String expression, String next); + +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java new file mode 100644 index 00000000000..822bc87a59f --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java @@ -0,0 +1,11 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.ScriptTaskState; + +/*** + * + * @author ptyin + */ +public interface ScriptTaskStateBuilder extends StateBuilder +{ +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java new file mode 100644 index 00000000000..6f1796674c7 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java @@ -0,0 +1,28 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.ServiceTaskState; + +/*** + * + * @author ptyin + */ +public interface ServiceTaskStateBuilder extends StateBuilder +{ + + /** + * Configure service method. + * + * @param serviceName name of service bean + * @return builder for chaining + */ + ServiceTaskStateBuilder withServiceName(String serviceName); + + + /** + * Configure service method. + * + * @param serviceMethod method of service bean + * @return builder for chaining + */ + ServiceTaskStateBuilder withServiceMethod(String serviceMethod); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java new file mode 100644 index 00000000000..f3deee0c62a --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java @@ -0,0 +1,51 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.State; + +/*** + * Configure transitions for {@link StateMachineBuilder}. + * + * @param builder type + * @param state type + * @author PTYin + */ +public interface StateBuilder, S extends State> +{ + /** + * Configure name. + * + * @param name name of state + * @return builder for chaining + */ + B withName(String name); + + /** + * Configure comment. + * + * @param comment comment of state + * @return builder for chaining + */ + B withComment(String comment); + + /** + * Configure next state. + * + * @param next next state + * @return builder for chaining + */ + B withNext(String next); + + /** + * Build a state. + * + * @return built state + */ + S build(); + + /** + * Get the working {@link StatesConfigurer} parent. + * + * @return parent + */ + StatesConfigurer and(); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java new file mode 100644 index 00000000000..ef688ee917a --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.impl.ChoiceStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.ServiceTaskStateBuilderImpl; +import io.seata.saga.statelang.domain.State; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * State builder factory. + * + * @author ptyin + */ +public class StateBuilderFactory { + protected static Map>, Class>> stateBuilderMap = + new ConcurrentHashMap<>(); + + static { + stateBuilderMap.put(ServiceTaskStateBuilder.class, ServiceTaskStateBuilderImpl.class); + stateBuilderMap.put(ChoiceStateBuilder.class, ChoiceStateBuilderImpl.class); + } + + public static StateBuilder getStateBuilder(Class> clazz) + throws InstantiationException, IllegalAccessException { + Class> implClazz = stateBuilderMap.getOrDefault(clazz, clazz); + return implClazz.newInstance(); + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java new file mode 100644 index 00000000000..ec6defdcbac --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java @@ -0,0 +1,72 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.StateMachine; + +/** + * A Java stream-based {@link StateMachine} builder. + * + * @author PTYin + */ +public interface StateMachineBuilder +{ + /** + * Build a state machine + * + * @return built state machine + */ + StateMachine build(); + + /** + * Configure states. + * + * @return configurer for states + */ + StatesConfigurer withStates(); + + /** + * Configure name. + * + * @param name name of state machine + * @return builder for chaining + */ + StateMachineBuilder withName(String name); + + /** + * Configure comment. + * + * @param comment comment of state machine + * @return builder for chaining + */ + StateMachineBuilder withComment(String comment); + + /** + * Configure version. + * + * @param version version of state machine + * @return builder for chaining + */ + StateMachineBuilder withVersion(String version); + + /** + * Configure start state. + * + * @param stateName initial state name of state machine + * @return builder for chaining + */ + StateMachineBuilder withStartState(String stateName); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java new file mode 100644 index 00000000000..49789a2fc64 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java @@ -0,0 +1,35 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.domain.State; + +/*** + * Configure states for {@link StateMachineBuilder}. + * + * @author PTYin + */ +public interface StatesConfigurer +{ + /** + * Build a state {@link State}. + * + * @param clazz specific builder class + * @param builder type + * @return builder for chaining + */ + > B build(Class clazz); + + /** + * Add a built state + * + * @param state a built state {@link State} + * @return configurer for chaining + */ + StatesConfigurer add(State state); + + /** + * Configure all built states. + * + * @return the working {@link StateMachineBuilder} parent + */ + StateMachineBuilder configure(); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java new file mode 100644 index 00000000000..9863e37c781 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java @@ -0,0 +1,71 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.StateBuilder; +import io.seata.saga.statelang.builder.StatesConfigurer; +import io.seata.saga.statelang.domain.State; +import io.seata.saga.statelang.domain.impl.BaseState; + +/** + * Base state builder to inherit. + * + * @param builder type + * @param state type + * @author ptyin + */ +public abstract class BaseStateBuilder, S extends State> + implements StateBuilder { + private StatesConfigurer parent; + + @Override + public B withName(String name) { + ((BaseState) getState()).setName(name); + return getBuilder(); + } + + @Override + public B withComment(String comment) { + ((BaseState) getState()).setComment(comment); + return getBuilder(); + } + + @Override + public B withNext(String next) { + ((BaseState) getState()).setNext(next); + return getBuilder(); + } + + @Override + public S build() { + return getState(); + } + + @Override + public StatesConfigurer and() { + parent.add(getState()); + return parent; + } + + public void setParent(StatesConfigurer parent) { + this.parent = parent; + } + + protected abstract B getBuilder(); + + protected abstract S getState(); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java new file mode 100644 index 00000000000..706c5a31300 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.ChoiceStateBuilder; +import io.seata.saga.statelang.domain.ChoiceState; +import io.seata.saga.statelang.domain.impl.ChoiceStateImpl; + +import java.util.ArrayList; + +/** + * Default implementation for {@link ChoiceStateBuilder} + * + * @author ptyin + */ +public class ChoiceStateBuilderImpl + extends BaseStateBuilder + implements ChoiceStateBuilder { + + protected ChoiceStateImpl state = new ChoiceStateImpl(); + + public ChoiceStateBuilderImpl() { + state.setChoices(new ArrayList<>()); + } + + @Override + public ChoiceStateBuilder put(String expression, String next) { + ChoiceStateImpl.ChoiceImpl choice = new ChoiceStateImpl.ChoiceImpl(); + choice.setExpression(expression); + choice.setNext(next); + state.getChoices().add(choice); + return this; + } + + @Override + protected ChoiceStateBuilder getBuilder() { + return this; + } + + @Override + protected ChoiceState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java new file mode 100644 index 00000000000..19f7797fef9 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.ServiceTaskStateBuilder; +import io.seata.saga.statelang.domain.ServiceTaskState; +import io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl; + +/** + * Default implementation for {@link ServiceTaskStateBuilder} + * + * @author ptyin + */ +public class ServiceTaskStateBuilderImpl + extends BaseStateBuilder + implements ServiceTaskStateBuilder { + + protected ServiceTaskStateImpl state = new ServiceTaskStateImpl(); + + @Override + public ServiceTaskStateBuilder withServiceName(String serviceName) { + state.setServiceName(serviceName); + return this; + } + + @Override + public ServiceTaskStateBuilder withServiceMethod(String serviceMethod) { + state.setServiceMethod(serviceMethod); + return this; + } + + @Override + protected ServiceTaskStateBuilder getBuilder() { + return this; + } + + @Override + protected ServiceTaskState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java new file mode 100644 index 00000000000..c8213d5d024 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.StateMachineBuilder; +import io.seata.saga.statelang.builder.StatesConfigurer; +import io.seata.saga.statelang.domain.StateMachine; +import io.seata.saga.statelang.domain.impl.StateMachineImpl; + +/** + * Default implementation for {@link StateMachineBuilder}. + * + * @author ptyin + */ +public class StateMachineBuilderImpl implements StateMachineBuilder { + + private final StateMachineImpl stateMachine = new StateMachineImpl(); + + @Override + public StateMachine build() { + return stateMachine; + } + + @Override + public StatesConfigurer withStates() { + StatesConfigurerImpl statesConfigurer = new StatesConfigurerImpl(); + statesConfigurer.setParent(this); + statesConfigurer.setStateMachine(stateMachine); + return statesConfigurer; + } + + @Override + public StateMachineBuilder withName(String name) { + stateMachine.setName(name); + return this; + } + + @Override + public StateMachineBuilder withComment(String comment) { + stateMachine.setComment(comment); + return this; + } + + @Override + public StateMachineBuilder withVersion(String version) { + stateMachine.setVersion(version); + return this; + } + + @Override + public StateMachineBuilder withStartState(String stateName) { + stateMachine.setStartState(stateName); + return this; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java new file mode 100644 index 00000000000..684013bbbb2 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.common.exception.FrameworkException; +import io.seata.saga.statelang.builder.*; +import io.seata.saga.statelang.domain.State; +import io.seata.saga.statelang.domain.impl.StateMachineImpl; + +/** + * Default implementation for {@link StatesConfigurer}. + * + * @author ptyin + */ +public class StatesConfigurerImpl implements StatesConfigurer { + + private StateMachineBuilder parent; + + private StateMachineImpl stateMachine; + + @Override + @SuppressWarnings("unchecked") + public > B build(Class clazz) { + B builder; + try { + builder = (B) StateBuilderFactory.getStateBuilder(clazz); + } catch (InstantiationException | IllegalAccessException e) { + throw new FrameworkException(e, "Given builder class is inappropriate or not implemented yet."); + } catch (ClassCastException e) { + throw new FrameworkException(e, "StateBuilderFactory got a wrong state builder."); + } + ((BaseStateBuilder) builder).setParent(this); + return builder; + } + + @Override + public StatesConfigurer add(State state) { + stateMachine.putState(state.getName(), state); + return this; + } + + @Override + public StateMachineBuilder configure() { + return parent; + } + + public void setParent(StateMachineBuilder parent) { + this.parent = parent; + } + + public void setStateMachine(StateMachineImpl stateMachine) { + this.stateMachine = stateMachine; + } +} diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java new file mode 100644 index 00000000000..14923f256b2 --- /dev/null +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.ChoiceStateBuilder; +import io.seata.saga.statelang.builder.ServiceTaskStateBuilder; +import io.seata.saga.statelang.builder.StateMachineBuilder; +import io.seata.saga.statelang.builder.impl.StateMachineBuilderImpl; +import io.seata.saga.statelang.domain.StateMachine; +import org.junit.jupiter.api.Test; + +/** + * Java stream-based builder tests. + * + * @author lorne.cl + */ +public class StateBuilderTests { + @Test + void testBuildStateMachine() { + StateMachineBuilder stateMachineBuilder = new StateMachineBuilderImpl(); + StateMachine stateMachine = stateMachineBuilder + .withName("simpleTestStateMachine") + .withComment("测试状态机定义") + .withVersion("0.0.2") + .withStartState("FirstState") + .withStates() + .build(ServiceTaskStateBuilder.class) + .withName("FirstState") + .withServiceName("demoService") + .withServiceMethod("foo") + .withNext("ChoiceState") + .and() + .build(ChoiceStateBuilder.class) + .withName("ChoiceState") + .put("[a] == 1", "SecondState") + .put("[a] == 2", "ThirdState") + .and() + .configure() + .build(); + System.out.println(stateMachine); + } +} From 758e44a41fb9c7ba3565073d9c92e58e05ba33c9 Mon Sep 17 00:00:00 2001 From: PTYin Date: Mon, 17 Jul 2023 16:13:46 +0800 Subject: [PATCH 02/10] optimize: add TaskStateBuilder --- .../saga/statelang/builder/StateBuilder.java | 2 +- .../statelang/builder/TaskStateBuilder.java | 50 +++++++++++++++++++ .../statelang/builder/StateBuilderTests.java | 3 +- .../saga/statelang/simple_statelang.json | 18 +++++-- 4 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java index f3deee0c62a..2da8672fa57 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java @@ -7,7 +7,7 @@ * * @param builder type * @param state type - * @author PTYin + * @author ptyin */ public interface StateBuilder, S extends State> { diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java new file mode 100644 index 00000000000..a162553d69e --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import java.util.Collection; +import java.util.List; + +/*** + * Task state builder. + * + * @param builder type + * @author ptyin + */ +public interface TaskStateBuilder> { + B withCompensationState(String compensationState); + + B withForCompensation(boolean forCompensation); + + B withForUpdate(boolean forUpdate); + + RetryBuilder withRetry(); + + interface RetryBuilder { + RetryBuilder withExceptions(Collection> exceptions); + + RetryBuilder withIntervalSeconds(double intervalSeconds); + + RetryBuilder withMaxAttempts(int maxAttempts); + + RetryBuilder withBackoffRate(double backoffRate); + } + + interface ExceptionMatchBuilder { + + } +} diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java index 14923f256b2..4bba6e42543 100644 --- a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -20,6 +20,7 @@ import io.seata.saga.statelang.builder.StateMachineBuilder; import io.seata.saga.statelang.builder.impl.StateMachineBuilderImpl; import io.seata.saga.statelang.domain.StateMachine; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** @@ -50,6 +51,6 @@ void testBuildStateMachine() { .and() .configure() .build(); - System.out.println(stateMachine); + Assertions.assertNotNull(stateMachine); } } diff --git a/test/src/test/resources/saga/statelang/simple_statelang.json b/test/src/test/resources/saga/statelang/simple_statelang.json index 14e52f4c6cc..cfe9573bff9 100644 --- a/test/src/test/resources/saga/statelang/simple_statelang.json +++ b/test/src/test/resources/saga/statelang/simple_statelang.json @@ -8,12 +8,20 @@ "Type": "ServiceTask", "ServiceName": "demoService", "ServiceMethod": "foo", - "Next": "SecondState" + "Next": "ChoiceState" }, - "SecondState": { - "Type": "ServiceTask", - "ServiceName": "demoService", - "ServiceMethod": "bar" + "ChoiceState": { + "Type": "Choice", + "Choices": [ + { + "Expression":"[a] == 1", + "Next":"SecondState" + }, + { + "Expression":"[a] == 2", + "Next":"ThirdState" + } + ] } } } \ No newline at end of file From e4209a46dd0d4ddbc13df187eafff68c433bdb3f Mon Sep 17 00:00:00 2001 From: PTYin Date: Fri, 8 Sep 2023 22:24:58 +0800 Subject: [PATCH 03/10] optimize: add task state attribute builder --- .../statelang/builder/ChoiceStateBuilder.java | 16 +- .../builder/ScriptTaskStateBuilder.java | 5 +- .../builder/ServiceTaskStateBuilder.java | 4 +- .../statelang/builder/TaskStateBuilder.java | 200 ++++++++++++++- .../impl/AbstractTaskStateBuilder.java | 236 ++++++++++++++++++ .../builder/impl/ChoiceStateBuilderImpl.java | 8 +- .../statelang/builder/StateBuilderTests.java | 4 +- 7 files changed, 461 insertions(+), 12 deletions(-) create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java index 78a2aa02cee..c31d64666f7 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java @@ -8,6 +8,20 @@ */ public interface ChoiceStateBuilder extends StateBuilder { - ChoiceStateBuilder put(String expression, String next); + /** + * Put (expression, next state) pair into choices. + * + * @param expression expression to evaluate + * @param next name of next state + * @return builder for chaining + */ + ChoiceStateBuilder withChoice(String expression, String next); + /** + * Configure default choice when no valid choices. + * + * @param defaultChoice default choice + * @return builder for chaining + */ + ChoiceStateBuilder withDefault(String defaultChoice); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java index 822bc87a59f..71de93b1347 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java @@ -6,6 +6,7 @@ * * @author ptyin */ -public interface ScriptTaskStateBuilder extends StateBuilder -{ +public interface ScriptTaskStateBuilder extends StateBuilder, + TaskStateBuilder { + } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java index 6f1796674c7..3831c43bf2c 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java @@ -6,8 +6,8 @@ * * @author ptyin */ -public interface ServiceTaskStateBuilder extends StateBuilder -{ +public interface ServiceTaskStateBuilder extends StateBuilder, + TaskStateBuilder { /** * Configure service method. diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java index a162553d69e..f468f1b175f 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java @@ -17,7 +17,6 @@ package io.seata.saga.statelang.builder; import java.util.Collection; -import java.util.List; /*** * Task state builder. @@ -26,25 +25,218 @@ * @author ptyin */ public interface TaskStateBuilder> { + /** + * Configure compensation state. + * + * @param compensationState name of compensation state + * @return builder for chaining + */ B withCompensationState(String compensationState); + /** + * Configure if this state is used to compensate another state. + * + * @param forCompensation if is for compensation or not + * @return builder for chaining + */ B withForCompensation(boolean forCompensation); + /** + * Configure if this state will update data + * + * @param forUpdate if is for update + * @return builder for chaining + */ B withForUpdate(boolean forUpdate); - RetryBuilder withRetry(); + /** + * Configure retry strategy. If the state has multiple retry strategies, use following way to build: + *
+     * {@code
+     * stateBuilder
+     *     .withRetry()
+     *         .withExceptions(Arrays.asList(IllegalArgumentException.class))
+     *         .withIntervalSeconds(1)
+     *         .and()
+     *     .withRetry()
+     *         .withExceptions(Arrays.asList(NullPointerException.class))
+     *         .withIntervalSeconds(10)
+     * // ...
+     * }
+     * 
+ * + * @return retry builder + */ + RetryBuilder withOneRetry(); - interface RetryBuilder { + /** + * Configure exception catching rules. If the state has multiple catching rules, use following way to build: + *
+     * {@code
+     * stateBuilder
+     *     .withCatches()
+     *         .withExceptions(Arrays.asList(IllegalArgumentException.class))
+     *         .withIntervalSeconds(1)
+     *         .and()
+     *     .withCatches()
+     *         .withExceptions(Arrays.asList(NullPointerException.class))
+     *         .withIntervalSeconds(10)
+     * // ...
+     * }
+     * 
+ * + * @return exception match builder + */ + ExceptionMatchBuilder withOneCatch(); + + /** + * Configure execution status. + * + * @param expression expression to evaluated + * @param status matched status + * @return builder for chaining + */ + B withOneStatus(String expression, String status); + + /** + * Configure loop strategy. + * + * @return builder for chaining + */ + LoopBuilder withLoop(); + + interface ChildBuilder { + /** + * Return parent builder + * + * @return parent builder + */ + B and(); + } + + interface RetryBuilder extends ChildBuilder { + /** + * Configure exception classes to capture + * + * @param exceptions exception classes + * @return retry builder for chaining + */ RetryBuilder withExceptions(Collection> exceptions); + /** + * Configure interval + * + * @param intervalSeconds interval in seconds + * @return retry builder for chaining + */ RetryBuilder withIntervalSeconds(double intervalSeconds); + /** + * Configure max attempts + * + * @param maxAttempts max count of attempts + * @return retry builder for chaining + */ RetryBuilder withMaxAttempts(int maxAttempts); + /** + * Configure backoff rate + * + * @param backoffRate backoff rate + * @return retry builder for chaining + */ RetryBuilder withBackoffRate(double backoffRate); } - interface ExceptionMatchBuilder { + interface ExceptionMatchBuilder extends ChildBuilder { + /** + * Configure exception classes to capture. + * + * @param exceptions exception classes + * @return exception match builder for chaining + */ + ExceptionMatchBuilder withExceptions(Collection> exceptions); + + /** + * Configure next state when exception matched. + * + * @param next name of next state + * @return exception match builder for chaining + */ + ExceptionMatchBuilder withNext(String next); + } + + interface LoopBuilder extends ChildBuilder { + /** + * Configure max parallelism. + * + * @param parallel max parallelism, i.e. max count of threads at a specific moment + * @return loop builder for chaining + */ + LoopBuilder withParallel(int parallel); + + /** + * Configure collection object name. + * + * @param collection collection name + * @return loop builder for chaining + */ + LoopBuilder withCollection(String collection); + + /** + * Configure element variable name. + * + * @param elementVariableName element variable name + * @return loop builder for chaining + */ + LoopBuilder withElementVariableName(String elementVariableName); + + /** + * Configure element variable index name, default loopCounter. + * + * @param elementIndexName element index name + * @return loop builder for chaining + */ + LoopBuilder withElementIndexName(String elementIndexName); + + /** + * Configure completion condition, default nrOfInstances == nrOfCompletedInstances. + * + * @param completionCondition completion condition + * @return loop builder for chaining + */ + LoopBuilder withCompletionCondition(String completionCondition); + + /** + * Configure the name of loop result, default loopResult. + * + * @param resultName result name + * @return loop builder for chaining + */ + LoopBuilder withResultName(String resultName); + + /** + * Configure the name of number of instances, default nrOfInstances. + * + * @param numberOfInstancesName the name of number of instances + * @return loop builder for chaining + */ + LoopBuilder withNumberOfInstancesName(String numberOfInstancesName); + + /** + * Configure the name of number of active instances, default nrOfActiveInstances. + * + * @param numberOfActiveInstancesName the name of number of active instances + * @return loop builder for chaining + */ + LoopBuilder withNumberOfActiveInstancesName(String numberOfActiveInstancesName); + /** + * Configure the name of number of active instances, default nrOfCompletedInstances. + * + * @param numberOfCompletedInstancesName the number of completed instances name + * @return loop builder for chaining + */ + LoopBuilder withNumberOfCompletedInstancesName(String numberOfCompletedInstancesName); } } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java new file mode 100644 index 00000000000..ff39ba59578 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java @@ -0,0 +1,236 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.StateBuilder; +import io.seata.saga.statelang.builder.TaskStateBuilder; +import io.seata.saga.statelang.domain.State; +import io.seata.saga.statelang.domain.impl.AbstractTaskState; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.stream.Collectors; + +/** + * Abstract task state builder to inherit. + * + * @param builder type + * @param state type + * @author ptyin + */ +public abstract class AbstractTaskStateBuilder & StateBuilder, S extends State> + extends BaseStateBuilder implements TaskStateBuilder { + + protected AbstractTaskState state; + + public AbstractTaskStateBuilder() { + state = (AbstractTaskState) getState(); + // Do some default setup + state.setForCompensation(false); + state.setForUpdate(false); + state.setRetryPersistModeUpdate(false); + state.setCompensatePersistModeUpdate(false); + + state.setPersist(true); + } + + @Override + public B withCompensationState(String compensationState) { + state.setCompensateState(compensationState); + return getBuilder(); + } + + @Override + public B withForCompensation(boolean forCompensation) { + state.setForUpdate(forCompensation); + return getBuilder(); + } + + @Override + public B withForUpdate(boolean forUpdate) { + state.setForUpdate(forUpdate); + return getBuilder(); + } + + @Override + public RetryBuilder withOneRetry() { + return new RetryBuilderImpl(); + } + + @Override + public ExceptionMatchBuilder withOneCatch() { + return new ExceptionMatchBuilderImpl(); + } + + @Override + public B withOneStatus(String expression, String status) { + if (state.getStatus() == null) { + state.setStatus(new HashMap<>()); + } + state.getStatus().put(expression, status); + return getBuilder(); + } + + @Override + public LoopBuilder withLoop() { + return new LoopBuilderImpl(); + } + + public class RetryBuilderImpl implements TaskStateBuilder.RetryBuilder { + + private final AbstractTaskState.RetryImpl oneRetry = new AbstractTaskState.RetryImpl(); + + @Override + public B and() { + if (state.getRetry() == null) { + state.setRetry(new ArrayList<>()); + } + state.getRetry().add(oneRetry); + return getBuilder(); + } + + @Override + public RetryBuilder withExceptions(Collection> exceptions) { + oneRetry.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); + oneRetry.setExceptionClasses(new ArrayList<>(exceptions)); + return this; + } + + @Override + public RetryBuilder withIntervalSeconds(double intervalSeconds) { + oneRetry.setIntervalSeconds(intervalSeconds); + return this; + } + + @Override + public RetryBuilder withMaxAttempts(int maxAttempts) { + oneRetry.setMaxAttempts(maxAttempts); + return this; + } + + @Override + public RetryBuilder withBackoffRate(double backoffRate) { + oneRetry.setBackoffRate(backoffRate); + return this; + } + } + + public class ExceptionMatchBuilderImpl implements TaskStateBuilder.ExceptionMatchBuilder { + + private final AbstractTaskState.ExceptionMatchImpl oneCatch = new AbstractTaskState.ExceptionMatchImpl(); + + @Override + public B and() { + if (state.getCatches() == null) { + state.setCatches(new ArrayList<>()); + } + state.getCatches().add(oneCatch); + return getBuilder(); + } + + @Override + public ExceptionMatchBuilder withExceptions(Collection> exceptions) { + oneCatch.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); + oneCatch.setExceptionClasses(new ArrayList<>(exceptions)); + return this; + } + + @Override + public ExceptionMatchBuilder withNext(String next) { + oneCatch.setNext(next); + return this; + } + } + + public class LoopBuilderImpl implements LoopBuilder { + + private final AbstractTaskState.LoopImpl loop = new AbstractTaskState.LoopImpl(); + + public LoopBuilderImpl() { + // Do some default setup + loop.setParallel(1); + loop.setElementVariableName("loopElement"); + loop.setElementIndexName("loopCounter"); + loop.setResultName("loopResult"); + loop.setNumberOfInstancesName("nrOfInstances"); + loop.setNumberOfActiveInstancesName("nrOfActiveInstances"); + loop.setNumberOfCompletedInstancesName("nrOfCompletedInstances"); + loop.setCompletionCondition("[nrOfInstances] == [nrOfCompletedInstances]"); + } + + @Override + public B and() { + state.setLoop(loop); + return getBuilder(); + } + + @Override + public LoopBuilder withParallel(int parallel) { + loop.setParallel(parallel); + return this; + } + + @Override + public LoopBuilder withCollection(String collection) { + loop.setCollection(collection); + return this; + } + + @Override + public LoopBuilder withElementVariableName(String elementVariableName) { + loop.setElementVariableName(elementVariableName); + return this; + } + + @Override + public LoopBuilder withElementIndexName(String elementIndexName) { + loop.setElementIndexName(elementIndexName); + return this; + } + + @Override + public LoopBuilder withCompletionCondition(String completionCondition) { + loop.setCompletionCondition(completionCondition); + return this; + } + + @Override + public LoopBuilder withResultName(String resultName) { + loop.setResultName(resultName); + return this; + } + + @Override + public LoopBuilder withNumberOfInstancesName(String numberOfInstancesName) { + loop.setNumberOfInstancesName(numberOfInstancesName); + return this; + } + + @Override + public LoopBuilder withNumberOfActiveInstancesName(String numberOfActiveInstancesName) { + loop.setNumberOfActiveInstancesName(numberOfActiveInstancesName); + return this; + } + + @Override + public LoopBuilder withNumberOfCompletedInstancesName(String numberOfCompletedInstancesName) { + loop.setNumberOfCompletedInstancesName(numberOfCompletedInstancesName); + return this; + } + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java index 706c5a31300..6840772900a 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java @@ -38,7 +38,7 @@ public ChoiceStateBuilderImpl() { } @Override - public ChoiceStateBuilder put(String expression, String next) { + public ChoiceStateBuilder withChoice(String expression, String next) { ChoiceStateImpl.ChoiceImpl choice = new ChoiceStateImpl.ChoiceImpl(); choice.setExpression(expression); choice.setNext(next); @@ -46,6 +46,12 @@ public ChoiceStateBuilder put(String expression, String next) { return this; } + @Override + public ChoiceStateBuilder withDefault(String defaultChoice) { + state.setDefaultChoice(defaultChoice); + return this; + } + @Override protected ChoiceStateBuilder getBuilder() { return this; diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java index 4bba6e42543..1390bdde45e 100644 --- a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -46,8 +46,8 @@ void testBuildStateMachine() { .and() .build(ChoiceStateBuilder.class) .withName("ChoiceState") - .put("[a] == 1", "SecondState") - .put("[a] == 2", "ThirdState") + .withChoice("[a] == 1", "SecondState") + .withChoice("[a] == 2", "ThirdState") .and() .configure() .build(); From 781c880b8d1c83af9bdc3195712bbe9445fc537b Mon Sep 17 00:00:00 2001 From: PTYin Date: Mon, 11 Sep 2023 16:01:15 +0800 Subject: [PATCH 04/10] optimize: complete all stream-based state builder --- .../statelang/builder/BuildException.java | 5 + .../statelang/builder/ChoiceStateBuilder.java | 24 ++--- ...CompensateSubStateMachineStateBuilder.java | 19 ++++ .../CompensationTriggerStateBuilder.java | 30 ++++++ .../builder/FailEndStateBuilder.java | 32 +++++++ .../statelang/builder/ForkStateBuilder.java | 32 +++++++ .../statelang/builder/JoinStateBuilder.java | 30 ++++++ .../builder/ScriptTaskStateBuilder.java | 11 ++- .../builder/ServiceTaskStateBuilder.java | 27 ++---- .../saga/statelang/builder/StateBuilder.java | 32 +------ .../builder/StateBuilderFactory.java | 26 +++-- .../statelang/builder/StatesConfigurer.java | 2 +- .../builder/SubStateMachineBuilder.java | 35 +++++++ .../builder/SuccessEndStateBuilder.java | 30 ++++++ .../impl/AbstractServiceTaskStateBuilder.java | 68 +++++++++++++ .../impl/AbstractTaskStateBuilder.java | 96 ++++++++++--------- .../builder/impl/BaseStateBuilder.java | 13 +-- .../builder/impl/ChoiceStateBuilderImpl.java | 2 +- ...ensateSubStateMachineStateBuilderImpl.java | 46 +++++++++ .../CompensationTriggerStateBuilderImpl.java | 43 +++++++++ .../builder/impl/FailEndStateBuilderImpl.java | 55 +++++++++++ .../builder/impl/ForkStateBuilderImpl.java | 73 ++++++++++++++ .../builder/impl/JoinStateBuilderImpl.java | 43 +++++++++ .../impl/ScriptTaskStateBuilderImpl.java | 58 +++++++++++ .../impl/ServiceTaskStateBuilderImpl.java | 21 ++-- .../builder/impl/StatesConfigurerImpl.java | 4 +- .../impl/SubStateMachineBuilderImpl.java | 52 ++++++++++ .../impl/SuccessEndStateBuilderImpl.java | 43 +++++++++ .../builder/prop/BasicPropertyBuilder.java | 49 ++++++++++ .../builder/prop/ChoicePropertyBuilder.java | 42 ++++++++ .../builder/prop/FailEndPropertyBuilder.java | 41 ++++++++ .../builder/prop/ForkPropertyBuilder.java | 51 ++++++++++ .../prop/ScriptTaskPropertyBuilder.java | 41 ++++++++ .../prop/ServiceTaskPropertyBuilder.java | 68 +++++++++++++ .../prop/SubStateMachinePropertyBuilder.java | 33 +++++++ .../TaskPropertyBuilder.java} | 52 +++++----- .../statelang/builder/StateBuilderTests.java | 3 - 37 files changed, 1157 insertions(+), 175 deletions(-) create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensationTriggerStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/FailEndStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ForkStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/JoinStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SubStateMachineBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SuccessEndStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractServiceTaskStateBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensateSubStateMachineStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/FailEndStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/JoinStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SuccessEndStateBuilderImpl.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/BasicPropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ChoicePropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/FailEndPropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ScriptTaskPropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ServiceTaskPropertyBuilder.java create mode 100644 saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/SubStateMachinePropertyBuilder.java rename saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/{TaskStateBuilder.java => prop/TaskPropertyBuilder.java} (76%) diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java index e435c4e51d5..dc0a6bcfe92 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/BuildException.java @@ -22,5 +22,10 @@ * @author ptyin */ public class BuildException extends RuntimeException { + public BuildException() { + } + public BuildException(String message) { + super(message); + } } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java index c31d64666f7..b1f09c22aa3 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java @@ -1,27 +1,17 @@ package io.seata.saga.statelang.builder; +import io.seata.saga.statelang.builder.prop.ChoicePropertyBuilder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; import io.seata.saga.statelang.domain.ChoiceState; /*** + * Choice state builder for {@link ChoiceState} * * @author ptyin */ -public interface ChoiceStateBuilder extends StateBuilder { +public interface ChoiceStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + ChoicePropertyBuilder { - /** - * Put (expression, next state) pair into choices. - * - * @param expression expression to evaluate - * @param next name of next state - * @return builder for chaining - */ - ChoiceStateBuilder withChoice(String expression, String next); - - /** - * Configure default choice when no valid choices. - * - * @param defaultChoice default choice - * @return builder for chaining - */ - ChoiceStateBuilder withDefault(String defaultChoice); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java new file mode 100644 index 00000000000..1badfe6b7ae --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java @@ -0,0 +1,19 @@ +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.ServiceTaskPropertyBuilder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; +import io.seata.saga.statelang.domain.CompensateSubStateMachineState; + +/*** + * Compensate SubStateMachine state builder for {@link CompensateSubStateMachineState}. + * + * @author ptyin + */ +public interface CompensateSubStateMachineStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + TaskPropertyBuilder, + ServiceTaskPropertyBuilder { + +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensationTriggerStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensationTriggerStateBuilder.java new file mode 100644 index 00000000000..7fa94e547c8 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensationTriggerStateBuilder.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.domain.CompensationTriggerState; + +/** + * Compensation trigger state builder for {@link CompensationTriggerState} + * + * @author ptyin + */ +public interface CompensationTriggerStateBuilder extends + StateBuilder, + BasicPropertyBuilder { +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/FailEndStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/FailEndStateBuilder.java new file mode 100644 index 00000000000..3c6dfe4efd8 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/FailEndStateBuilder.java @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.FailEndPropertyBuilder; +import io.seata.saga.statelang.domain.FailEndState; + +/** + * Fail end state builder for {@link FailEndState} + * + * @author ptyin + */ +public interface FailEndStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + FailEndPropertyBuilder { +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ForkStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ForkStateBuilder.java new file mode 100644 index 00000000000..e99500e267e --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ForkStateBuilder.java @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.ForkPropertyBuilder; +import io.seata.saga.statelang.domain.ForkState; + +/** + * Fork state builder for {@link ForkState} + * + * @author ptyin + */ +public interface ForkStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + ForkPropertyBuilder { +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/JoinStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/JoinStateBuilder.java new file mode 100644 index 00000000000..7374a5aed07 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/JoinStateBuilder.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.domain.JoinState; + +/** + * Join state builder for {@link JoinState} + * + * @author ptyin + */ +public interface JoinStateBuilder extends + StateBuilder, + BasicPropertyBuilder { +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java index 71de93b1347..52ec94c88b0 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java @@ -1,12 +1,19 @@ package io.seata.saga.statelang.builder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.ScriptTaskPropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; import io.seata.saga.statelang.domain.ScriptTaskState; /*** + * Script task state builder for {@link ScriptTaskState} * * @author ptyin */ -public interface ScriptTaskStateBuilder extends StateBuilder, - TaskStateBuilder { +public interface ScriptTaskStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + TaskPropertyBuilder, + ScriptTaskPropertyBuilder { } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java index 3831c43bf2c..0c8750d516e 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java @@ -1,28 +1,19 @@ package io.seata.saga.statelang.builder; +import io.seata.saga.statelang.builder.prop.ServiceTaskPropertyBuilder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; import io.seata.saga.statelang.domain.ServiceTaskState; /*** + * Service task state builder for {@link ServiceTaskState}. * * @author ptyin */ -public interface ServiceTaskStateBuilder extends StateBuilder, - TaskStateBuilder { +public interface ServiceTaskStateBuilder extends + StateBuilder, + BasicPropertyBuilder, + TaskPropertyBuilder, + ServiceTaskPropertyBuilder { - /** - * Configure service method. - * - * @param serviceName name of service bean - * @return builder for chaining - */ - ServiceTaskStateBuilder withServiceName(String serviceName); - - - /** - * Configure service method. - * - * @param serviceMethod method of service bean - * @return builder for chaining - */ - ServiceTaskStateBuilder withServiceMethod(String serviceMethod); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java index 2da8672fa57..6ce06e16c42 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java @@ -3,40 +3,14 @@ import io.seata.saga.statelang.domain.State; /*** - * Configure transitions for {@link StateMachineBuilder}. + * State builder. * - * @param builder type * @param state type * @author ptyin */ -public interface StateBuilder, S extends State> -{ +public interface StateBuilder { /** - * Configure name. - * - * @param name name of state - * @return builder for chaining - */ - B withName(String name); - - /** - * Configure comment. - * - * @param comment comment of state - * @return builder for chaining - */ - B withComment(String comment); - - /** - * Configure next state. - * - * @param next next state - * @return builder for chaining - */ - B withNext(String next); - - /** - * Build a state. + * Build a state. * * @return built state */ diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java index ef688ee917a..333fb67ea58 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java @@ -16,12 +16,10 @@ package io.seata.saga.statelang.builder; -import io.seata.saga.statelang.builder.impl.ChoiceStateBuilderImpl; -import io.seata.saga.statelang.builder.impl.ServiceTaskStateBuilderImpl; -import io.seata.saga.statelang.domain.State; +import io.seata.saga.statelang.builder.impl.*; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * State builder factory. @@ -29,17 +27,27 @@ * @author ptyin */ public class StateBuilderFactory { - protected static Map>, Class>> stateBuilderMap = - new ConcurrentHashMap<>(); + protected static Map>, Class>> stateBuilderMap + = new HashMap<>(); static { - stateBuilderMap.put(ServiceTaskStateBuilder.class, ServiceTaskStateBuilderImpl.class); stateBuilderMap.put(ChoiceStateBuilder.class, ChoiceStateBuilderImpl.class); + stateBuilderMap.put(CompensateSubStateMachineStateBuilder.class, + CompensateSubStateMachineStateBuilderImpl.class); + stateBuilderMap.put(CompensationTriggerStateBuilder.class, + CompensationTriggerStateBuilderImpl.class); + stateBuilderMap.put(FailEndStateBuilder.class, FailEndStateBuilderImpl.class); + stateBuilderMap.put(ForkStateBuilder.class, ForkStateBuilderImpl.class); + stateBuilderMap.put(JoinStateBuilder.class, JoinStateBuilderImpl.class); + stateBuilderMap.put(ScriptTaskStateBuilder.class, ScriptTaskStateBuilderImpl.class); + stateBuilderMap.put(ServiceTaskStateBuilder.class, ServiceTaskStateBuilderImpl.class); + stateBuilderMap.put(SubStateMachineBuilder.class, SubStateMachineBuilderImpl.class); + stateBuilderMap.put(SuccessEndStateBuilder.class, SuccessEndStateBuilderImpl.class); } - public static StateBuilder getStateBuilder(Class> clazz) + public static StateBuilder getStateBuilder(Class> clazz) throws InstantiationException, IllegalAccessException { - Class> implClazz = stateBuilderMap.getOrDefault(clazz, clazz); + Class> implClazz = stateBuilderMap.getOrDefault(clazz, clazz); return implClazz.newInstance(); } } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java index 49789a2fc64..7b69c84b4ce 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java @@ -16,7 +16,7 @@ public interface StatesConfigurer * @param builder type * @return builder for chaining */ - > B build(Class clazz); + > B build(Class clazz); /** * Add a built state diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SubStateMachineBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SubStateMachineBuilder.java new file mode 100644 index 00000000000..06c08394a0f --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SubStateMachineBuilder.java @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.SubStateMachinePropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; +import io.seata.saga.statelang.domain.SubStateMachine; + +/** + * SubStateMachine builder for {@link SubStateMachine} + * + * @author ptyin + */ +public interface SubStateMachineBuilder extends + StateBuilder, + BasicPropertyBuilder, + TaskPropertyBuilder, + SubStateMachinePropertyBuilder { + +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SuccessEndStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SuccessEndStateBuilder.java new file mode 100644 index 00000000000..a499246f4ea --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/SuccessEndStateBuilder.java @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder; + +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.domain.SucceedEndState; + +/** + * Success end state builder for {@link SucceedEndState} + * + * @author ptyin + */ +public interface SuccessEndStateBuilder extends + StateBuilder, + BasicPropertyBuilder { +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractServiceTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractServiceTaskStateBuilder.java new file mode 100644 index 00000000000..d9691752866 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractServiceTaskStateBuilder.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.prop.ServiceTaskPropertyBuilder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; +import io.seata.saga.statelang.domain.ServiceTaskState; +import io.seata.saga.statelang.domain.impl.ServiceTaskStateImpl; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Abstract service task state builder to inherit. + * + * @author ptyin + */ +public abstract class AbstractServiceTaskStateBuilder +

& TaskPropertyBuilder

& ServiceTaskPropertyBuilder

, + S extends ServiceTaskState> + extends AbstractTaskStateBuilder + implements ServiceTaskPropertyBuilder

{ + + @Override + public P withServiceName(String serviceName) { + ((ServiceTaskStateImpl) getState()).setServiceName(serviceName); + return getPropertyBuilder(); + } + + @Override + public P withServiceMethod(String serviceMethod) { + ((ServiceTaskStateImpl) getState()).setServiceMethod(serviceMethod); + return getPropertyBuilder(); + } + + @Override + public P withServiceType(String serviceType) { + ((ServiceTaskStateImpl) getState()).setServiceType(serviceType); + return getPropertyBuilder(); + } + + @Override + public P withParameterTypes(Collection parameterTypes) { + ((ServiceTaskStateImpl) getState()).setParameterTypes(new ArrayList<>(parameterTypes)); + return getPropertyBuilder(); + } + + @Override + public P withAsync(boolean async) { + ((ServiceTaskStateImpl) getState()).setAsync(async); + return getPropertyBuilder(); + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java index ff39ba59578..79147e55ebc 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java @@ -16,8 +16,8 @@ package io.seata.saga.statelang.builder.impl; -import io.seata.saga.statelang.builder.StateBuilder; -import io.seata.saga.statelang.builder.TaskStateBuilder; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; +import io.seata.saga.statelang.builder.prop.TaskPropertyBuilder; import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.impl.AbstractTaskState; @@ -29,17 +29,17 @@ /** * Abstract task state builder to inherit. * - * @param builder type + * @param

builder type * @param state type * @author ptyin */ -public abstract class AbstractTaskStateBuilder & StateBuilder, S extends State> - extends BaseStateBuilder implements TaskStateBuilder { - - protected AbstractTaskState state; +public abstract class AbstractTaskStateBuilder +

& TaskPropertyBuilder

, S extends State> + extends BaseStateBuilder + implements BasicPropertyBuilder

, TaskPropertyBuilder

{ public AbstractTaskStateBuilder() { - state = (AbstractTaskState) getState(); + AbstractTaskState state = (AbstractTaskState) getState(); // Do some default setup state.setForCompensation(false); state.setForUpdate(false); @@ -50,114 +50,117 @@ public AbstractTaskStateBuilder() { } @Override - public B withCompensationState(String compensationState) { - state.setCompensateState(compensationState); - return getBuilder(); + public P withCompensationState(String compensationState) { + ((AbstractTaskState) getState()).setCompensateState(compensationState); + return getPropertyBuilder(); } @Override - public B withForCompensation(boolean forCompensation) { - state.setForUpdate(forCompensation); - return getBuilder(); + public P withForCompensation(boolean forCompensation) { + ((AbstractTaskState) getState()).setForUpdate(forCompensation); + return getPropertyBuilder(); } @Override - public B withForUpdate(boolean forUpdate) { - state.setForUpdate(forUpdate); - return getBuilder(); + public P withForUpdate(boolean forUpdate) { + ((AbstractTaskState) getState()).setForUpdate(forUpdate); + return getPropertyBuilder(); } @Override - public RetryBuilder withOneRetry() { + public RetryBuilder

withOneRetry() { return new RetryBuilderImpl(); } @Override - public ExceptionMatchBuilder withOneCatch() { + public ExceptionMatchBuilder

withOneCatch() { return new ExceptionMatchBuilderImpl(); } @Override - public B withOneStatus(String expression, String status) { + public P withOneStatus(String expression, String status) { + AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getStatus() == null) { state.setStatus(new HashMap<>()); } state.getStatus().put(expression, status); - return getBuilder(); + return getPropertyBuilder(); } @Override - public LoopBuilder withLoop() { + public LoopBuilder

withLoop() { return new LoopBuilderImpl(); } - public class RetryBuilderImpl implements TaskStateBuilder.RetryBuilder { + public class RetryBuilderImpl implements RetryBuilder

{ private final AbstractTaskState.RetryImpl oneRetry = new AbstractTaskState.RetryImpl(); @Override - public B and() { + public P and() { + AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getRetry() == null) { state.setRetry(new ArrayList<>()); } state.getRetry().add(oneRetry); - return getBuilder(); + return getPropertyBuilder(); } @Override - public RetryBuilder withExceptions(Collection> exceptions) { + public RetryBuilder

withExceptions(Collection> exceptions) { oneRetry.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); oneRetry.setExceptionClasses(new ArrayList<>(exceptions)); return this; } @Override - public RetryBuilder withIntervalSeconds(double intervalSeconds) { + public RetryBuilder

withIntervalSeconds(double intervalSeconds) { oneRetry.setIntervalSeconds(intervalSeconds); return this; } @Override - public RetryBuilder withMaxAttempts(int maxAttempts) { + public RetryBuilder

withMaxAttempts(int maxAttempts) { oneRetry.setMaxAttempts(maxAttempts); return this; } @Override - public RetryBuilder withBackoffRate(double backoffRate) { + public RetryBuilder

withBackoffRate(double backoffRate) { oneRetry.setBackoffRate(backoffRate); return this; } } - public class ExceptionMatchBuilderImpl implements TaskStateBuilder.ExceptionMatchBuilder { + public class ExceptionMatchBuilderImpl implements ExceptionMatchBuilder

{ private final AbstractTaskState.ExceptionMatchImpl oneCatch = new AbstractTaskState.ExceptionMatchImpl(); @Override - public B and() { + public P and() { + AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getCatches() == null) { state.setCatches(new ArrayList<>()); } state.getCatches().add(oneCatch); - return getBuilder(); + return getPropertyBuilder(); } @Override - public ExceptionMatchBuilder withExceptions(Collection> exceptions) { + public ExceptionMatchBuilder

withExceptions(Collection> exceptions) { oneCatch.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); oneCatch.setExceptionClasses(new ArrayList<>(exceptions)); return this; } @Override - public ExceptionMatchBuilder withNext(String next) { + public ExceptionMatchBuilder

withNext(String next) { oneCatch.setNext(next); return this; } } - public class LoopBuilderImpl implements LoopBuilder { + public class LoopBuilderImpl implements LoopBuilder

{ private final AbstractTaskState.LoopImpl loop = new AbstractTaskState.LoopImpl(); @@ -174,61 +177,62 @@ public LoopBuilderImpl() { } @Override - public B and() { + public P and() { + AbstractTaskState state = ((AbstractTaskState) getState()); state.setLoop(loop); - return getBuilder(); + return getPropertyBuilder(); } @Override - public LoopBuilder withParallel(int parallel) { + public LoopBuilder

withParallel(int parallel) { loop.setParallel(parallel); return this; } @Override - public LoopBuilder withCollection(String collection) { + public LoopBuilder

withCollection(String collection) { loop.setCollection(collection); return this; } @Override - public LoopBuilder withElementVariableName(String elementVariableName) { + public LoopBuilder

withElementVariableName(String elementVariableName) { loop.setElementVariableName(elementVariableName); return this; } @Override - public LoopBuilder withElementIndexName(String elementIndexName) { + public LoopBuilder

withElementIndexName(String elementIndexName) { loop.setElementIndexName(elementIndexName); return this; } @Override - public LoopBuilder withCompletionCondition(String completionCondition) { + public LoopBuilder

withCompletionCondition(String completionCondition) { loop.setCompletionCondition(completionCondition); return this; } @Override - public LoopBuilder withResultName(String resultName) { + public LoopBuilder

withResultName(String resultName) { loop.setResultName(resultName); return this; } @Override - public LoopBuilder withNumberOfInstancesName(String numberOfInstancesName) { + public LoopBuilder

withNumberOfInstancesName(String numberOfInstancesName) { loop.setNumberOfInstancesName(numberOfInstancesName); return this; } @Override - public LoopBuilder withNumberOfActiveInstancesName(String numberOfActiveInstancesName) { + public LoopBuilder

withNumberOfActiveInstancesName(String numberOfActiveInstancesName) { loop.setNumberOfActiveInstancesName(numberOfActiveInstancesName); return this; } @Override - public LoopBuilder withNumberOfCompletedInstancesName(String numberOfCompletedInstancesName) { + public LoopBuilder

withNumberOfCompletedInstancesName(String numberOfCompletedInstancesName) { loop.setNumberOfCompletedInstancesName(numberOfCompletedInstancesName); return this; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java index 9863e37c781..92896b70a11 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/BaseStateBuilder.java @@ -18,6 +18,7 @@ import io.seata.saga.statelang.builder.StateBuilder; import io.seata.saga.statelang.builder.StatesConfigurer; +import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.impl.BaseState; @@ -28,26 +29,26 @@ * @param state type * @author ptyin */ -public abstract class BaseStateBuilder, S extends State> - implements StateBuilder { +public abstract class BaseStateBuilder, S extends State> + implements StateBuilder, BasicPropertyBuilder { private StatesConfigurer parent; @Override public B withName(String name) { ((BaseState) getState()).setName(name); - return getBuilder(); + return getPropertyBuilder(); } @Override public B withComment(String comment) { ((BaseState) getState()).setComment(comment); - return getBuilder(); + return getPropertyBuilder(); } @Override public B withNext(String next) { ((BaseState) getState()).setNext(next); - return getBuilder(); + return getPropertyBuilder(); } @Override @@ -65,7 +66,7 @@ public void setParent(StatesConfigurer parent) { this.parent = parent; } - protected abstract B getBuilder(); + protected abstract B getPropertyBuilder(); protected abstract S getState(); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java index 6840772900a..a630b85cbd9 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ChoiceStateBuilderImpl.java @@ -53,7 +53,7 @@ public ChoiceStateBuilder withDefault(String defaultChoice) { } @Override - protected ChoiceStateBuilder getBuilder() { + protected ChoiceStateBuilder getPropertyBuilder() { return this; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensateSubStateMachineStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensateSubStateMachineStateBuilderImpl.java new file mode 100644 index 00000000000..c8212e3d3ca --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensateSubStateMachineStateBuilderImpl.java @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.CompensateSubStateMachineStateBuilder; +import io.seata.saga.statelang.domain.CompensateSubStateMachineState; +import io.seata.saga.statelang.domain.impl.CompensateSubStateMachineStateImpl; + +/** + * Default implementation for {@link CompensateSubStateMachineStateBuilder} + * + * @author ptyin + */ +public class CompensateSubStateMachineStateBuilderImpl + extends AbstractServiceTaskStateBuilder + implements CompensateSubStateMachineStateBuilder { + + protected CompensateSubStateMachineStateImpl state; + + @Override + protected CompensateSubStateMachineStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected CompensateSubStateMachineState getState() { + if (state == null) { + state = new CompensateSubStateMachineStateImpl(); + } + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java new file mode 100644 index 00000000000..042173a95d6 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.CompensationTriggerStateBuilder; +import io.seata.saga.statelang.domain.CompensationTriggerState; +import io.seata.saga.statelang.domain.impl.CompensationTriggerStateImpl; + +/** + * Default implementation for {@link CompensationTriggerStateBuilder} + * + * @author ptyin + */ +public class CompensationTriggerStateBuilderImpl + extends BaseStateBuilder + implements CompensationTriggerStateBuilder{ + + protected CompensationTriggerStateImpl state = new CompensationTriggerStateImpl(); + + @Override + protected CompensationTriggerStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected CompensationTriggerState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/FailEndStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/FailEndStateBuilderImpl.java new file mode 100644 index 00000000000..d924c922dad --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/FailEndStateBuilderImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.FailEndStateBuilder; +import io.seata.saga.statelang.domain.FailEndState; +import io.seata.saga.statelang.domain.impl.FailEndStateImpl; + +/** + * Default implementation for {@link FailEndStateBuilder} + * + * @author ptyin + */ +public class FailEndStateBuilderImpl + extends BaseStateBuilder + implements FailEndStateBuilder { + + protected FailEndStateImpl state = new FailEndStateImpl(); + + @Override + public FailEndStateBuilder withErrorCode(String errorCode) { + state.setErrorCode(errorCode); + return this; + } + + @Override + public FailEndStateBuilder withMessage(String message) { + state.setMessage(message); + return this; + } + + @Override + protected FailEndStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected FailEndState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java new file mode 100644 index 00000000000..22e2906f58f --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.common.util.CollectionUtils; +import io.seata.saga.statelang.builder.BuildException; +import io.seata.saga.statelang.builder.ForkStateBuilder; +import io.seata.saga.statelang.domain.ForkState; +import io.seata.saga.statelang.domain.impl.ForkStateImpl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +/** + * Default implementation for {@link ForkStateBuilder} + * + * @author ptyin + */ +public class ForkStateBuilderImpl + extends BaseStateBuilder + implements ForkStateBuilder { + + protected ForkStateImpl state = new ForkStateImpl(); + + @Override + public ForkStateBuilder withBranches(Collection branches) { + if (CollectionUtils.isEmpty(branches)) { + throw new BuildException("Branches of fork state should not be empty"); + } + if (new HashSet<>(branches).size() < branches.size()) { + throw new BuildException("Branches of fork state should not be same."); + } + state.setBranches(new ArrayList<>(branches)); + return this; + } + + @Override + public ForkStateBuilder withParallel(int parallel) { + state.setParallel(parallel); + return this; + } + + @Override + public ForkStateBuilder withAwaitTimeout(int awaitTimeout) { + state.setAwaitTimeout(awaitTimeout); + return this; + } + + @Override + protected ForkStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected ForkState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/JoinStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/JoinStateBuilderImpl.java new file mode 100644 index 00000000000..2096530fdf2 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/JoinStateBuilderImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.JoinStateBuilder; +import io.seata.saga.statelang.domain.JoinState; +import io.seata.saga.statelang.domain.impl.JoinStateImpl; + +/** + * Default implementation for {@link JoinStateBuilder} + * + * @author ptyin + */ +public class JoinStateBuilderImpl + extends BaseStateBuilder + implements JoinStateBuilder { + + protected JoinStateImpl state = new JoinStateImpl(); + + @Override + protected JoinStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected JoinState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java new file mode 100644 index 00000000000..532d8e28851 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.ScriptTaskStateBuilder; +import io.seata.saga.statelang.domain.ScriptTaskState; +import io.seata.saga.statelang.domain.impl.ScriptTaskStateImpl; + +/** + * Default implementation for {@link ScriptTaskStateBuilder} + * + * @author ptyin + */ +public class ScriptTaskStateBuilderImpl + extends AbstractTaskStateBuilder + implements ScriptTaskStateBuilder { + + protected ScriptTaskStateImpl state; + + @Override + public ScriptTaskStateBuilder withScriptType(String scriptType) { + state.setScriptType(scriptType); + return this; + } + + @Override + public ScriptTaskStateBuilder withScriptContent(String scriptContent) { + state.setScriptContent(scriptContent); + return this; + } + + @Override + protected ScriptTaskStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected ScriptTaskState getState() { + if (state == null) { + state = new ScriptTaskStateImpl(); + } + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java index 19f7797fef9..1f5bcdccc81 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ServiceTaskStateBuilderImpl.java @@ -26,30 +26,21 @@ * @author ptyin */ public class ServiceTaskStateBuilderImpl - extends BaseStateBuilder + extends AbstractServiceTaskStateBuilder implements ServiceTaskStateBuilder { - protected ServiceTaskStateImpl state = new ServiceTaskStateImpl(); + protected ServiceTaskStateImpl state; @Override - public ServiceTaskStateBuilder withServiceName(String serviceName) { - state.setServiceName(serviceName); - return this; - } - - @Override - public ServiceTaskStateBuilder withServiceMethod(String serviceMethod) { - state.setServiceMethod(serviceMethod); - return this; - } - - @Override - protected ServiceTaskStateBuilder getBuilder() { + protected ServiceTaskStateBuilder getPropertyBuilder() { return this; } @Override protected ServiceTaskState getState() { + if (state == null) { + state = new ServiceTaskStateImpl(); + } return state; } } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java index 684013bbbb2..8bc984e6d95 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java @@ -34,7 +34,7 @@ public class StatesConfigurerImpl implements StatesConfigurer { @Override @SuppressWarnings("unchecked") - public > B build(Class clazz) { + public > B build(Class clazz) { B builder; try { builder = (B) StateBuilderFactory.getStateBuilder(clazz); @@ -43,7 +43,7 @@ public class StatesConfigurerImpl implements StatesConfigurer { } catch (ClassCastException e) { throw new FrameworkException(e, "StateBuilderFactory got a wrong state builder."); } - ((BaseStateBuilder) builder).setParent(this); + ((BaseStateBuilder) builder).setParent(this); return builder; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java new file mode 100644 index 00000000000..adda4906087 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.SubStateMachineBuilder; +import io.seata.saga.statelang.domain.SubStateMachine; +import io.seata.saga.statelang.domain.impl.SubStateMachineImpl; + +/** + * Default implementation for {@link SubStateMachineBuilder} + * + * @author ptyin + */ +public class SubStateMachineBuilderImpl + extends AbstractTaskStateBuilder + implements SubStateMachineBuilder{ + + protected SubStateMachineImpl state; + + @Override + public SubStateMachineBuilder withStateMachineName(String stateMachineName) { + state.setStateMachineName(stateMachineName); + return this; + } + + @Override + protected SubStateMachineBuilder getPropertyBuilder() { + return this; + } + + @Override + protected SubStateMachine getState() { + if (state == null) { + state = new SubStateMachineImpl(); + } + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SuccessEndStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SuccessEndStateBuilderImpl.java new file mode 100644 index 00000000000..ca11f9d27eb --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SuccessEndStateBuilderImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.impl; + +import io.seata.saga.statelang.builder.SuccessEndStateBuilder; +import io.seata.saga.statelang.domain.SucceedEndState; +import io.seata.saga.statelang.domain.impl.SucceedEndStateImpl; + +/** + * Default implementation for {@link SuccessEndStateBuilder} + * + * @author ptyin + */ +public class SuccessEndStateBuilderImpl + extends BaseStateBuilder + implements SuccessEndStateBuilder { + + SucceedEndStateImpl state = new SucceedEndStateImpl(); + + @Override + protected SuccessEndStateBuilder getPropertyBuilder() { + return this; + } + + @Override + protected SucceedEndState getState() { + return state; + } +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/BasicPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/BasicPropertyBuilder.java new file mode 100644 index 00000000000..b603269fb0b --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/BasicPropertyBuilder.java @@ -0,0 +1,49 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +/*** + * State property builder. + * + * @param

property builder type + * @author ptyin + */ +public interface BasicPropertyBuilder

> { + /** + * Configure name. + * + * @param name name of state + * @return builder for chaining + */ + P withName(String name); + + /** + * Configure comment. + * + * @param comment comment of state + * @return builder for chaining + */ + P withComment(String comment); + + /** + * Configure next state. + * + * @param next next state + * @return builder for chaining + */ + P withNext(String next); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ChoicePropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ChoicePropertyBuilder.java new file mode 100644 index 00000000000..d66c0ef1d71 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ChoicePropertyBuilder.java @@ -0,0 +1,42 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +/** + * Choice state property builder + * + * @param

property builder type + * @author ptyin + */ +public interface ChoicePropertyBuilder

> { + /** + * Put (expression, next state) pair into choices. + * + * @param expression expression to evaluate + * @param next name of next state + * @return builder for chaining + */ + P withChoice(String expression, String next); + + /** + * Configure default choice when no valid choices. + * + * @param defaultChoice default choice + * @return builder for chaining + */ + P withDefault(String defaultChoice); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/FailEndPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/FailEndPropertyBuilder.java new file mode 100644 index 00000000000..75a8591aff0 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/FailEndPropertyBuilder.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +/** + * Fail end property builder + * + * @param

property builder type + * @author ptyin + */ +public interface FailEndPropertyBuilder

> { + /** + * Configure the state error code + * + * @param errorCode error code + * @return builder for chaining + */ + P withErrorCode(String errorCode); + + /** + * Configure the state error message + * + * @param message error message + * @return builder for chaining + */ + P withMessage(String message); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java new file mode 100644 index 00000000000..152245d5490 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java @@ -0,0 +1,51 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +import java.util.Collection; + +/** + * Fork property builder + * + * @param

property builder type + * @author ptyin + */ +public interface ForkPropertyBuilder

> { + /** + * Configure parallel branches + * + * @param branches names of each first state in branch + * @return builder for chaining + */ + P withBranches(Collection branches); + + /** + * Configure max parallelism, default 0 which stands for no limit. + * + * @param parallel max parallelism, i.e. max count of threads at a specific moment + * @return loop builder for chaining + */ + P withParallel(int parallel); + + /** + * Configure max await timeout, default 12 hours. + * + * @param awaitTimeout await timeout + * @return builder for chaining + */ + P withAwaitTimeout(int awaitTimeout); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ScriptTaskPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ScriptTaskPropertyBuilder.java new file mode 100644 index 00000000000..db8fbd273c1 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ScriptTaskPropertyBuilder.java @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +/*** + * Script task state property builder + * + * @param

property builder type + * @author ptyin + */ +public interface ScriptTaskPropertyBuilder

> { + /** + * Configure script type such as groovy. + * + * @param scriptType type of script + * @return builder for chaining + */ + P withScriptType(String scriptType); + + /** + * Configure script content. + * + * @param scriptContent content of script + * @return builder for chaining + */ + P withScriptContent(String scriptContent); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ServiceTaskPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ServiceTaskPropertyBuilder.java new file mode 100644 index 00000000000..40216b0e403 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ServiceTaskPropertyBuilder.java @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +import java.util.Collection; + +/** + * Service task property builder. + * + * @param

property builder type + * @author ptyin + */ +public interface ServiceTaskPropertyBuilder

> { + + /** + * Configure service type such as SpringBean, SOFA RPC, default is StringBean. + * + * @param serviceType type of service + * @return builder for chaining + */ + P withServiceType(String serviceType); + + /** + * Configure service method. + * + * @param serviceName name of service bean + * @return builder for chaining + */ + P withServiceName(String serviceName); + + /** + * Configure service method. + * + * @param serviceMethod method of service bean + * @return builder for chaining + */ + P withServiceMethod(String serviceMethod); + + /** + * Configure parameter types + * + * @param parameterTypes parameter types + * @return builder for chaining + */ + P withParameterTypes(Collection parameterTypes); + + /** + * Configure synchronization mode + * + * @param async async or not + * @return builder for chaining + */ + P withAsync(boolean async); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/SubStateMachinePropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/SubStateMachinePropertyBuilder.java new file mode 100644 index 00000000000..62895b37e03 --- /dev/null +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/SubStateMachinePropertyBuilder.java @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.seata.saga.statelang.builder.prop; + +/** + * SubStateMachine property builder + * + * @param

property builder type + * @author ptyin + */ +public interface SubStateMachinePropertyBuilder

> { + /** + * Configure sub statemachine name + * + * @param stateMachineName name of state machine + * @return builder for chaining + */ + P withStateMachineName(String stateMachineName); +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java similarity index 76% rename from saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java rename to saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java index f468f1b175f..0db6c6c43f0 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/TaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java @@ -14,24 +14,24 @@ * limitations under the License. */ -package io.seata.saga.statelang.builder; +package io.seata.saga.statelang.builder.prop; import java.util.Collection; /*** - * Task state builder. + * Task property builder. * - * @param builder type + * @param

property builder type * @author ptyin */ -public interface TaskStateBuilder> { +public interface TaskPropertyBuilder

> { /** * Configure compensation state. * * @param compensationState name of compensation state * @return builder for chaining */ - B withCompensationState(String compensationState); + P withCompensationState(String compensationState); /** * Configure if this state is used to compensate another state. @@ -39,7 +39,7 @@ public interface TaskStateBuilder> { * @param forCompensation if is for compensation or not * @return builder for chaining */ - B withForCompensation(boolean forCompensation); + P withForCompensation(boolean forCompensation); /** * Configure if this state will update data @@ -47,7 +47,7 @@ public interface TaskStateBuilder> { * @param forUpdate if is for update * @return builder for chaining */ - B withForUpdate(boolean forUpdate); + P withForUpdate(boolean forUpdate); /** * Configure retry strategy. If the state has multiple retry strategies, use following way to build: @@ -67,7 +67,7 @@ public interface TaskStateBuilder> { * * @return retry builder */ - RetryBuilder withOneRetry(); + TaskPropertyBuilder.RetryBuilder

withOneRetry(); /** * Configure exception catching rules. If the state has multiple catching rules, use following way to build: @@ -87,7 +87,7 @@ public interface TaskStateBuilder> { * * @return exception match builder */ - ExceptionMatchBuilder withOneCatch(); + TaskPropertyBuilder.ExceptionMatchBuilder

withOneCatch(); /** * Configure execution status. @@ -96,14 +96,14 @@ public interface TaskStateBuilder> { * @param status matched status * @return builder for chaining */ - B withOneStatus(String expression, String status); + P withOneStatus(String expression, String status); /** * Configure loop strategy. * * @return builder for chaining */ - LoopBuilder withLoop(); + TaskPropertyBuilder.LoopBuilder

withLoop(); interface ChildBuilder { /** @@ -114,14 +114,14 @@ interface ChildBuilder { B and(); } - interface RetryBuilder extends ChildBuilder { + interface RetryBuilder extends TaskPropertyBuilder.ChildBuilder { /** * Configure exception classes to capture * * @param exceptions exception classes * @return retry builder for chaining */ - RetryBuilder withExceptions(Collection> exceptions); + TaskPropertyBuilder.RetryBuilder withExceptions(Collection> exceptions); /** * Configure interval @@ -129,7 +129,7 @@ interface RetryBuilder extends ChildBuilder { * @param intervalSeconds interval in seconds * @return retry builder for chaining */ - RetryBuilder withIntervalSeconds(double intervalSeconds); + TaskPropertyBuilder.RetryBuilder withIntervalSeconds(double intervalSeconds); /** * Configure max attempts @@ -137,7 +137,7 @@ interface RetryBuilder extends ChildBuilder { * @param maxAttempts max count of attempts * @return retry builder for chaining */ - RetryBuilder withMaxAttempts(int maxAttempts); + TaskPropertyBuilder.RetryBuilder withMaxAttempts(int maxAttempts); /** * Configure backoff rate @@ -145,17 +145,17 @@ interface RetryBuilder extends ChildBuilder { * @param backoffRate backoff rate * @return retry builder for chaining */ - RetryBuilder withBackoffRate(double backoffRate); + TaskPropertyBuilder.RetryBuilder withBackoffRate(double backoffRate); } - interface ExceptionMatchBuilder extends ChildBuilder { + interface ExceptionMatchBuilder extends TaskPropertyBuilder.ChildBuilder { /** * Configure exception classes to capture. * * @param exceptions exception classes * @return exception match builder for chaining */ - ExceptionMatchBuilder withExceptions(Collection> exceptions); + TaskPropertyBuilder.ExceptionMatchBuilder withExceptions(Collection> exceptions); /** * Configure next state when exception matched. @@ -163,17 +163,17 @@ interface ExceptionMatchBuilder extends ChildBuilder { * @param next name of next state * @return exception match builder for chaining */ - ExceptionMatchBuilder withNext(String next); + TaskPropertyBuilder.ExceptionMatchBuilder withNext(String next); } - interface LoopBuilder extends ChildBuilder { + interface LoopBuilder extends TaskPropertyBuilder.ChildBuilder { /** * Configure max parallelism. * * @param parallel max parallelism, i.e. max count of threads at a specific moment * @return loop builder for chaining */ - LoopBuilder withParallel(int parallel); + TaskPropertyBuilder.LoopBuilder withParallel(int parallel); /** * Configure collection object name. @@ -181,7 +181,7 @@ interface LoopBuilder extends ChildBuilder { * @param collection collection name * @return loop builder for chaining */ - LoopBuilder withCollection(String collection); + TaskPropertyBuilder.LoopBuilder withCollection(String collection); /** * Configure element variable name. @@ -189,7 +189,7 @@ interface LoopBuilder extends ChildBuilder { * @param elementVariableName element variable name * @return loop builder for chaining */ - LoopBuilder withElementVariableName(String elementVariableName); + TaskPropertyBuilder.LoopBuilder withElementVariableName(String elementVariableName); /** * Configure element variable index name, default loopCounter. @@ -197,7 +197,7 @@ interface LoopBuilder extends ChildBuilder { * @param elementIndexName element index name * @return loop builder for chaining */ - LoopBuilder withElementIndexName(String elementIndexName); + TaskPropertyBuilder.LoopBuilder withElementIndexName(String elementIndexName); /** * Configure completion condition, default nrOfInstances == nrOfCompletedInstances. @@ -205,7 +205,7 @@ interface LoopBuilder extends ChildBuilder { * @param completionCondition completion condition * @return loop builder for chaining */ - LoopBuilder withCompletionCondition(String completionCondition); + TaskPropertyBuilder.LoopBuilder withCompletionCondition(String completionCondition); /** * Configure the name of loop result, default loopResult. @@ -213,7 +213,7 @@ interface LoopBuilder extends ChildBuilder { * @param resultName result name * @return loop builder for chaining */ - LoopBuilder withResultName(String resultName); + TaskPropertyBuilder.LoopBuilder withResultName(String resultName); /** * Configure the name of number of instances, default nrOfInstances. diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java index 1390bdde45e..59a66582122 100644 --- a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -15,9 +15,6 @@ */ package io.seata.saga.statelang.builder; -import io.seata.saga.statelang.builder.ChoiceStateBuilder; -import io.seata.saga.statelang.builder.ServiceTaskStateBuilder; -import io.seata.saga.statelang.builder.StateMachineBuilder; import io.seata.saga.statelang.builder.impl.StateMachineBuilderImpl; import io.seata.saga.statelang.domain.StateMachine; import org.junit.jupiter.api.Assertions; From 703958016154125759f55b82d044a641e5e6ecd4 Mon Sep 17 00:00:00 2001 From: ptyin Date: Tue, 12 Sep 2023 18:19:42 +0800 Subject: [PATCH 05/10] optimize: add statemachine and task implicit properties --- .../builder/StateMachineBuilder.java | 34 +++++++++++ .../impl/AbstractTaskStateBuilder.java | 58 +++++++++++++++++- .../builder/impl/StateMachineBuilderImpl.java | 25 ++++++++ .../builder/prop/TaskPropertyBuilder.java | 59 +++++++++++++++++++ 4 files changed, 173 insertions(+), 3 deletions(-) diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java index ec6defdcbac..95e4d6123fd 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateMachineBuilder.java @@ -15,6 +15,7 @@ */ package io.seata.saga.statelang.builder; +import io.seata.saga.statelang.domain.RecoverStrategy; import io.seata.saga.statelang.domain.StateMachine; /** @@ -69,4 +70,37 @@ public interface StateMachineBuilder * @return builder for chaining */ StateMachineBuilder withStartState(String stateName); + + /** + * Configure recover strategy + * + * @param recoverStrategy recover strategy + * @return builder for chaining + */ + StateMachineBuilder withRecoverStrategy(RecoverStrategy recoverStrategy); + + /** + * Configure if this state should be persistent, default true + * + * @param persist persistent or not + * @return builder for chaining + */ + StateMachineBuilder withPersist(boolean persist); + + /** + * Configure if update origin or append new retryStateInstLog, default false + * + * @param retryPersistModeUpdate append new retryStateInstLog or not + * @return builder for chaining + */ + StateMachineBuilder withRetryPersistModeUpdate(boolean retryPersistModeUpdate); + + + /** + * Configure if update origin or append new compensateStateInstLog, default false + * + * @param compensatePersistModeUpdate append new compensateStateInstLog or not + * @return builder for chaining + */ + StateMachineBuilder withCompensatePersistModeUpdate(boolean compensatePersistModeUpdate); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java index 79147e55ebc..9f680b8155d 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java @@ -21,9 +21,7 @@ import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.impl.AbstractTaskState; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; +import java.util.*; import java.util.stream.Collectors; /** @@ -67,6 +65,24 @@ public P withForUpdate(boolean forUpdate) { return getPropertyBuilder(); } + @Override + public P withPersist(boolean persist) { + ((AbstractTaskState) getState()).setPersist(persist); + return getPropertyBuilder(); + } + + @Override + public P withRetryPersistModeUpdate(boolean retryPersistModeUpdate) { + ((AbstractTaskState) getState()).setRetryPersistModeUpdate(retryPersistModeUpdate); + return getPropertyBuilder(); + } + + @Override + public P withCompensatePersistModeUpdate(boolean compensatePersistModeUpdate) { + ((AbstractTaskState) getState()).setCompensatePersistModeUpdate(compensatePersistModeUpdate); + return getPropertyBuilder(); + } + @Override public RetryBuilder

withOneRetry() { return new RetryBuilderImpl(); @@ -77,6 +93,42 @@ public ExceptionMatchBuilder

withOneCatch() { return new ExceptionMatchBuilderImpl(); } + @Override + public P withInput(Collection input) { + ((AbstractTaskState) getState()).setInput(new ArrayList<>(input)); + return getPropertyBuilder(); + } + + @Override + public P withOutput(Map output) { + AbstractTaskState state = ((AbstractTaskState) getState()); + if (state.getOutput() == null) { + state.setOutput(new HashMap<>()); + } + state.getOutput().putAll(output); + return getPropertyBuilder(); + } + + @Override + public P withOneOutput(String variable, Object expression) { + AbstractTaskState state = ((AbstractTaskState) getState()); + if (state.getOutput() == null) { + state.setOutput(new HashMap<>()); + } + state.getOutput().put(variable, expression); + return getPropertyBuilder(); + } + + @Override + public P withStatus(Map status) { + AbstractTaskState state = ((AbstractTaskState) getState()); + if (state.getStatus() == null) { + state.setStatus(new HashMap<>()); + } + state.getStatus().putAll(status); + return getPropertyBuilder(); + } + @Override public P withOneStatus(String expression, String status) { AbstractTaskState state = ((AbstractTaskState) getState()); diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java index c8213d5d024..03329ca36b7 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java @@ -18,6 +18,7 @@ import io.seata.saga.statelang.builder.StateMachineBuilder; import io.seata.saga.statelang.builder.StatesConfigurer; +import io.seata.saga.statelang.domain.RecoverStrategy; import io.seata.saga.statelang.domain.StateMachine; import io.seata.saga.statelang.domain.impl.StateMachineImpl; @@ -66,4 +67,28 @@ public StateMachineBuilder withStartState(String stateName) { stateMachine.setStartState(stateName); return this; } + + @Override + public StateMachineBuilder withRecoverStrategy(RecoverStrategy recoverStrategy) { + stateMachine.setRecoverStrategy(recoverStrategy); + return this; + } + + @Override + public StateMachineBuilder withPersist(boolean persist) { + stateMachine.setPersist(persist); + return this; + } + + @Override + public StateMachineBuilder withRetryPersistModeUpdate(boolean retryPersistModeUpdate) { + stateMachine.setRetryPersistModeUpdate(retryPersistModeUpdate); + return this; + } + + @Override + public StateMachineBuilder withCompensatePersistModeUpdate(boolean compensatePersistModeUpdate) { + stateMachine.setCompensatePersistModeUpdate(compensatePersistModeUpdate); + return this; + } } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java index 0db6c6c43f0..52750d0168a 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/TaskPropertyBuilder.java @@ -17,6 +17,7 @@ package io.seata.saga.statelang.builder.prop; import java.util.Collection; +import java.util.Map; /*** * Task property builder. @@ -49,6 +50,31 @@ public interface TaskPropertyBuilder

> { */ P withForUpdate(boolean forUpdate); + /** + * Configure if this state should be persistent, default true + * + * @param persist persistent or not + * @return builder for chaining + */ + P withPersist(boolean persist); + + /** + * Configure if update origin or append new retryStateInstLog, default false + * + * @param retryPersistModeUpdate append new retryStateInstLog or not + * @return builder for chaining + */ + P withRetryPersistModeUpdate(boolean retryPersistModeUpdate); + + + /** + * Configure if update origin or append new compensateStateInstLog, default false + * + * @param compensatePersistModeUpdate append new compensateStateInstLog or not + * @return builder for chaining + */ + P withCompensatePersistModeUpdate(boolean compensatePersistModeUpdate); + /** * Configure retry strategy. If the state has multiple retry strategies, use following way to build: *

@@ -89,6 +115,39 @@ public interface TaskPropertyBuilder

> { */ TaskPropertyBuilder.ExceptionMatchBuilder

withOneCatch(); + /** + * Configure input list of task + * + * @param input input list + * @return builder for chaining + */ + P withInput(Collection input); + + /** + * Configure output mapping for task + * + * @param output output map + * @return builder for chaining + */ + P withOutput(Map output); + + /** + * Configure one output mapping for task + * + * @param variable name of variable + * @param expression expression to evaluated and then assigned to the variable + * @return builder for chaining + */ + P withOneOutput(String variable, Object expression); + + /** + * Configure execution status. + * + * @param status status mapping + * @return builder for chaining + */ + P withStatus(Map status); + /** * Configure execution status. * From 64311d160ce5c5d6eb1605c0f36de323c3a995c4 Mon Sep 17 00:00:00 2001 From: ptyin Date: Tue, 12 Sep 2023 18:36:17 +0800 Subject: [PATCH 06/10] test: add unit test case for statemachine builder --- .../statelang/builder/StateBuilderTests.java | 163 +++++++++++++++++- 1 file changed, 156 insertions(+), 7 deletions(-) diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java index 59a66582122..02a7d1566ba 100644 --- a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -15,10 +15,25 @@ */ package io.seata.saga.statelang.builder; +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.ser.FilterProvider; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import io.seata.saga.statelang.builder.impl.StateMachineBuilderImpl; +import io.seata.saga.statelang.domain.ExecutionStatus; +import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.StateMachine; +import io.seata.saga.statelang.domain.impl.StateMachineImpl; +import io.seata.saga.statelang.parser.StateMachineParserFactory; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +import java.io.IOException; +import java.util.*; /** * Java stream-based builder tests. @@ -26,28 +41,162 @@ * @author lorne.cl */ public class StateBuilderTests { + + final static Map SERVICE_STATUS_MAP = new LinkedHashMap<>(); + static ObjectWriter ow; + static { + SERVICE_STATUS_MAP.put("return.code == 'S'", ExecutionStatus.SU.name()); + SERVICE_STATUS_MAP.put("return.code == 'F'", ExecutionStatus.FA.name()); + SERVICE_STATUS_MAP.put("$exception{java.lang.Throwable}", ExecutionStatus.UN.name()); + String[] ignorableFieldNames = {"stateMachine"}; + FilterProvider filters = new SimpleFilterProvider().addFilter( + "filter properties by name", SimpleBeanPropertyFilter.serializeAllExcept(ignorableFieldNames)); + ObjectMapper mapper = new ObjectMapper(); + mapper.addMixIn(Object.class, PropertyFilterMixIn.class); + ow = mapper.writer(filters).withDefaultPrettyPrinter(); + } + + @JsonFilter("filter properties by name") + static class PropertyFilterMixIn {} + @Test - void testBuildStateMachine() { + void testBuildStateMachine() throws IOException { + ClassPathResource resource = new ClassPathResource("statelang/simple_statemachine.json"); + String json = io.seata.saga.statelang.parser.utils.IOUtils.toString(resource.getInputStream(), "UTF-8"); + StateMachine parsedStateMachine = StateMachineParserFactory.getStateMachineParser(null).parse(json); + StateMachineBuilder stateMachineBuilder = new StateMachineBuilderImpl(); - StateMachine stateMachine = stateMachineBuilder + StateMachine builtStateMachine = stateMachineBuilder .withName("simpleTestStateMachine") .withComment("测试状态机定义") - .withVersion("0.0.2") .withStartState("FirstState") + .withVersion("0.0.1") .withStates() .build(ServiceTaskStateBuilder.class) .withName("FirstState") - .withServiceName("demoService") + .withServiceName("is.seata.saga.DemoService") .withServiceMethod("foo") + .withPersist(false) + .withNext("ScriptState") + .and() + .build(ScriptTaskStateBuilder.class) + .withName("ScriptState") + .withScriptType("groovy") + .withScriptContent("return 'hello ' + inputA") + .withInput(Collections.singletonList(new HashMap(){{ + put("inputA", "$.data1"); + }})) + .withOneOutput("scriptStateResult", "$.#root") .withNext("ChoiceState") .and() .build(ChoiceStateBuilder.class) .withName("ChoiceState") - .withChoice("[a] == 1", "SecondState") - .withChoice("[a] == 2", "ThirdState") + .withChoice("foo == 1", "FirstMatchState") + .withChoice("foo == 2", "SecondMatchState") + .withDefault("FailState") + .and() + .build(ServiceTaskStateBuilder.class) + .withName("FirstMatchState") + .withServiceName("is.seata.saga.DemoService") + .withServiceMethod("bar") + .withCompensationState("CompensateFirst") + .withStatus(SERVICE_STATUS_MAP) + .withInput(Arrays.asList( + new HashMap() {{ + put("inputA1", "$.data1"); + put("inputA2", new HashMap() {{ + put("a", "$.data2.a"); + }}); + }}, + new HashMap() {{ + put("inputB", "$.header"); + }} + )) + .withOneOutput("firstMatchStateResult", "$.#root") + .withOneRetry() + .withExceptions(Collections.singletonList(Exception.class)) + .withIntervalSeconds(2) + .withMaxAttempts(3) + .withBackoffRate(1.5) + .and() + .withOneCatch() + .withExceptions(Collections.singletonList(Exception.class)) + .withNext("CompensationTrigger") + .and() + .withNext("SuccessState") + .and() + .build(ServiceTaskStateBuilder.class) + .withName("CompensateFirst") + .withServiceName("is.seata.saga.DemoService") + .withServiceMethod("compensateBar") + .withForCompensation(true) + .withForUpdate(true) + .withInput(Collections.singletonList(new HashMap(){{ + put("input", "$.data"); + }})) + .withOneOutput("firstMatchStateResult", "$.#root") + .withStatus(SERVICE_STATUS_MAP) + .and() + .build(CompensationTriggerStateBuilder.class) + .withName("CompensationTrigger") + .withNext("CompensateEndState") + .and() + .build(FailEndStateBuilder.class) + .withName("CompensateEndState") + .withErrorCode("StateCompensated") + .withMessage("State Compensated!") + .and() + .build(SubStateMachineBuilder.class) + .withName("SecondMatchState") + .withStateMachineName("simpleTestStateMachine") + .withInput(Arrays.asList( + new HashMap() {{ + put("input", "$.data"); + }}, + new HashMap() {{ + put("header", "$.header"); + }} + )) + .withOneOutput("firstMatchStateResult", "$.#root") + .withNext("SuccessState") + .and() + .build(FailEndStateBuilder.class) + .withName("FailState") + .withErrorCode("DefaultStateError") + .withMessage("No Matches!") + .and() + .build(SuccessEndStateBuilder.class) + .withName("SuccessState") .and() .configure() .build(); - Assertions.assertNotNull(stateMachine); + assertStateMachineEquals((StateMachineImpl) parsedStateMachine, (StateMachineImpl) builtStateMachine); + } + + static void assertStateMachineEquals(StateMachineImpl expected, StateMachineImpl target) + throws JsonProcessingException { + Assertions.assertEquals(expected.getName(), target.getName()); + Assertions.assertEquals(expected.getComment(), target.getComment()); + Assertions.assertEquals(expected.getVersion(), target.getVersion()); + Assertions.assertEquals(expected.getStartState(), target.getStartState()); + Assertions.assertEquals(expected.getRecoverStrategy(), target.getRecoverStrategy()); + Assertions.assertEquals(expected.isPersist(), target.isPersist()); + Assertions.assertEquals(expected.isRetryPersistModeUpdate(), target.isRetryPersistModeUpdate()); + Assertions.assertEquals(expected.isCompensatePersistModeUpdate(), target.isCompensatePersistModeUpdate()); + + Assertions.assertEquals(expected.getStates().keySet(), target.getStates().keySet()); + for (String stateName: expected.getStates().keySet()) { + if ("SecondMatchState".equals(stateName)) { + // the compensateStateObject of SubStateMachine contains random string + continue; + } + assertStateEquals(stateName, expected.getState(stateName), target.getState(stateName)); + } + } + + static void assertStateEquals(String stateName, State expected, State target) throws JsonProcessingException { + String expectedJson = ow.writeValueAsString(expected); + String targetJson = ow.writeValueAsString(target); + Assertions.assertEquals(expectedJson, targetJson, String.format("State [%s] is not identical", stateName)); } } From 7bca9554c4dcd52feda6368744a42f76801ed9ee Mon Sep 17 00:00:00 2001 From: ptyin Date: Tue, 12 Sep 2023 18:36:53 +0800 Subject: [PATCH 07/10] bugfix: fix problems found by test --- .../impl/AbstractTaskStateBuilder.java | 20 +++++++------- .../impl/ScriptTaskStateBuilderImpl.java | 6 +++++ .../impl/SubStateMachineBuilderImpl.java | 26 +++++++++++++++++++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java index 9f680b8155d..b85d60727ff 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java @@ -21,7 +21,10 @@ import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.impl.AbstractTaskState; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.stream.Collectors; /** @@ -41,9 +44,6 @@ public AbstractTaskStateBuilder() { // Do some default setup state.setForCompensation(false); state.setForUpdate(false); - state.setRetryPersistModeUpdate(false); - state.setCompensatePersistModeUpdate(false); - state.setPersist(true); } @@ -55,7 +55,7 @@ public P withCompensationState(String compensationState) { @Override public P withForCompensation(boolean forCompensation) { - ((AbstractTaskState) getState()).setForUpdate(forCompensation); + ((AbstractTaskState) getState()).setForCompensation(forCompensation); return getPropertyBuilder(); } @@ -103,7 +103,7 @@ public P withInput(Collection input) { public P withOutput(Map output) { AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getOutput() == null) { - state.setOutput(new HashMap<>()); + state.setOutput(new LinkedHashMap<>()); } state.getOutput().putAll(output); return getPropertyBuilder(); @@ -113,7 +113,7 @@ public P withOutput(Map output) { public P withOneOutput(String variable, Object expression) { AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getOutput() == null) { - state.setOutput(new HashMap<>()); + state.setOutput(new LinkedHashMap<>()); } state.getOutput().put(variable, expression); return getPropertyBuilder(); @@ -123,7 +123,7 @@ public P withOneOutput(String variable, Object expression) { public P withStatus(Map status) { AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getStatus() == null) { - state.setStatus(new HashMap<>()); + state.setStatus(new LinkedHashMap<>()); } state.getStatus().putAll(status); return getPropertyBuilder(); @@ -133,7 +133,7 @@ public P withStatus(Map status) { public P withOneStatus(String expression, String status) { AbstractTaskState state = ((AbstractTaskState) getState()); if (state.getStatus() == null) { - state.setStatus(new HashMap<>()); + state.setStatus(new LinkedHashMap<>()); } state.getStatus().put(expression, status); return getPropertyBuilder(); @@ -161,7 +161,6 @@ public P and() { @Override public RetryBuilder

withExceptions(Collection> exceptions) { oneRetry.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); - oneRetry.setExceptionClasses(new ArrayList<>(exceptions)); return this; } @@ -201,7 +200,6 @@ public P and() { @Override public ExceptionMatchBuilder

withExceptions(Collection> exceptions) { oneCatch.setExceptions(exceptions.stream().map(Class::getName).collect(Collectors.toList())); - oneCatch.setExceptionClasses(new ArrayList<>(exceptions)); return this; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java index 532d8e28851..51d6d662f55 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ScriptTaskStateBuilderImpl.java @@ -31,6 +31,12 @@ public class ScriptTaskStateBuilderImpl protected ScriptTaskStateImpl state; + public ScriptTaskStateBuilderImpl() { + state.setForCompensation(false); + state.setForUpdate(false); + state.setPersist(false); + } + @Override public ScriptTaskStateBuilder withScriptType(String scriptType) { state.setScriptType(scriptType); diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java index adda4906087..e7826f3e69f 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java @@ -16,9 +16,13 @@ package io.seata.saga.statelang.builder.impl; +import io.seata.common.util.StringUtils; +import io.seata.saga.statelang.builder.StatesConfigurer; import io.seata.saga.statelang.builder.SubStateMachineBuilder; +import io.seata.saga.statelang.domain.ServiceTaskState; import io.seata.saga.statelang.domain.SubStateMachine; import io.seata.saga.statelang.domain.impl.SubStateMachineImpl; +import io.seata.saga.statelang.parser.impl.CompensateSubStateMachineStateParser; /** * Default implementation for {@link SubStateMachineBuilder} @@ -37,6 +41,28 @@ public SubStateMachineBuilder withStateMachineName(String stateMachineName) { return this; } + protected void beforeBuilt() { + if (StringUtils.isBlank(state.getCompensateState())) { + CompensateSubStateMachineStateParser compensateSubStateMachineStateParser + = new CompensateSubStateMachineStateParser(); + ServiceTaskState subStateMachineCompenState = compensateSubStateMachineStateParser.parse(null); + state.setCompensateStateObject(subStateMachineCompenState); + state.setCompensateState(subStateMachineCompenState.getName()); + } + } + + @Override + public StatesConfigurer and() { + beforeBuilt(); + return super.and(); + } + + @Override + public SubStateMachine build() { + beforeBuilt(); + return super.build(); + } + @Override protected SubStateMachineBuilder getPropertyBuilder() { return this; From 3845508442012edbdc3eabab0ddbaa05d938a9b0 Mon Sep 17 00:00:00 2001 From: PTYin Date: Fri, 15 Sep 2023 09:51:27 +0800 Subject: [PATCH 08/10] style: fix code style against checkstyle --- .../statelang/builder/ChoiceStateBuilder.java | 15 +++++++++++++++ .../CompensateSubStateMachineStateBuilder.java | 15 +++++++++++++++ .../statelang/builder/ScriptTaskStateBuilder.java | 15 +++++++++++++++ .../builder/ServiceTaskStateBuilder.java | 15 +++++++++++++++ .../saga/statelang/builder/StateBuilder.java | 15 +++++++++++++++ .../statelang/builder/StateBuilderFactory.java | 11 ++++++++++- .../saga/statelang/builder/StatesConfigurer.java | 15 +++++++++++++++ .../builder/impl/AbstractTaskStateBuilder.java | 14 +++++++------- .../impl/CompensationTriggerStateBuilderImpl.java | 2 +- .../builder/impl/StatesConfigurerImpl.java | 5 ++++- .../builder/impl/SubStateMachineBuilderImpl.java | 2 +- 11 files changed, 113 insertions(+), 11 deletions(-) diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java index b1f09c22aa3..a06dd55a577 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ChoiceStateBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.builder.prop.ChoicePropertyBuilder; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java index 1badfe6b7ae..481f3401394 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/CompensateSubStateMachineStateBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.builder.prop.ServiceTaskPropertyBuilder; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java index 52ec94c88b0..1659f406592 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ScriptTaskStateBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.builder.prop.BasicPropertyBuilder; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java index 0c8750d516e..e3448a380c8 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/ServiceTaskStateBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.builder.prop.ServiceTaskPropertyBuilder; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java index 6ce06e16c42..e44edf79b75 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.domain.State; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java index 333fb67ea58..36681ec423d 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StateBuilderFactory.java @@ -16,7 +16,16 @@ package io.seata.saga.statelang.builder; -import io.seata.saga.statelang.builder.impl.*; +import io.seata.saga.statelang.builder.impl.ChoiceStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.CompensateSubStateMachineStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.CompensationTriggerStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.FailEndStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.ForkStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.JoinStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.ScriptTaskStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.ServiceTaskStateBuilderImpl; +import io.seata.saga.statelang.builder.impl.SubStateMachineBuilderImpl; +import io.seata.saga.statelang.builder.impl.SuccessEndStateBuilderImpl; import java.util.HashMap; import java.util.Map; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java index 7b69c84b4ce..5edb4cf6f63 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/StatesConfigurer.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package io.seata.saga.statelang.builder; import io.seata.saga.statelang.domain.State; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java index b85d60727ff..9cadc82586e 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/AbstractTaskStateBuilder.java @@ -101,7 +101,7 @@ public P withInput(Collection input) { @Override public P withOutput(Map output) { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getOutput() == null) { state.setOutput(new LinkedHashMap<>()); } @@ -111,7 +111,7 @@ public P withOutput(Map output) { @Override public P withOneOutput(String variable, Object expression) { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getOutput() == null) { state.setOutput(new LinkedHashMap<>()); } @@ -121,7 +121,7 @@ public P withOneOutput(String variable, Object expression) { @Override public P withStatus(Map status) { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getStatus() == null) { state.setStatus(new LinkedHashMap<>()); } @@ -131,7 +131,7 @@ public P withStatus(Map status) { @Override public P withOneStatus(String expression, String status) { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getStatus() == null) { state.setStatus(new LinkedHashMap<>()); } @@ -150,7 +150,7 @@ public class RetryBuilderImpl implements RetryBuilder

{ @Override public P and() { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getRetry() == null) { state.setRetry(new ArrayList<>()); } @@ -189,7 +189,7 @@ public class ExceptionMatchBuilderImpl implements ExceptionMatchBuilder

{ @Override public P and() { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); if (state.getCatches() == null) { state.setCatches(new ArrayList<>()); } @@ -228,7 +228,7 @@ public LoopBuilderImpl() { @Override public P and() { - AbstractTaskState state = ((AbstractTaskState) getState()); + AbstractTaskState state = (AbstractTaskState) getState(); state.setLoop(loop); return getPropertyBuilder(); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java index 042173a95d6..d03666961c6 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/CompensationTriggerStateBuilderImpl.java @@ -27,7 +27,7 @@ */ public class CompensationTriggerStateBuilderImpl extends BaseStateBuilder - implements CompensationTriggerStateBuilder{ + implements CompensationTriggerStateBuilder { protected CompensationTriggerStateImpl state = new CompensationTriggerStateImpl(); diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java index 8bc984e6d95..1ff6d97c8b9 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StatesConfigurerImpl.java @@ -17,7 +17,10 @@ package io.seata.saga.statelang.builder.impl; import io.seata.common.exception.FrameworkException; -import io.seata.saga.statelang.builder.*; +import io.seata.saga.statelang.builder.StateBuilder; +import io.seata.saga.statelang.builder.StateBuilderFactory; +import io.seata.saga.statelang.builder.StateMachineBuilder; +import io.seata.saga.statelang.builder.StatesConfigurer; import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.impl.StateMachineImpl; diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java index e7826f3e69f..c4b5ad27502 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/SubStateMachineBuilderImpl.java @@ -31,7 +31,7 @@ */ public class SubStateMachineBuilderImpl extends AbstractTaskStateBuilder - implements SubStateMachineBuilder{ + implements SubStateMachineBuilder { protected SubStateMachineImpl state; From 5d020fab09bd2eee75c3c0ed4a8ddde06547f353 Mon Sep 17 00:00:00 2001 From: PTYin Date: Fri, 15 Sep 2023 11:25:13 +0800 Subject: [PATCH 09/10] bugfix: revert simpleTestStateMachine --- .../saga/statelang/simple_statelang.json | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/test/src/test/resources/saga/statelang/simple_statelang.json b/test/src/test/resources/saga/statelang/simple_statelang.json index cfe9573bff9..14e52f4c6cc 100644 --- a/test/src/test/resources/saga/statelang/simple_statelang.json +++ b/test/src/test/resources/saga/statelang/simple_statelang.json @@ -8,20 +8,12 @@ "Type": "ServiceTask", "ServiceName": "demoService", "ServiceMethod": "foo", - "Next": "ChoiceState" + "Next": "SecondState" }, - "ChoiceState": { - "Type": "Choice", - "Choices": [ - { - "Expression":"[a] == 1", - "Next":"SecondState" - }, - { - "Expression":"[a] == 2", - "Next":"ThirdState" - } - ] + "SecondState": { + "Type": "ServiceTask", + "ServiceName": "demoService", + "ServiceMethod": "bar" } } } \ No newline at end of file From d369ddde10177bef88ec155680146b6de156077c Mon Sep 17 00:00:00 2001 From: PTYin Date: Wed, 20 Sep 2023 11:16:02 +0800 Subject: [PATCH 10/10] bugfix: rename ForkPropertyBuilder#withTimeout & add logic before StateMachineBuilderImpl#build --- .../builder/impl/ForkStateBuilderImpl.java | 4 +-- .../builder/impl/StateMachineBuilderImpl.java | 2 ++ .../builder/prop/ForkPropertyBuilder.java | 4 +-- .../parser/impl/StateMachineParserImpl.java | 24 +++-------------- .../parser/utils/StateMachineUtils.java | 20 ++++++++++++++ .../statelang/builder/StateBuilderTests.java | 19 +++++++++++++ .../statelang/simple_statemachine.json | 27 ++++++++++++++++++- 7 files changed, 75 insertions(+), 25 deletions(-) diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java index 22e2906f58f..25708f347ac 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/ForkStateBuilderImpl.java @@ -56,8 +56,8 @@ public ForkStateBuilder withParallel(int parallel) { } @Override - public ForkStateBuilder withAwaitTimeout(int awaitTimeout) { - state.setAwaitTimeout(awaitTimeout); + public ForkStateBuilder withTimeout(long timeout) { + state.setTimeout(timeout); return this; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java index 03329ca36b7..627b0ee2e4a 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/impl/StateMachineBuilderImpl.java @@ -21,6 +21,7 @@ import io.seata.saga.statelang.domain.RecoverStrategy; import io.seata.saga.statelang.domain.StateMachine; import io.seata.saga.statelang.domain.impl.StateMachineImpl; +import io.seata.saga.statelang.parser.utils.StateMachineUtils; /** * Default implementation for {@link StateMachineBuilder}. @@ -33,6 +34,7 @@ public class StateMachineBuilderImpl implements StateMachineBuilder { @Override public StateMachine build() { + StateMachineUtils.parseAfterAll(stateMachine); return stateMachine; } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java index 152245d5490..226d15f22f4 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/builder/prop/ForkPropertyBuilder.java @@ -44,8 +44,8 @@ public interface ForkPropertyBuilder

> { /** * Configure max await timeout, default 12 hours. * - * @param awaitTimeout await timeout + * @param timeout await timeout * @return builder for chaining */ - P withAwaitTimeout(int awaitTimeout); + P withTimeout(long timeout); } diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/impl/StateMachineParserImpl.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/impl/StateMachineParserImpl.java index a409989089f..c12c0ef1716 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/impl/StateMachineParserImpl.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/impl/StateMachineParserImpl.java @@ -15,15 +15,12 @@ */ package io.seata.saga.statelang.parser.impl; -import java.util.Map; import io.seata.common.util.StringUtils; import io.seata.saga.statelang.domain.DomainConstants; import io.seata.saga.statelang.domain.RecoverStrategy; import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.StateMachine; -import io.seata.saga.statelang.domain.impl.AbstractTaskState; import io.seata.saga.statelang.domain.impl.BaseState; -import io.seata.saga.statelang.domain.impl.ForkStateImpl; import io.seata.saga.statelang.domain.impl.StateMachineImpl; import io.seata.saga.statelang.parser.JsonParser; import io.seata.saga.statelang.parser.JsonParserFactory; @@ -35,6 +32,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; + /** * State machine language parser * @@ -112,22 +111,7 @@ public StateMachine parse(String json) { stateMachine.putState(stateName, state); }); - Map stateMap = stateMachine.getStates(); - for (State state : stateMap.values()) { - if (state instanceof AbstractTaskState) { - AbstractTaskState taskState = (AbstractTaskState) state; - if (StringUtils.isNotBlank(taskState.getCompensateState())) { - taskState.setForUpdate(true); - - State compState = stateMap.get(taskState.getCompensateState()); - if (compState instanceof AbstractTaskState) { - ((AbstractTaskState) compState).setForCompensation(true); - } - } - } else if (state instanceof ForkStateImpl) { - StateMachineUtils.generateBranchStatesAndPairedJoin((ForkStateImpl) state); - } - } + StateMachineUtils.parseAfterAll(stateMachine); return stateMachine; } @@ -138,4 +122,4 @@ public String getJsonParserName() { public void setJsonParserName(String jsonParserName) { this.jsonParserName = jsonParserName; } -} \ No newline at end of file +} diff --git a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/utils/StateMachineUtils.java b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/utils/StateMachineUtils.java index 6ffe952b2dc..d46c362a13a 100644 --- a/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/utils/StateMachineUtils.java +++ b/saga/seata-saga-statelang/src/main/java/io/seata/saga/statelang/parser/utils/StateMachineUtils.java @@ -24,6 +24,7 @@ import io.seata.saga.statelang.domain.State; import io.seata.saga.statelang.domain.StateMachine; import io.seata.saga.statelang.domain.TaskState; +import io.seata.saga.statelang.domain.impl.AbstractTaskState; import io.seata.saga.statelang.domain.impl.ForkStateImpl; import io.seata.saga.statelang.parser.ParserException; @@ -164,4 +165,23 @@ public static Map getStateToParentForkMap(StateMachine st } return stateNameToParentForkMap; } + + public static void parseAfterAll(StateMachine stateMachine) { + Map stateMap = stateMachine.getStates(); + for (State state : stateMap.values()) { + if (state instanceof AbstractTaskState) { + AbstractTaskState taskState = (AbstractTaskState) state; + if (StringUtils.isNotBlank(taskState.getCompensateState())) { + taskState.setForUpdate(true); + + State compState = stateMap.get(taskState.getCompensateState()); + if (compState instanceof AbstractTaskState) { + ((AbstractTaskState) compState).setForCompensation(true); + } + } + } else if (state instanceof ForkStateImpl) { + StateMachineUtils.generateBranchStatesAndPairedJoin((ForkStateImpl) state); + } + } + } } diff --git a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java index 02a7d1566ba..9061fc3decb 100644 --- a/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java +++ b/saga/seata-saga-statelang/src/test/java/io/seata/saga/statelang/builder/StateBuilderTests.java @@ -93,6 +93,7 @@ void testBuildStateMachine() throws IOException { .withName("ChoiceState") .withChoice("foo == 1", "FirstMatchState") .withChoice("foo == 2", "SecondMatchState") + .withChoice("foo == 3", "ThirdMatchState") .withDefault("FailState") .and() .build(ServiceTaskStateBuilder.class) @@ -160,6 +161,24 @@ void testBuildStateMachine() throws IOException { .withOneOutput("firstMatchStateResult", "$.#root") .withNext("SuccessState") .and() + .build(ForkStateBuilder.class) + .withName("ThirdMatchState") + .withBranches(Arrays.asList("FirstParallel", "SecondParallel")) + .withTimeout(1000) + .withParallel(2) + .and() + .build(ServiceTaskStateBuilder.class) + .withName("FirstParallel") + .withNext("JoinState") + .and() + .build(ServiceTaskStateBuilder.class) + .withName("SecondParallel") + .withNext("JoinState") + .and() + .build(JoinStateBuilder.class) + .withName("JoinState") + .withNext("SuccessState") + .and() .build(FailEndStateBuilder.class) .withName("FailState") .withErrorCode("DefaultStateError") diff --git a/saga/seata-saga-statelang/src/test/resources/statelang/simple_statemachine.json b/saga/seata-saga-statelang/src/test/resources/statelang/simple_statemachine.json index 417d3b5b8de..919d48ca77e 100644 --- a/saga/seata-saga-statelang/src/test/resources/statelang/simple_statemachine.json +++ b/saga/seata-saga-statelang/src/test/resources/statelang/simple_statemachine.json @@ -35,6 +35,10 @@ { "Expression": "foo == 2", "Next": "SecondMatchState" + }, + { + "Expression": "foo == 3", + "Next": "ThirdMatchState" } ], "Default": "FailState" @@ -126,6 +130,27 @@ }, "Next": "SuccessState" }, + "ThirdMatchState": { + "Type": "Fork", + "Branches": [ + "FirstParallel", + "SecondParallel" + ], + "Timeout": 1000, + "Parallel": 2 + }, + "FirstParallel": { + "Type": "ServiceTask", + "Next": "JoinState" + }, + "SecondParallel": { + "Type": "ServiceTask", + "Next": "JoinState" + }, + "JoinState": { + "Type": "Join", + "Next": "SuccessState" + }, "FailState": { "Type": "Fail", "ErrorCode": "DefaultStateError", @@ -135,4 +160,4 @@ "Type": "Succeed" } } -} \ No newline at end of file +}