Qfsm example

Qfsm is a graphical tool for designing finite state machines that is runnable on various operating systems. You can download it from its home page http://qfsm.sourceforge.net/. This example re-implements the functionality of First example with significant help of code generated from Qfsm diagram.

Javadoc for this example.

src_examples/net/sourceforge/anotherfsm/examples/qfsm/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. */   /** * This example re-implements the functionality of First example with * significant help of code generated from Qfsm diagram. * * 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 and files</h3> * * <ul> * <li>SearchString.fsm * Qfsm data file, the painted diagram.</li> * <li>SearchString.xml * Code generator configuration file.</li> * <li>generate.sh * Shell script to execute code generator and generate the files.</li> * * <li>SearchString.xml.generated * Generated configuration template, no updates.</li> * <li>SearchStringFsm.java.generated * Generated state machine, no updates.</li> * <li>SearchStringProcessor.java.generated * Generated listeners template, no updates.</li> * * <li>{@link net.sourceforge.anotherfsm.examples.qfsm.SearchStringFsm} * Defines structure of the state machine.</li> * <li>{@link net.sourceforge.anotherfsm.examples.qfsm.SearchStringProcessor} * Defines listeners for the states and transitions.</li> * * <li>{@link net.sourceforge.anotherfsm.examples.qfsm.Qfsm} * Defines main() method, passes data to the state machine.</li> * </ul> * * @author Michal Turek */ package net.sourceforge.anotherfsm.examples.qfsm;

State machine diagram

To paint a new state machine diagram please execute Qfsm and using menu File - New create a new project. Make sure you select Type - Free Text radio button, only this state machine type is supported by AnotherFSM code generator at the moment. You should also fill the state machine name and other items in the dialog.


State machine diagram used in this example

Ok, the diagram is finished. All states have their name, the input strings and the descriptions of transitions are properly set. You have to define the start state and optionally the final state(s). The descriptions of various items will be used for generating of Javadoc most of the time so consider to set them too. Note nearly no information from the diagram is lost during code generation.

Code generation

Let's generate the Java code. The code generator is bundled directly to the AnotherFSM package, it's an executable Java class. The helper shell script bellow demonstrates its usage.

src_examples/net/sourceforge/anotherfsm/examples/qfsm/generate.sh
#!/bin/bash -ex # # 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. # # One purpose script to generate Java code from Qfsm data file.     # Example of the script execution # pushd src_examples/net/sourceforge/anotherfsm/examples/qfsm ; ./generate.sh ; popd     # Relative path to AnotherFSM root directory ROOT_DIR=../../../../../..   # Java classpath (development/production) CLASSPATH=$ROOT_DIR/build/classes # CLASSPATH=$ROOT_DIR/build/anotherfsm-*.jar     echo -e "\n\nShowing usage..." java -classpath $CLASSPATH \ net.sourceforge.anotherfsm.qfsm.CodeGenerator \ --help     echo -e "\n\nGenerating XML configuration file..." java -classpath $CLASSPATH \ net.sourceforge.anotherfsm.qfsm.CodeGenerator \ --force \ --template SearchString.xml.generated     echo -e "\n\nGenerating Java code..." java -classpath $CLASSPATH \ net.sourceforge.anotherfsm.qfsm.CodeGenerator \ --force \ --config-file SearchString.xml \ --qfsm-file SearchString.fsm  

The generated configuration XML template contains the following possibilities. All items are mandatory.

The generator splits state machine to two classes. The base StateMachineClass defines the structure of states, transitions and their connections. On the other hand the child ProcessorClass class defines template for listeners. It is expected only the second one will be updated manually. This is to simplify three-way-merge on state machine update and code re-generation.

