First example
Javadoc for this example.
src_examples/net/sourceforge/anotherfsm/examples/first/package-info.java
/*
* Copyright 2013 Michal Turek, AnotherFSM
*
* http://anotherfsm.sourceforge.net/
*
* 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.
*/
/**
* Introduction to the main features of AnotherFSM library.
*
* The code searches "AnotherFSM" string in the user input and exits the
* application after it is entered. Of course this implementation is an overkill
* solution for such simple task, remember it's only a demonstration.
*
* <h3>Classes</h3>
*
* <ul>
* <li>{@link net.sourceforge.anotherfsm.examples.first.SearchFsm}
* Defines structure of the state machine.</li>
* <li>{@link net.sourceforge.anotherfsm.examples.first.SearchFsmProcessor}
* Defines listeners for the states and transitions.</li>
* <li>{@link net.sourceforge.anotherfsm.examples.first.FirstExample}
* Defines main() method, passes data to the state machine.</li>
* </ul>
*
* @author Michal Turek
*/
package net.sourceforge.anotherfsm.examples.first;
src_examples/net/sourceforge/anotherfsm/examples/first/SearchFsm.java
/*
* Copyright 2013 Michal Turek, AnotherFSM
*
* http://anotherfsm.sourceforge.net/
*
* 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 net.sourceforge.anotherfsm.examples.first;
import net.sourceforge.anotherfsm.CharacterEvent;
import net.sourceforge.anotherfsm.DeterministicStateMachine;
import net.sourceforge.anotherfsm.FsmException;
import net.sourceforge.anotherfsm.OtherEvent;
import net.sourceforge.anotherfsm.State;
import net.sourceforge.anotherfsm.Transition;
/**
* State machine to search hard coded "AnotherFSM" string. This class will be
* generated from state machine schema after the editor and/or generator is
* implemented.
*
* Note the state machine is not fully correct. Every state should also contain
* transition on 'A' character to {@link #stateA} but this was ignored for
* simplicity.
*
* @author Michal Turek
*/
class SearchFsm extends DeterministicStateMachine {
// The states
public final State stateStart;
public final State stateA;
public final State stateN;
public final State stateO;
public final State stateT;
public final State stateH;
public final State stateE;
public final State stateR;
public final State stateF;
public final State stateS;
public final State stateM;
// The transitions to search "AnotherFSM" string
public final Transition trStartToA;
public final Transition trAtoN;
public final Transition trNtoO;
public final Transition trOtoT;
public final Transition trTtoH;
public final Transition trHtoE;
public final Transition trEtoR;
public final Transition trRtoF;
public final Transition trFtoS;
public final Transition trStoM;
// The transitions to return searching to the beginning on bad input
public final Transition trStartOther;
public final Transition trAOther;
public final Transition trNOther;
public final Transition trOOther;
public final Transition trTOther;
public final Transition trHOther;
public final Transition trEOther;
public final Transition trROther;
public final Transition trFOther;
public final Transition trSOther;
public final Transition trMOther;
/**
* Create the object, build the state machine.
*
* @param name
* the name of the state machine
* @throws FsmException
* if building of state machine fails
*/
public SearchFsm(String name) throws FsmException {
super(name);
// Create the states
stateStart = new State("Start state");
stateA = new State("State A");
stateN = new State("State N");
stateO = new State("State O");
stateT = new State("State T");
stateH = new State("State H");
stateE = new State("State E");
stateR = new State("State R");
stateF = new State("State F");
stateS = new State("State S");
stateM = new State("State M", State.Type.FINAL);
// Create the transitions for searching
trStartToA = new Transition(stateStart, CharacterEvent.instance('A'),
stateA);
trAtoN = new Transition(stateA, CharacterEvent.instance('n'), stateN);
trNtoO = new Transition(stateN, CharacterEvent.instance('o'), stateO);
trOtoT = new Transition(stateO, CharacterEvent.instance('t'), stateT);
trTtoH = new Transition(stateT, CharacterEvent.instance('h'), stateH);
trHtoE = new Transition(stateH, CharacterEvent.instance('e'), stateE);
trEtoR = new Transition(stateE, CharacterEvent.instance('r'), stateR);
trRtoF = new Transition(stateR, CharacterEvent.instance('F'), stateF);
trFtoS = new Transition(stateF, CharacterEvent.instance('S'), stateS);
trStoM = new Transition(stateS, CharacterEvent.instance('M'), stateM);
// Create the transitions for bad input
trStartOther = new Transition(stateStart, OtherEvent.instance,
stateStart);
trAOther = new Transition(stateA, OtherEvent.instance, stateStart);
trNOther = new Transition(stateN, OtherEvent.instance, stateStart);
trOOther = new Transition(stateO, OtherEvent.instance, stateStart);
trTOther = new Transition(stateT, OtherEvent.instance, stateStart);
trHOther = new Transition(stateH, OtherEvent.instance, stateStart);
trEOther = new Transition(stateE, OtherEvent.instance, stateStart);
trROther = new Transition(stateR, OtherEvent.instance, stateStart);
trFOther = new Transition(stateF, OtherEvent.instance, stateStart);
trSOther = new Transition(stateS, OtherEvent.instance, stateStart);
trMOther = new Transition(stateM, OtherEvent.instance, stateStart);
// Register states
addState(stateStart);
addState(stateA);
addState(stateN);
addState(stateO);
addState(stateT);
addState(stateH);
addState(stateE);
addState(stateR);
addState(stateF);
addState(stateS);
addState(stateM);
// Register transitions for searching
addTransition(trStartToA);
addTransition(trAtoN);
addTransition(trNtoO);
addTransition(trOtoT);
addTransition(trTtoH);
addTransition(trHtoE);
addTransition(trEtoR);
addTransition(trRtoF);
addTransition(trFtoS);
addTransition(trStoM);
// Register transitions for bad input
addTransition(trStartOther);
addTransition(trAOther);
addTransition(trNOther);
addTransition(trOOther);
addTransition(trTOther);
addTransition(trHOther);
addTransition(trEOther);
addTransition(trROther);
addTransition(trFOther);
addTransition(trSOther);
addTransition(trMOther);
// Define the start state
setStartState(stateStart);
}
}
src_examples/net/sourceforge/anotherfsm/examples/first/SearchFsmProcessor.java
/*
* Copyright 2013 Michal Turek, AnotherFSM
*
* http://anotherfsm.sourceforge.net/
*
* 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 net.sourceforge.anotherfsm.examples.first;
import net.sourceforge.anotherfsm.CharacterEvent;
import net.sourceforge.anotherfsm.EqualsPreprocessor;
import net.sourceforge.anotherfsm.Event;
import net.sourceforge.anotherfsm.FsmException;
import net.sourceforge.anotherfsm.OtherEvent;
import net.sourceforge.anotherfsm.Preprocessor;
import net.sourceforge.anotherfsm.State;
import net.sourceforge.anotherfsm.StateAdapter;
import net.sourceforge.anotherfsm.TransitionListener;
/**
* Listeners of the state machine. This class is more a demonstration of the
* features than something useful.
*
* @author Michal Turek
*/
public class SearchFsmProcessor extends SearchFsm {
/**
* Create the object.
*
* @param name
* the name of the state machine
* @throws FsmException
* if building of state machine fails
*/
public SearchFsmProcessor(String name) throws FsmException {
super(name);
// Create a new preprocessor that is based on equals() method of events
EqualsPreprocessor preprocessor = new EqualsPreprocessor(name);
// Don't pass newline characters to the state machine
preprocessor.addProcessor(CharacterEvent.instance('\n'),
new Preprocessor.Processor<CharacterEvent>() {
@Override
public Event process(CharacterEvent event) {
// Null stops the event processing in preprocessor
return null;
}
});
// Register preprocessor to the state machine
addPreprocessor(preprocessor);
// Do something on enter of state A
stateA.addListener(new StateAdapter() {
@Override
public void onStateEnter(State previous, Event event, State current) {
logger.info("Character 'A' entered, good start.");
}
});
// Do something on transition from state R to state F
trRtoF.addListener(new TransitionListener() {
@Override
public void onTransition(State source, Event event,
State destination) {
logger.info("Great, nearly done, please continue.");
}
});
// Do something on any transition
addListener(new TransitionListener() {
@Override
public void onTransition(State source, Event event,
State destination) {
// State machine tries to process OtherEvent event if no
// transition matches
if (event instanceof OtherEvent) {
logger.info("Oh bad character, let's start again...");
}
}
});
// Do something on enter of any state
addListener(new StateAdapter() {
@Override
public void onStateEnter(State previous, Event event, State current) {
// The last state of the string is a final state
if (current.isFinalState()) {
logger.info("Whole string successfully entered.");
}
}
});
}
}
src_examples/net/sourceforge/anotherfsm/examples/first/FirstExample.java
/*
* Copyright 2013 Michal Turek, AnotherFSM
*
* http://anotherfsm.sourceforge.net/
*
* 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 net.sourceforge.anotherfsm.examples.first;
import java.io.IOException;
import net.sourceforge.anotherfsm.AnotherFsm;
import net.sourceforge.anotherfsm.CharacterEvent;
import net.sourceforge.anotherfsm.FsmException;
import net.sourceforge.anotherfsm.StateMachine;
import net.sourceforge.anotherfsm.logger.FsmLogger;
import net.sourceforge.anotherfsm.logger.StdStreamLoggerFactory;
/**
* Search "AnotherFSM" string in the input from user and exit the application
* after it is entered.
*
* @author Michal Turek
*/
public class FirstExample {
static {
// Register factory of loggers before any logger is created
AnotherFsm.setLoggerFactory(new StdStreamLoggerFactory());
}
/** The logger object for this class. */
private final static FsmLogger logger = AnotherFsm
.getLogger(FirstExample.class);
/**
* The application start function.
*
* @param args
* the input arguments, unused
*/
public static void main(String[] args) {
// Create instance of the state machine
try (StateMachine machine = new SearchFsmProcessor(
FirstExample.class.getSimpleName())) {
// Building done in the constructor, prepare for events processing
machine.start();
logger.info("Type 'AnotherFSM' string to exit.");
while (true) {
// Read a character from user and pass it to the state machine
char c = (char) System.in.read();
machine.process(CharacterEvent.instance(c));
// Exit after a final state is entered
if (machine.isInFinalState()) {
logger.debug("'AnotherFSM' string found in input, exiting");
break;
}
}
} catch (FsmException | IOException e) {
// Process any exception that may occur
logger.fatal("Unexpected exception occurred", e);
}
logger.debug("End of main()");
}
}
Sample outputs
2013-01-18 18:35:56,137 [main] INFO SearchFsmProcessor.FirstExample - Transition started: @INITIAL@ -> StartEvent -> Start state
2013-01-18 18:35:56,144 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: @INITIAL@ -> StartEvent -> Start state
2013-01-18 18:35:56,144 [main] INFO FirstExample - Type 'AnotherFSM' string to exit.
AnotherFSM
2013-01-18 18:36:06,265 [main] INFO SearchFsmProcessor.FirstExample - Transition started: Start state -> CharacterEvent(A) -> State A
2013-01-18 18:36:06,265 [main] INFO SearchFsmProcessor.FirstExample - Character 'A' entered, good start.
2013-01-18 18:36:06,265 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: Start state -> CharacterEvent(A) -> State A
2013-01-18 18:36:06,266 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State A -> CharacterEvent(n) -> State N
2013-01-18 18:36:06,266 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State A -> CharacterEvent(n) -> State N
2013-01-18 18:36:06,266 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State N -> CharacterEvent(o) -> State O
2013-01-18 18:36:06,266 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State N -> CharacterEvent(o) -> State O
2013-01-18 18:36:06,267 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State O -> CharacterEvent(t) -> State T
2013-01-18 18:36:06,267 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State O -> CharacterEvent(t) -> State T
2013-01-18 18:36:06,267 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State T -> CharacterEvent(h) -> State H
2013-01-18 18:36:06,267 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State T -> CharacterEvent(h) -> State H
2013-01-18 18:36:06,268 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State H -> CharacterEvent(e) -> State E
2013-01-18 18:36:06,268 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State H -> CharacterEvent(e) -> State E
2013-01-18 18:36:06,268 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State E -> CharacterEvent(r) -> State R
2013-01-18 18:36:06,268 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State E -> CharacterEvent(r) -> State R
2013-01-18 18:36:06,269 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State R -> CharacterEvent(F) -> State F
2013-01-18 18:36:06,269 [main] INFO SearchFsmProcessor.FirstExample - Great, nearly done, please continue.
2013-01-18 18:36:06,269 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State R -> CharacterEvent(F) -> State F
2013-01-18 18:36:06,269 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State F -> CharacterEvent(S) -> State S
2013-01-18 18:36:06,270 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State F -> CharacterEvent(S) -> State S
2013-01-18 18:36:06,270 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State S -> CharacterEvent(M) -> State M
2013-01-18 18:36:06,270 [main] INFO SearchFsmProcessor.FirstExample - Whole string successfully entered.
2013-01-18 18:36:06,270 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State S -> CharacterEvent(M) -> State M
2013-01-18 18:36:06,271 [main] DEBUG FirstExample - 'AnotherFSM' string found in input, exiting
2013-01-18 18:36:06,271 [main] DEBUG FirstExample - End of main()
2013-01-18 18:36:28,590 [main] INFO SearchFsmProcessor.FirstExample - Transition started: @INITIAL@ -> StartEvent -> Start state
2013-01-18 18:36:28,600 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: @INITIAL@ -> StartEvent -> Start state
2013-01-18 18:36:28,600 [main] INFO FirstExample - Type 'AnotherFSM' string to exit.
Ano
2013-01-18 18:36:33,742 [main] INFO SearchFsmProcessor.FirstExample - Transition started: Start state -> CharacterEvent(A) -> State A
2013-01-18 18:36:33,743 [main] INFO SearchFsmProcessor.FirstExample - Character 'A' entered, good start.
2013-01-18 18:36:33,743 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: Start state -> CharacterEvent(A) -> State A
2013-01-18 18:36:33,743 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State A -> CharacterEvent(n) -> State N
2013-01-18 18:36:33,744 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State A -> CharacterEvent(n) -> State N
2013-01-18 18:36:33,744 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State N -> CharacterEvent(o) -> State O
2013-01-18 18:36:33,744 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State N -> CharacterEvent(o) -> State O
2013-01-18 18:36:33,744 [main] INFO EqualsPreprocessor.FirstExample - Event preprocessed: CharacterEvent(
) -> null
X
2013-01-18 18:36:44,280 [main] INFO SearchFsmProcessor.FirstExample - Transition started: State O -> CharacterEvent(X)/OtherEvent(CharacterEvent(X)) -> Start state
2013-01-18 18:36:44,281 [main] INFO SearchFsmProcessor.FirstExample - Oh bad character, let's start again...
2013-01-18 18:36:44,281 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: State O -> CharacterEvent(X)/OtherEvent(CharacterEvent(X)) -> Start state
2013-01-18 18:36:44,281 [main] INFO EqualsPreprocessor.FirstExample - Event preprocessed: CharacterEvent(
) -> null
Y
2013-01-18 18:36:53,689 [main] INFO SearchFsmProcessor.FirstExample - Transition started: Start state -> CharacterEvent(Y)/OtherEvent(CharacterEvent(Y)) -> Start state
2013-01-18 18:36:53,690 [main] INFO SearchFsmProcessor.FirstExample - Oh bad character, let's start again...
2013-01-18 18:36:53,690 [main] INFO SearchFsmProcessor.FirstExample - Transition finished: Start state -> CharacterEvent(Y)/OtherEvent(CharacterEvent(Y)) -> Start state
2013-01-18 18:36:53,690 [main] INFO EqualsPreprocessor.FirstExample - Event preprocessed: CharacterEvent(
) -> null
...