Skip to content

Commit 467bf35

Browse files
author
Beh01der
committed
Initial commit to GitHub
0 parents  commit 467bf35

22 files changed

+1760
-0
lines changed

pom.xml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>au.com.ds.ef</groupId>
5+
<artifactId>EasyFlow</artifactId>
6+
<version>1.0</version>
7+
<packaging>jar</packaging>
8+
<name>EasyFlow</name>
9+
<description>EasyFlow - Simple and lightweight Finite State Machine</description>
10+
11+
<build>
12+
<plugins>
13+
<plugin>
14+
<groupId>org.apache.maven.plugins</groupId>
15+
<artifactId>maven-compiler-plugin</artifactId>
16+
<version>2.5.1</version>
17+
<configuration>
18+
<source>1.6</source>
19+
<target>1.6</target>
20+
</configuration>
21+
</plugin>
22+
<plugin>
23+
<groupId>org.apache.maven.plugins</groupId>
24+
<artifactId>maven-source-plugin</artifactId>
25+
<executions>
26+
<execution>
27+
<id>attach-sources</id>
28+
<goals>
29+
<goal>jar</goal>
30+
</goals>
31+
</execution>
32+
</executions>
33+
</plugin>
34+
</plugins>
35+
</build>
36+
<dependencies>
37+
<dependency>
38+
<groupId>com.google.guava</groupId>
39+
<artifactId>guava</artifactId>
40+
<version>14.0-rc3</version>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.slf4j</groupId>
44+
<artifactId>slf4j-api</artifactId>
45+
<version>1.7.2</version>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.slf4j</groupId>
49+
<artifactId>slf4j-log4j12</artifactId>
50+
<version>1.7.2</version>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>junit</groupId>
55+
<artifactId>junit</artifactId>
56+
<version>4.11</version>
57+
<scope>test</scope>
58+
</dependency>
59+
</dependencies>
60+
</project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package au.com.ds.ef;
2+
3+
import java.util.concurrent.Executor;
4+
import java.util.concurrent.Executors;
5+
6+
public class AsyncExecutor implements Executor {
7+
private Executor executor = Executors.newSingleThreadExecutor();
8+
9+
@Override
10+
public void execute(Runnable task) {
11+
executor.execute(task);
12+
}
13+
}
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
package au.com.ds.ef;
2+
3+
import au.com.ds.ef.call.*;
4+
import au.com.ds.ef.err.ExecutionError;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import java.util.concurrent.Executor;
9+
10+
11+
public class EasyFlow<C extends StatefulContext> {
12+
private static Logger log = LoggerFactory.getLogger(EasyFlow.class);
13+
protected State<C> startState;
14+
private C context;
15+
private Executor executor;
16+
private boolean validated;
17+
18+
private StateHandler<C> onStateEnterHandler;
19+
private StateHandler<C> onStateLeaveHandler;
20+
private StateHandler<C> onFinalStateHandler;
21+
private EventHandler<C> onEventTriggeredHandler;
22+
private ContextHandler<C> onTerminateHandler;
23+
private ExecutionErrorHandler onError;
24+
private boolean trace = false;
25+
26+
protected EasyFlow(State<C> startState, TransitionBuilder<C>... transitions) {
27+
this.startState = startState;
28+
this.validated = false;
29+
for (TransitionBuilder<C> transition : transitions) {
30+
startState.addEvent(transition.getEvent(), transition.getStateTo());
31+
}
32+
}
33+
34+
private void prepare() {
35+
startState.setFlowRunner(this);
36+
if (executor == null) {
37+
executor = new AsyncExecutor();
38+
}
39+
40+
if (onError == null) {
41+
onError = new DefaultErrorHandler();
42+
}
43+
}
44+
45+
public EasyFlow<C> validate() {
46+
if (!validated) {
47+
prepare();
48+
49+
LogicValidator<C> validator = new LogicValidator<C>(startState);
50+
validator.validate();
51+
validated = true;
52+
}
53+
54+
return this;
55+
}
56+
57+
public void start(final C context) {
58+
validate();
59+
this.context = context;
60+
61+
if (context.getState() == null) {
62+
setCurrentState(startState, context);
63+
}
64+
}
65+
66+
@SuppressWarnings("unchecked")
67+
protected void setCurrentState(final State<C> state, final C context) {
68+
execute(new Runnable() {
69+
@Override
70+
public void run() {
71+
if (isTrace())
72+
log.debug("setting current state to {} for {} <<<", state, context);
73+
74+
State<C> prevState = context.getState();
75+
if (prevState != null) {
76+
prevState.leave(context);
77+
}
78+
79+
context.setState(state);
80+
context.getState().enter(context);
81+
82+
if (isTrace())
83+
log.debug("setting current state to {} for {} >>>", state, context);
84+
}
85+
});
86+
}
87+
88+
protected void execute(Runnable task) {
89+
executor.execute(task);
90+
}
91+
92+
public C getContext() {
93+
return context;
94+
}
95+
96+
public EasyFlow<C> whenEventTriggered(EventHandler<C> onEventTriggered) {
97+
this.onEventTriggeredHandler = onEventTriggered;
98+
return this;
99+
}
100+
101+
protected void callOnEventTriggered(Event<C> event, State<C> from, State<C> to, C context) throws Exception {
102+
if (onEventTriggeredHandler != null) {
103+
try {
104+
if (isTrace())
105+
log.debug("when triggered {} in {} for {} <<<", event, from, context);
106+
107+
onEventTriggeredHandler.call(event, from, to, context);
108+
109+
if (isTrace())
110+
log.debug("when triggered {} in {} for {} >>>", event, from, context);
111+
} catch (Exception e) {
112+
callOnError(new ExecutionError(from, event, e,
113+
"Execution Error in [EasyFlow.whenEventTriggered] handler", context));
114+
}
115+
}
116+
}
117+
118+
public EasyFlow<C> whenStateEnter(StateHandler<C> onStateEnter) {
119+
this.onStateEnterHandler = onStateEnter;
120+
return this;
121+
}
122+
123+
protected void callOnStateEnter(final State<C> state, final C context) {
124+
if (onStateEnterHandler != null) {
125+
try {
126+
if (isTrace())
127+
log.debug("when enter state {} for {} <<<", state, context);
128+
129+
onStateEnterHandler.call(state, context);
130+
131+
if (isTrace())
132+
log.debug("when enter state {} for {} >>>", state, context);
133+
} catch (Exception e) {
134+
callOnError(new ExecutionError(state, null, e,
135+
"Execution Error in [EasyFlow.whenStateEnter] handler", context));
136+
}
137+
}
138+
}
139+
140+
public EasyFlow<C> whenStateLeave(StateHandler<C> onStateLeave) {
141+
this.onStateLeaveHandler = onStateLeave;
142+
return this;
143+
}
144+
145+
protected void callOnStateLeave(final State<C> state, final C context) {
146+
if (onStateLeaveHandler != null) {
147+
try {
148+
if (isTrace())
149+
log.debug("when leave state {} for {} <<<", state, context);
150+
151+
onStateLeaveHandler.call(state, context);
152+
153+
if (isTrace())
154+
log.debug("when leave state {} for {} >>>", state, context);
155+
} catch (Exception e) {
156+
callOnError(new ExecutionError(state, null, e,
157+
"Execution Error in [EasyFlow.whenStateLeave] handler", context));
158+
}
159+
}
160+
}
161+
162+
public EasyFlow<C> whenFinalState(StateHandler<C> onFinalState) {
163+
this.onFinalStateHandler = onFinalState;
164+
return this;
165+
}
166+
167+
protected void callOnFinalState(final State<C> state, final C context) {
168+
try {
169+
if (onFinalStateHandler != null) {
170+
if (isTrace())
171+
log.debug("when final state {} for {} <<<", state, context);
172+
173+
onFinalStateHandler.call(state, context);
174+
175+
if (isTrace())
176+
log.debug("when final state {} for {} >>>", state, context);
177+
}
178+
179+
synchronized (context) {
180+
callOnTerminate(context);
181+
context.notifyAll();
182+
}
183+
184+
} catch (Exception e) {
185+
callOnError(new ExecutionError(state, null, e,
186+
"Execution Error in [EasyFlow.whenFinalState] handler", context));
187+
}
188+
}
189+
190+
public EasyFlow<C> whenError(ExecutionErrorHandler onError) {
191+
this.onError = onError;
192+
return this;
193+
}
194+
195+
public EasyFlow<C> whenTerminate(ContextHandler onTerminateHandler) {
196+
this.onTerminateHandler = onTerminateHandler;
197+
return this;
198+
}
199+
200+
public void waitForCompletion() {
201+
waitForCompletion(context);
202+
}
203+
204+
public void waitForCompletion(C context) {
205+
try {
206+
synchronized (context) {
207+
context.wait();
208+
}
209+
} catch (InterruptedException e) {
210+
log.error("Error", e);
211+
}
212+
}
213+
214+
public EasyFlow<C> executor(Executor executor) {
215+
this.executor = executor;
216+
return this;
217+
}
218+
219+
public EasyFlow<C> trace() {
220+
trace = true;
221+
return this;
222+
}
223+
224+
protected boolean isTrace() {
225+
return trace;
226+
}
227+
228+
protected void callOnError(final ExecutionError error) {
229+
if (onError != null) {
230+
onError.call(error);
231+
}
232+
233+
synchronized (error.getContext()) {
234+
callOnTerminate((C) error.getContext());
235+
error.getContext().notifyAll();
236+
}
237+
}
238+
239+
protected void callOnTerminate(final C context) {
240+
if (!context.isTerminated()) {
241+
try {
242+
if (isTrace())
243+
log.debug("terminating context {}", context);
244+
245+
context.setTerminated();
246+
if (onTerminateHandler != null){
247+
if (isTrace())
248+
log.debug("when terminate for {} <<<", context);
249+
250+
onTerminateHandler.call(context);
251+
252+
if (isTrace())
253+
log.debug("when terminate for {} >>>", context);
254+
}
255+
} catch (Exception e) {
256+
log.error("Execution Error in [EasyFlow.whenTerminate] handler", e);
257+
}
258+
}
259+
}
260+
}

0 commit comments

Comments
 (0)