Code Monkey home page Code Monkey logo

spring-statemachine's Introduction

Spring Statemachine

badge (GitHub default) Revved up by Gradle Enterprise

The Spring Statemachine project aims to provide a common infrastructure to work with state machine concepts in Spring applications.

It is advised to check the actual state of this project by referring to the latest releases found on Spring Statemachine Project Page. The git repo default branch may be relatively unstable when new features are added into the source code.

Code of Conduct

This project adheres to the Contributor Covenant code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].

Downloading Artifacts

See downloading Spring artifacts for Maven repository information.

Documentation

The Spring Statemachine Project Page contains links to currently available JavaDoc and Reference Documentation for particular releases and versions.

Samples

Samples can be found under spring-statemachine-samples. Check the reference documentation more about what those do.

Building from Source

Spring Statemachine uses a Gradle-based build system. In the instructions below, ./gradlew is invoked from the root of the source tree and serves as a cross-platform, self-contained bootstrap mechanism for the build.

Prerequisites

Git and the JDK8 build.

Be sure that your JAVA_HOME environment variable points to the jdk folder extracted from the JDK download. While build requires JDK8, created artifacts are JDK7 compatible.

Check out sources

git clone [email protected]:spring-projects/spring-statemachine.git

Install all spring-\* jars into your local Maven cache

./gradlew install

Compile and test; build all jars, distribution zips, and docs

./gradlew build

Discover more commands with ./gradlew tasks. See also the Gradle build and release FAQ.

Contributing

Pull requests are welcome; see the contributor guidelines for details.

If you want to contribute, search github tickets marked with help wanted or come up with your own ticket but please first open a ticket to discuss in order to avoid duplicate work on a topic or issue. Nobody wants to see the same work done twice!

License

Spring Statemachine is Open Source software released under the Apache 2.0 license.

spring-statemachine's People

Contributors

adarwesley avatar alexandrenavarro avatar cschwalm avatar danielsiwiec avatar donquih0te avatar egreijus avatar enadim avatar erichaagdev avatar fabiofalci avatar flycash avatar github-actions[bot] avatar gvagenas avatar hamid646m avatar hazim1093 avatar heffebaycay avatar hielsnoppe avatar jonseah avatar jonybuzz avatar jvalkeal avatar manedev79 avatar mprimi avatar nicolacammillini avatar ouaibsky avatar pangyikhei avatar pinguet62 avatar qeeqez avatar spring-builds avatar spring-operator avatar tarioch avatar xjoewoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-statemachine's Issues

Small C&P error in README.adoc

I believe the first sentence of the section "Building from Source" in README.adoc should be

"Spring Statemachine uses a Gradle-based build system."

instead of

"Spring Security Kerberos uses a Gradle-based build system."

Tests are fragile

Once and awhile the tests fail. Saw a failed test in CdPlayerTests.testPlayLcdTimeChanges and this one at
demo.cdplayer.CdPlayerTests.testPlayPause(CdPlayerTests.java:171)

Using latches to test asynchronous stuff is difficult

java.lang.AssertionError:
Expected: is <2>
but: was <1>
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.junit.Assert.assertThat(Assert.java:865)
at org.junit.Assert.assertThat(Assert.java:832)
at demo.cdplayer.CdPlayerTests.testPlayPause(CdPlayerTests.java:171)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Parallel Statemachine

I looked at spring-statemachine and its hierarchical state machines.

What I was looking for was more like parallel state machines where the transitions are between a tuple pair of states, one state from statemachine a and one from statemachine b. Perhaps with identical state sets or different state sets.

Then you can model eventual consistency where some tuple pairs are "rest states" where the two states corresponds in some abstract meaning and some are "volatile states" with where trigger ready transitions tries to bring it into a "rest state".

Another advantage is that states can be changed externally, outside the control of the statemachine, and the state pair transitions will bring the system into consistency.

Is this something that is achievable with spring-statemachine.

Transition from simple to other substate doesn't work

With states [S1, S2[S20,S21]]:

Doing transitions:
S1-S2, S20-S21, S2-S1, S1-S21

We should end up in states S2, S21, instead we're left to S1.

