beh01der / easyflow Goto Github PK
View Code? Open in Web Editor NEWEasyFlow - Simple and lightweight Finite State Machine for Java
Home Page: http://datasymphony.com.au/open-source/easyflow
License: Apache License 2.0
EasyFlow - Simple and lightweight Finite State Machine for Java
Home Page: http://datasymphony.com.au/open-source/easyflow
License: Apache License 2.0
probably it would be easier for end user if you allowed to use jdk enum:
enum UserState implements EasyFlow.State {}
enum UserEvent implements EasyFlow.Event {}
please release to maven central
I can not build the Gradle-project using your library due to the fact that the duplicated depending on org.slf4j: slf4j-api: 1.7.2:
--- au.com.datasymphony:EasyFlow:1.3.1
+--- org.slf4j:slf4j-api:1.7.2
+--- com.google.guava:guava:15.0
--- org.slf4j:slf4j-log4j12:1.7.2
+--- org.slf4j:slf4j-api:1.7.2
--- log4j:log4j:1.2.17
Hi, Andrey
Firstly, thank you for very good library.
So powerfull and simple.
But I can't figure out the right way to handle exception during state process.
What the right way to "clean up" after exception?
In some situation I wanna to revert to previous state. In others I prefer restart flow. How make this?
In my App developed in Android Studio I am using EasyFlow but the events are not triggered in a reproducible manner:
All are in the main thread; here are extracts of my code:
onSelectingMainMenu.to(MAIN_MENU).transit(
onReturnToPreviousChoice.to(READY),
onSelectingMainMenuFinished.to(READY),
onSelectingSettingsMenu.to(SETTINGS_MENU).transit(
onReturnToPreviousChoice.to(MAIN_MENU)
)
)
...
switch (direction) {
case TOP:
onReturnToPreviousChoice.trigger(flowContext);
...
Any help?
Thank you.
I am trying to use EasyFlow for my project, but I am facing a problem, because I cannot find out from which package comes the "StatefulContext" class.
This class appears to be founmental, because all the "FlowConntext" should extend the "StatefulContext" class.
In case you know where I can find the "StatefulContext", please leave a comment below.
I'm trying to implement simple FSM to manage UI state in Android application. Here is a problem I found (isolated to an abstract example):
FSM definition (pseudo code):
State { A, B, C }
Event { next }
fsm = from(State.A).transit(
on(Event.next).to(State.B).transit(
on(Event.next).to(State.C).transit(
on(Event.next).to(State.A)
)
)
);
fsm.executor(new UIThreadExecutor()); // same as in android ATM example
Handler on "whenEnter":
mFlow.whenEnter(new StateHandler<FlowContext>() {
@Override
public void call(StateEnum state, FlowContext context) throws Exception {
println("entering: " + state);
Thread.sleep(200); // delay handler execution, so that issue become repeatable
}
});
Now, last but not least, following code is executed on some event (eg. button press):
mContext.trigger(Event.next);
mContext.trigger(Event.next);
mContext.trigger(Event.next);
Expected result:
entering: A
entering: B
entering: C
entering: A
Observed result:
entering: A
entering: B
entering: B
entering: B
My understanding of what causes an issue here:
After looking briefly into code I see that triggering is implemented in a strange way by splitting it to two runnables: first, handlers are called in separate executor task, but then another executor task is added to do actual state switching (setCurrentState method). So, as a matter of luck, if second task (state change) is interleaved with another trigger, we may observe handlers being called twice for same transition.
Thanks for this awesome and really lightweight engine!!!
But for my requirements i need to have a support of event triggering scheduling.
I suggest to add a special method for this in Event class:
public void scheduledTrigger(final C context, long delay, TimeUnit unit) {
scheduledExecutorService.schedule(new Runnable() {
trigger(context);
}, delay, unit);
}
scheduledExecutorService - should be configurable like executor in EasyFlow object.
What do you think about such feature?
Hello.
Looks like there is issue in whenEnter(StateHandler onEnter) logic.
public <C1 extends StatefulContext> EasyFlow<C1> whenEnter(StateHandler<C1> onEnter) {
handlers.setHandler(EventType.STATE_ENTER, null, null, onEnter);
return (EasyFlow<C1>) this;
}
It should be
handlers.setHandler(EventType.ANY_STATE_ENTER, null, null, onEnter);
not
handlers.setHandler(EventType.STATE_ENTER, null, null, onEnter);
Current version never invoke onEnter at all because HandlerCollection#callOnStateEntered
is trying to find handler without specific state and with type ANY_STATE_ENTER
public <C extends StatefulContext> void callOnStateEntered(StateEnum state, C context) throws Exception {
Handler h = handlers.get(new HandlerType(EventType.STATE_ENTER, null, state));
if (h != null) {
ContextHandler<C> contextHandler = (ContextHandler<C>) h;
contextHandler.call(context);
}
h = handlers.get(new HandlerType(EventType.ANY_STATE_ENTER, null, null));
if (h != null) {
StateHandler<C> stateHandler = (StateHandler<C>) h;
stateHandler.call(state, context);
}
}
Hello.
Looks like there is issue in whenEnter(StateHandler onEnter) logic.
public <C1 extends StatefulContext> EasyFlow<C1> whenEnter(StateHandler<C1> onEnter) {
handlers.setHandler(EventType.STATE_ENTER, null, null, onEnter);
return (EasyFlow<C1>) this;
}
It should be
handlers.setHandler(EventType.ANY_STATE_ENTER, null, null, onEnter);
not
handlers.setHandler(EventType.STATE_ENTER, null, null, onEnter);
Current version never invoke onEnter at all because HandlerCollection#callOnStateEntered
is trying to find handler without specific state and with type ANY_STATE_ENTER
public <C extends StatefulContext> void callOnStateEntered(StateEnum state, C context) throws Exception {
Handler h = handlers.get(new HandlerType(EventType.STATE_ENTER, null, state));
if (h != null) {
ContextHandler<C> contextHandler = (ContextHandler<C>) h;
contextHandler.call(context);
}
h = handlers.get(new HandlerType(EventType.ANY_STATE_ENTER, null, null));
if (h != null) {
StateHandler<C> stateHandler = (StateHandler<C>) h;
stateHandler.call(state, context);
}
}
Hi, I'm using the jar in a very simple test app in plain java and get the following exception. Any advice? I don't see this class in the jar anywhere.
Thanks, Mike
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at au.com.ds.ef.FlowBuilder.<clinit>(FlowBuilder.java:7)
SyncExecutor seems to be implemented in a thread-safe manner. Right?
Hi, Andrey.
The library looks promising to me, but I am a little bit confused that it was not updated for years. Did you switch off Android development, or decided that the pattern does not work well / there are better ways to structure the screen logic? Or you're just using it as a proven tool and do not have a need to make it better?
Can you please elaborate on the effectiveness of the pattern. Do you use it in every app/on every screen, or it fits only some cases?
I'm using easyflow to manage state change in a file parser and so far it's come in quite handy. However one thing I can't figure out is why after I reach a final state, the context reports itself as terminated, but the flow engine keeps going.
Is there a recommended way to exit the entire FlowEngine when your processing is complete?
EDIT: I found a solution, for anyone looking; create your own Executor class, instantiate your EasyFlow object with it, and call shutdownNow() on the executorservice once your context terminates.
Would be nice to have something like that be a built in option though, or at least the ability to tell EasyFlow to terminate directly.
Hi,
I have the following use case, when a main flow reaches to some state, it should split into several branches, the branches then are worked independently. When each branch is complete, the main flow should resume.
If you want a real case, then here it is. A loan application reaches to a point, where security, legal and some other services are needed to provide their input. After all the inputs are collected, the loan application goes to the next stage.
Is this scenario supported?
Hello,
Is there a way we can add support for non-deterministic Finite state machine.??
Does we currently support them by any mean or we can support them by some extensions!! any future plans for same??
instead of "tree style" like
flow = FlowBuilder
.from(SHOWING_WELCOME).transit(
onCardPresent.to(WAITING_FOR_PIN).transit(
onPinProvided.to(CHECKING_PIN).transit(
onPinValid.to(SHOWING_MAIN_MENU).transit(
onMenuShowBalance.to(SHOWING_BALANCE).transit(
onCancel.to(SHOWING_MAIN_MENU)
),
onMenuWithdrawCash.to(SHOWING_WITHDRAW_MENU).transit(
onCancel.to(SHOWING_MAIN_MENU),
onConfirm.to(SHOWING_TAKE_CASH).transit(
onCashExtracted.to(SHOWING_MAIN_MENU)
)
),
onMenuExit.to(RETURNING_CARD)
),
onPinInvalid.to(SHOWING_PIN_INVALID).transit(
onTryAgain.to(WAITING_FOR_PIN),
onNoMoreTries.to(SHOWING_CARD_LOCKED).transit(
onConfirm.to(SHOWING_WELCOME)
),
onCancel.to(RETURNING_CARD)
)
),
onCancel.to(RETURNING_CARD).transit(
onCardExtracted.to(SHOWING_WELCOME)
)
)
)
...
something like
flow = FlowBuilder.register(SHOWING_WELCOME,
onCardPresent.to(WAITING_FOR_PIN)
);
FlowBuilder.register(WAITING_FOR_PIN,
onPinProvided.to(CHECKING_PIN),
onCancel.to(RETURNING_CARD)
);
...
FlowBuilder.register(SHOWING_PIN_INVALID,
onTryAgain.to(WAITING_FOR_PIN),
onNoMoreTries.to(SHOWING_CARD_LOCKED),
onCancel.to(RETURNING_CARD)
);
... ...
Hello.
I realize this library is relatively easy to use and the error messages are telling (thanks) but it would still be nice if every exposed object/method had JavaDoc so users don't have to do trial-and-error when learning it.
One concrete example I had that was slightly frustrating is when I was encountering a race condition error when I didn't have an executor (it said I was in state "null" when I called 'trigger'; yet when I debugged it showed it in state "INITIAL_STATE" and it passed the trigger fine.) If I knew how this executor was used, I might have known to use it and thus avoided that race condition issue.
P.S. Not sure if the above is expected behavior.
Hi Andrey,
Thank you for your library, along with greenrobot EventBus, it helped us scale our background processing engine in our Android app!
It may be a non-issue but in certain of our state handler sub-classes, we initialize resources (ex: register broadcast receivers, holding a wakelock, etc.). However, for transitions that are not initiated within a state, it would be nice to have a mirror handler method for call(), named terminate() where we can resource clean-up.
Please let me know what you think, maybe I am misusing the APIs and there is already a facility in place for this scenario.
Thanks!
-Antoine
Hello everyone,
I am trying to use the EasyFlow framework, but I have a problem when I try to call the "on" method.
I have writen the following code:
public enum States implements StateEnum {
NEW, SUGGESTION
}
public enum Events implements EventEnum {
CONFIRM, CANCEL
}
EasyFlow<FlowContext> flow =
FlowBuilder.from(States.NEW)
.transit(
on(Events.CONFIRM).to(States.SUGGESTION));
At the code above, the "on" method is not recognized.
Do you have any idea how I could resolve this problem?
Sad, the sample project does not even work and looked promising :( Is this project super outdated? What about the maven sources? I would like to try it out :)
I like to use easy flow for a regular java project is it possible to do so?
Hi guys,
I am writing a Paper on Open Source Workflow Engines(WE). Can you tell me if your WE can support the Control-Flow Patterns described under http://www.workflowpatterns.com/patterns/control/ ? If you are not sure, can you provide a Getting Started Doc or an Example for a simple Sequence Workflow, so i can try to check it myself?
thank you,
Silviu
There is possible race condition during flow starting.
Example:
flow.start(true, context);
flow.trigger(SomeEvent);
Flow start calls setCurrentState which is using executor to set current state, but it's possible that initial state won't be initialised before actual trigger method call if we call trigger just after start.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.