src_examples/net/sourceforge/anotherfsm/examples/qfsm/SearchString.xml.generated
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <AnotherFsmCodeGenerator> <!-- The version of configuration file. --> <Version>0.1.0</Version>   <!-- The output directory relative to the active one. --> <OutputDirectory>.</OutputDirectory>   <!-- The state machine base class. --> <BaseClass>DeterministicStateMachine</BaseClass>   <!-- Java package of the generated files. --> <JavaPackage>net.sourceforge.anotherfsm</JavaPackage>   <!-- Description of transitions contains Java code. --> <TransitionDescriptionContainsCode>no</TransitionDescriptionContainsCode>   <!-- Configuration of the generated state machine class. --> <StateMachineClass> <!-- The suffix of the file name. --> <FileSuffix>.generated</FileSuffix>   <!-- Java imports to make the file compilable. --> <Imports> import net.sourceforge.anotherfsm.*; </Imports> </StateMachineClass>   <!-- Configuration of the generated processor class. --> <ProcessorClass> <!-- Generate type preprocessor. --> <TypePreprocessor>yes</TypePreprocessor>   <!-- Generate equals preprocessor. --> <EqualsPreprocessor>yes</EqualsPreprocessor>   <!-- Generate global state listener. --> <GlobalStateListener>yes</GlobalStateListener>   <!-- Generate global transition listener. --> <GlobalTransitionListener>yes</GlobalTransitionListener>   <!-- Generate state listeners. --> <StateListener>yes</StateListener>   <!-- Generate transition listeners. --> <TransitionListener>yes</TransitionListener>   <!-- The suffix of the file name. --> <FileSuffix>.generated</FileSuffix>   <!-- Java imports to make the file compilable. --> <Imports> import net.sourceforge.anotherfsm.*; </Imports> </ProcessorClass>   <!-- File header that will be put at the top of every generated file. --> <!-- Update the content as you want. --> <FileHeader> <![CDATA[ /* * 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. */ ]]> </FileHeader> </AnotherFsmCodeGenerator>  

Java code can be generated after the default configuration is updated. The example script and execution of code generator is described above.