Problem seem to be that we try to transit from simple state to substate in other machine.

Add hierarchical event processing

Currently only top-level machine is processing events and thus transitions only happens there. Need to modify concepts so that event first goes to active sub-machine and then to its parents if event is not accepted. Then we can add transition configuration to all machines and same thing should also happen with regions(where event processing is a little different).

Add testing framework

As seen how current samples are tested, it is tedious and a bit fragile #36 process. It's time to come up with a proper testing package which would ease a whole process of going through the testing cycle of states, transitions, etc.

Effective this framework should provide a player of some sort for your machine configuration.

Should not define terminate state as state

We should not have a need to define terminate state as state as shown below(should work when as commented below):

        @Override
        public void configure(StateMachineStateConfigurer<TestStates3, TestEvents> states)
                throws Exception {
            states
                .withStates()
                    .initial(TestStates3.READY)
                    .fork(TestStates3.FORK)
                    .state(TestStates3.TASKS)
                    .join(TestStates3.JOIN)
                    .and()
                    .withStates()
                        .parent(TestStates3.TASKS)
                        .initial(TestStates3.T1)
//                      .state(TestStates3.T1E)
                        .end(TestStates3.T1E)
                        .and()
                    .withStates()
                        .parent(TestStates3.TASKS)
                        .initial(TestStates3.T2)
//                      .state(TestStates3.T2E)
                        .end(TestStates3.T2E)
                        .and()
                    .withStates()
                        .parent(TestStates3.TASKS)
                        .initial(TestStates3.T3)
//                      .state(TestStates3.T3E)
                        .end(TestStates3.T3E);
        }

Define SPI for internal statemachine communication

StateMachine interface is a really meant for external usage and is not suitable for internal communication between statemachines. i.e. use case would bet with multiple regions where statemachines should have better ways collaborate between each others.

Support true parallel regions

Current model of event execution is run-to-completion which is the fundamental aspect of state machines. UML notation really doesn't require of parallel execution and thus it's left for the implementation. Most of the cases parallel execution would not even work, thus breaking a whole concept, but in case of region state it makes sense because its regions are really independent.

Event is given to each region and this really makes execution synchronous, while we should allow parallel event handling for these use cases.

TaskExecutor not created automatically

It was kinda mistake that we never added TaskExecutor creating automatically via configuration when it's needed with 1.0.0.M1. We need to align this with #7 so that if we get a pluggable event handling(i.e. with reactor) user should not have a need to add executor bean manually.

Add support for pseudostates

This is a first stage of adding support for pseudostates so we only need support for INITIAL. Rest of the pseudostates in separate tickets.

Should not need to attach fork/join to region states

Currently we need to draw line from fork/join to every target/source in a states within a regions. This is ok if we want a controlled entry/exit but if we just rely initial/terminate states, it should be enough to just point to region state hosting regions.

Move common annotation classes

Stuff under org.springframework.statemachine.config.common are common base classes for annotation based adapter callbacks and should be removed in a shared location. Those together with sm classes were just copied over from shdp. We need common place for those classes to be used from this project and shdp.

Add better builder for programmatic instantiation

If user wants to build machine without @Configuration classes and adapters, i.e. using a builder which simply returns a pojo, it's a little tedious task. We don't have this kind of builder yet and using all needed machine classes directly is something user should not do.

We need to either create a generic builder or recipes which would allow to fine tune builder for specific use cases.

Pluggable event handling

Currently we spawn tasks via spring task scheduler which is not optimal. It'd be nice if event handling framework could be refactored so that we could have a pluggable event execution.

Submachine not started with non initial transition

Below config illustrates the problem:

    @Configuration
    @EnableStateMachine
    static class Config3 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {

        @Override
        public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
            states
                .withStates()
                    .initial(TestStates.S1)
                    .state(TestStates.S1)
                    .state(TestStates.S2)
                    .and()
                    .withStates()
                        .parent(TestStates.S2)
                        .initial(TestStates.S20)
                        .state(TestStates.S20)
                        .state(TestStates.S21)
                        .and()
                        .withStates()
                            .parent(TestStates.S21)
                            .initial(TestStates.S211)
                            .state(TestStates.S211)
                            .state(TestStates.S212);
        }

        @Override
        public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
            transitions
                .withExternal()
                    .source(TestStates.S1)
                    .target(TestStates.S212)
                    .event(TestEvents.E1);
        }

    }

Last submachine is not started because transition to it is not going through initial state. Turned out we don't have a test for this scenario.

Add support for error handler

Beyond adding a features around error handling we should also add a special internal state to a statemachine itself indicating a health of a machine itself. i.e. if machine goes through an unrecoverable error, machine should go into its internal error state, notify user and stop event processing.

Add support for time based triggers

Currently we only have event based triggers. UML defines call, change, signal and timed events/triggers. At least we should support timers which is really only way for statemaching to do something automatically.

Add a flag to disable app context events

Currently application context events are published automatically which is just noise if user are not using those and it will make performance worse if a lot of state and transition events are sent. We could i.e. have flags in annotations, etc.

StateContext may use wrong statemachine

When actions are executed within a submachine, reference to a statemachine the submachine which is a bit wrong if you want to send events. This machine reference should be the root machine.

Feature to check if the statemachine would currently accept an event

As discussed here, it would be nice if it was possible to check if the statemachine would currently accept an event (like sendEvent(...) but without triggering a transition).

Use case:

I have some UI buttons which send events to the state machine. My use case is to enable/disable these buttons depending on whether the state machine would accept their event or not.

Should not define initial state as state

Currently we need to do this:

@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
  states
    .withStates()
      .initial(States.IDLE)
      .state(States.IDLE)
}

should tweak configurer so that state() is not needed for particular state if it's already introduced with initial().

bean overriding conflict

in combination with spring-security the ObjectPostProcessorConfiguration in @EnableStateMachine overrides the one from spring-security since they have the same bean name with @EnableGlobalMethodSecurity , maybe add @ConditionalOnMissingBean , since removing the ObjectPostProcessorConfiguration was sufficient

RegionState not created with nested states

Having config:

@Override
public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
    states
        .withStates()
            .initial(TestStates.SI)
            .state(TestStates.SI)
            .state(TestStates.S2)
            .end(TestStates.SF)
            .and()
            .withStates()
                .parent(TestStates.S2)
                .initial(TestStates.S20)
                .state(TestStates.S20)
                .state(TestStates.S21)
                .and()
            .withStates()
                .parent(TestStates.S2)
                .initial(TestStates.S30)
                .state(TestStates.S30)
                .state(TestStates.S31);
}

S2 is wrongly creates as a StateMachineState and things get broken.

Triggerless transition in regions is difficult

Below shows that problem, if we want to do triggerless transitions in regions, those need to be defined with a state() in a configurer matching regions parent state. This works but is very unintuitive because that function was originally added to be able to define override features, thus we should not need it for these use cases.

We need to re-design whole triggerless transition logic how it is handled in a sm and its submachines and regions.

    @Configuration
    @EnableStateMachine
    public static class Config5 extends EnumStateMachineConfigurerAdapter<TestStates, TestEvents> {

        @Override
        public void configure(StateMachineStateConfigurer<TestStates, TestEvents> states) throws Exception {
            states
                .withStates()
                    .initial(TestStates.S1)
                    .state(TestStates.S2)
                    .and()
                    .withStates()
                        .parent(TestStates.S2)
                        .initial(TestStates.S20)
                        .state(TestStates.S201)
                        .end(TestStates.S201)
                        .and()
                    .withStates()
                        .parent(TestStates.S2)
                        .initial(TestStates.S21)
                        .state(TestStates.S211)
                        .end(TestStates.S211);
        }

        @Override
        public void configure(StateMachineTransitionConfigurer<TestStates, TestEvents> transitions) throws Exception {
            transitions
                .withExternal()
                    .source(TestStates.S1)
                    .target(TestStates.S2)
                    .event(TestEvents.E1)
                    .and()
                .withExternal()
                    .state(TestStates.S2)
                    .source(TestStates.S20)
                    .target(TestStates.S201)
                    .and()
                .withExternal()
                    .state(TestStates.S2)
                    .source(TestStates.S21)
                    .target(TestStates.S211);
        }

    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.