src_examples/net/sourceforge/anotherfsm/examples/qfsm/SearchStringFsm.java.generated
/* * 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.qfsm;   import net.sourceforge.anotherfsm.*;   /** * State machine to search hard coded "AnotherFSM" string. * * <p> * This file was generated using AnotherFSM CodeGenerator:<br /> * {@code java -classpath anotherfsm-0.2.0-dev.jar net.sourceforge.anotherfsm.qfsm.CodeGenerator --force --config-file SearchString.xml --qfsm-file SearchString.fsm} * </p> * * @author Michal Turek * @version 0.1.0 */ class SearchStringFsm extends DeterministicStateMachine { /** * "A" processed. */ public final State stateA;   /** * "Anothe" processed. */ public final State stateE;   /** * "AnotherF" processed. */ public final State stateF;   /** * "Anoth" processed. */ public final State stateH;   /** * "AnotherFSM" processed. */ public final State stateM;   /** * "An" processed. */ public final State stateN;   /** * "Ano" processed. */ public final State stateO;   /** * "Another" processed. */ public final State stateR;   /** * "AnotherFS" processed. */ public final State stateS;   /** * The start state. */ public final State stateStart;   /** * "Anot" processed. */ public final State stateT;     /** * Transition from {@code stateA} to {@code stateN} on {@code CharacterEvent.instance('n')} event. */ public final Transition stateA_CharacterEvent_instancen_stateN;   /** * Transition from {@code stateA} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateA_OtherEvent_instance_stateStart;   /** * Transition from {@code stateE} to {@code stateR} on {@code CharacterEvent.instance('r')} event. */ public final Transition stateE_CharacterEvent_instancer_stateR;   /** * Transition from {@code stateE} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateE_OtherEvent_instance_stateStart;   /** * Transition from {@code stateF} to {@code stateS} on {@code CharacterEvent.instance('S')} event. */ public final Transition stateF_CharacterEvent_instanceS_stateS;   /** * Transition from {@code stateF} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateF_OtherEvent_instance_stateStart;   /** * Transition from {@code stateH} to {@code stateE} on {@code CharacterEvent.instance('e')} event. */ public final Transition stateH_CharacterEvent_instancee_stateE;   /** * Transition from {@code stateH} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateH_OtherEvent_instance_stateStart;   /** * Transition from {@code stateM} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateM_OtherEvent_instance_stateStart;   /** * Transition from {@code stateN} to {@code stateO} on {@code CharacterEvent.instance('o')} event. */ public final Transition stateN_CharacterEvent_instanceo_stateO;   /** * Transition from {@code stateN} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateN_OtherEvent_instance_stateStart;   /** * Transition from {@code stateO} to {@code stateT} on {@code CharacterEvent.instance('t')} event. */ public final Transition stateO_CharacterEvent_instancet_stateT;   /** * Transition from {@code stateO} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateO_OtherEvent_instance_stateStart;   /** * Transition from {@code stateR} to {@code stateF} on {@code CharacterEvent.instance('F')} event. */ public final Transition stateR_CharacterEvent_instanceF_stateF;   /** * Transition from {@code stateR} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateR_OtherEvent_instance_stateStart;   /** * Transition from {@code stateS} to {@code stateM} on {@code CharacterEvent.instance('M')} event. */ public final Transition stateS_CharacterEvent_instanceM_stateM;   /** * Transition from {@code stateS} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateS_OtherEvent_instance_stateStart;   /** * Transition from {@code stateStart} to {@code stateA} on {@code CharacterEvent.instance('A')} event. */ public final Transition stateStart_CharacterEvent_instanceA_stateA;   /** * Transition from {@code stateStart} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateStart_OtherEvent_instance_stateStart;   /** * Transition from {@code stateT} to {@code stateH} on {@code CharacterEvent.instance('h')} event. */ public final Transition stateT_CharacterEvent_instanceh_stateH;   /** * Transition from {@code stateT} to {@code stateStart} on {@code OtherEvent.instance} event. */ public final Transition stateT_OtherEvent_instance_stateStart;       /** * Create the object, build the state machine. * * @param name * the name of the state machine * @throws FsmException * if building of state machine fails */ public SearchStringFsm(String name) throws FsmException { super(name);   stateA = new State("stateA"); addState(stateA);   stateE = new State("stateE"); addState(stateE);   stateF = new State("stateF"); addState(stateF);   stateH = new State("stateH"); addState(stateH);   stateM = new State("stateM", State.Type.FINAL); addState(stateM);   stateN = new State("stateN"); addState(stateN);   stateO = new State("stateO"); addState(stateO);   stateR = new State("stateR"); addState(stateR);   stateS = new State("stateS"); addState(stateS);   stateStart = new State("stateStart"); addState(stateStart);   stateT = new State("stateT"); addState(stateT);     stateA_CharacterEvent_instancen_stateN = new Transition(stateA, CharacterEvent.instance('n'), stateN); addTransition(stateA_CharacterEvent_instancen_stateN);   stateA_OtherEvent_instance_stateStart = new Transition(stateA, OtherEvent.instance, stateStart); addTransition(stateA_OtherEvent_instance_stateStart);   stateE_CharacterEvent_instancer_stateR = new Transition(stateE, CharacterEvent.instance('r'), stateR); addTransition(stateE_CharacterEvent_instancer_stateR);   stateE_OtherEvent_instance_stateStart = new Transition(stateE, OtherEvent.instance, stateStart); addTransition(stateE_OtherEvent_instance_stateStart);   stateF_CharacterEvent_instanceS_stateS = new Transition(stateF, CharacterEvent.instance('S'), stateS); addTransition(stateF_CharacterEvent_instanceS_stateS);   stateF_OtherEvent_instance_stateStart = new Transition(stateF, OtherEvent.instance, stateStart); addTransition(stateF_OtherEvent_instance_stateStart);   stateH_CharacterEvent_instancee_stateE = new Transition(stateH, CharacterEvent.instance('e'), stateE); addTransition(stateH_CharacterEvent_instancee_stateE);   stateH_OtherEvent_instance_stateStart = new Transition(stateH, OtherEvent.instance, stateStart); addTransition(stateH_OtherEvent_instance_stateStart);   stateM_OtherEvent_instance_stateStart = new Transition(stateM, OtherEvent.instance, stateStart); addTransition(stateM_OtherEvent_instance_stateStart);   stateN_CharacterEvent_instanceo_stateO = new Transition(stateN, CharacterEvent.instance('o'), stateO); addTransition(stateN_CharacterEvent_instanceo_stateO);   stateN_OtherEvent_instance_stateStart = new Transition(stateN, OtherEvent.instance, stateStart); addTransition(stateN_OtherEvent_instance_stateStart);   stateO_CharacterEvent_instancet_stateT = new Transition(stateO, CharacterEvent.instance('t'), stateT); addTransition(stateO_CharacterEvent_instancet_stateT);   stateO_OtherEvent_instance_stateStart = new Transition(stateO, OtherEvent.instance, stateStart); addTransition(stateO_OtherEvent_instance_stateStart);   stateR_CharacterEvent_instanceF_stateF = new Transition(stateR, CharacterEvent.instance('F'), stateF); addTransition(stateR_CharacterEvent_instanceF_stateF);   stateR_OtherEvent_instance_stateStart = new Transition(stateR, OtherEvent.instance, stateStart); addTransition(stateR_OtherEvent_instance_stateStart);   stateS_CharacterEvent_instanceM_stateM = new Transition(stateS, CharacterEvent.instance('M'), stateM); addTransition(stateS_CharacterEvent_instanceM_stateM);   stateS_OtherEvent_instance_stateStart = new Transition(stateS, OtherEvent.instance, stateStart); addTransition(stateS_OtherEvent_instance_stateStart);   stateStart_CharacterEvent_instanceA_stateA = new Transition(stateStart, CharacterEvent.instance('A'), stateA); addTransition(stateStart_CharacterEvent_instanceA_stateA);   stateStart_OtherEvent_instance_stateStart = new Transition(stateStart, OtherEvent.instance, stateStart); addTransition(stateStart_OtherEvent_instance_stateStart);   stateT_CharacterEvent_instanceh_stateH = new Transition(stateT, CharacterEvent.instance('h'), stateH); addTransition(stateT_CharacterEvent_instanceh_stateH);   stateT_OtherEvent_instance_stateStart = new Transition(stateT, OtherEvent.instance, stateStart); addTransition(stateT_OtherEvent_instance_stateStart);     setStartState(stateStart); } }  
src_examples/net/sourceforge/anotherfsm/examples/qfsm/SearchStringProcessor.java.generated
/* * 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.qfsm;   import net.sourceforge.anotherfsm.*;   /** * State machine to search hard coded "AnotherFSM" string. * * <p> * This file was generated using AnotherFSM CodeGenerator:<br /> * {@code java -classpath anotherfsm-0.2.0-dev.jar net.sourceforge.anotherfsm.qfsm.CodeGenerator --force --config-file SearchString.xml --qfsm-file SearchString.fsm} * </p> * * @author Michal Turek * @version 0.1.0 */ class SearchStringProcessor extends SearchStringFsm { /** * Create the object, define and connect listeners. * * @param name * the name of the state machine * @throws FsmException * if building of state machine fails */ public SearchStringProcessor(String name) throws FsmException { super(name);   EqualsPreprocessor equalsPreprocessor = new EqualsPreprocessor(name);   // TODO Auto-generated method stub   addPreprocessor(equalsPreprocessor);   addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });     addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // TODO Auto-generated method stub } });     stateA.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateE.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateF.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateH.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateM.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateN.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateO.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateR.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateS.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateStart.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });   stateT.addListener(new StateAdapter(StateListener.Type.LOOP_NO_PROCESS) { @Override public void onStateEnter(State previous, Event event, State current) { // TODO Auto-generated method stub }   @Override public void onStateExit(State current, Event event, State next) { // TODO Auto-generated method stub } });     stateA_CharacterEvent_instancen_stateN.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateA_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateE_CharacterEvent_instancer_stateR.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateE_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateF_CharacterEvent_instanceS_stateS.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateF_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateH_CharacterEvent_instancee_stateE.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateH_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateM_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateN_CharacterEvent_instanceo_stateO.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateN_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateO_CharacterEvent_instancet_stateT.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateO_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateR_CharacterEvent_instanceF_stateF.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly logger.info("Great, nearly done, please continue."); } });   stateR_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateS_CharacterEvent_instanceM_stateM.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateS_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateStart_CharacterEvent_instanceA_stateA.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateStart_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateT_CharacterEvent_instanceh_stateH.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });   stateT_OtherEvent_instance_stateStart.addListener(new TransitionListener() { @Override public void onTransition(State source, Event event, State destination) { // The following code is generated, don't edit it directly   } });     } }  

Finalization

Program enter and the application logic is the same as in the First example. The manual update of SearchStringProcessor class (the listeners) consists mostly from deletion of unwanted functions, preprocessor definition and replace TODOs by real code.

src_examples/net/sourceforge/anotherfsm/examples/qfsm/Qfsm.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.qfsm;   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 Qfsm { 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(Qfsm.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 SearchStringProcessor( Qfsm.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 output

2013-03-17 16:24:52,948 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  @INITIAL@ -> StartEvent -> stateStart
2013-03-17 16:24:52,949 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: @INITIAL@ -> StartEvent -> stateStart
2013-03-17 16:24:52,950 [main]  INFO Qfsm - Type 'AnotherFSM' string to exit.
AnotherFSM
2013-03-17 16:24:57,983 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateStart -> CharacterEvent(A) -> stateA
2013-03-17 16:24:57,984 [main]  INFO SearchStringProcessor.Qfsm - Character 'A' entered, good start.
2013-03-17 16:24:57,984 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateStart -> CharacterEvent(A) -> stateA
2013-03-17 16:24:57,985 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateA -> CharacterEvent(n) -> stateN
2013-03-17 16:24:57,985 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateA -> CharacterEvent(n) -> stateN
2013-03-17 16:24:57,986 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateN -> CharacterEvent(o) -> stateO
2013-03-17 16:24:57,987 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateN -> CharacterEvent(o) -> stateO
2013-03-17 16:24:57,988 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateO -> CharacterEvent(t) -> stateT
2013-03-17 16:24:57,988 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateO -> CharacterEvent(t) -> stateT
2013-03-17 16:24:57,989 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateT -> CharacterEvent(h) -> stateH
2013-03-17 16:24:57,990 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateT -> CharacterEvent(h) -> stateH
2013-03-17 16:24:57,990 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateH -> CharacterEvent(e) -> stateE
2013-03-17 16:24:57,991 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateH -> CharacterEvent(e) -> stateE
2013-03-17 16:24:57,991 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateE -> CharacterEvent(r) -> stateR
2013-03-17 16:24:57,992 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateE -> CharacterEvent(r) -> stateR
2013-03-17 16:24:57,992 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateR -> CharacterEvent(F) -> stateF
2013-03-17 16:24:57,993 [main]  INFO SearchStringProcessor.Qfsm - Great, nearly done, please continue.
2013-03-17 16:24:57,993 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateR -> CharacterEvent(F) -> stateF
2013-03-17 16:24:57,994 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateF -> CharacterEvent(S) -> stateS
2013-03-17 16:24:57,994 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateF -> CharacterEvent(S) -> stateS
2013-03-17 16:24:57,995 [main]  INFO SearchStringProcessor.Qfsm - Transition started:  stateS -> CharacterEvent(M) -> stateM
2013-03-17 16:24:57,995 [main]  INFO SearchStringProcessor.Qfsm - Whole string successfully entered.
2013-03-17 16:24:57,996 [main]  INFO SearchStringProcessor.Qfsm - Transition finished: stateS -> CharacterEvent(M) -> stateM
2013-03-17 16:24:57,996 [main] DEBUG Qfsm - 'AnotherFSM' string found in input, exiting
2013-03-17 16:24:57,997 [main] DEBUG Qfsm - End of main()