As I mentioned earlier (German) I created a library called XML FiniteStateMachine, that can be used to build up a finite state machine from a xml definition.
The example I provided was a very basic one without any practical benefit. No I want to go one step further and provide an example that demonstrates how the library can be used to build up a finite state machine that leads a user through a conversation.
What is the aim of this example? The library was originally built to create a plug-in for the openfire server that remembers a user notes he left before. The workflow should be something like:
- User writes service or bot “add notice”
- Bot/Service answers “enter notice”
- User enters an arbitrary notice-string
- Bot/Service asks when to remind the user
- User enters the a delay or a fixed time
- Bot/Service stores the notice and starts a timer
- … some time later …
- Bot/Service sends a message containing the pre-entered notice to the users
The example that’ll be developed in the remainder of this article will show how a first version of this conversation can be realized using the XML FiniteStateMachine. It won’t be a plug-in for openfire, nor will it remind the user to any pre entered notice. It’ll only be able to store and list notices – for a skilled programmer it should be an easy task to take this example as skeletal structure and extend the yet missing functionality.
Step 1 – Design the FiniteStateMachine
The first task is to design the xml definition of the finite state machine. I’ve arranged a simple “conversation” that I’ll explain afterwards.
<?xml version="1.0" encoding="UTF-8"?>
<fsm startState="welcome">
<state id="welcome" listener="messageOutputListener">
<transition on="help" to="welcome" listener="messageOutputListener" />
<transition on="add notice" to="add-notice" listener="messageOutputListener" />
<transition on="exit" to="welcome" listener="exitListener" />
<transition on="*" to="welcome" listener="noValidCommandListener" />
</state>
<state id="accept-command" listener="messageOutputListener">
<transition on="help" to="accept-command" listener="messageOutputListener" />
<transition on="add notice" to="add-notice" listener="messageOutputListener" />
<transition on="list" to="accept-command" listener="listNoticeListener" />
<transition on="remove notice" to="remove-notice" listener="messageOutputListener" />
<transition on="exit" to="accept-command" listener="exitListener" />
<transition on="*" to="accept-command" listener="noValidCommandListener" />
</state>
<state id="add-notice" listener="messageOutputListener">
<transition on="abort" to="accept-command" listener="messageOutputListener" />
<transition on="help" to="add-notice" listener="messageOutputListener" />
<transition on="*" to="accept-command" listener="addNoticeListener" />
</state>
<state id="remove-notice" listener="messageOutputListener">
<transition on="abort" to="accept-command" listener="messageOutputListener" />
<transition on="help" to="add-notice" listener="messageOutputListener" />
<transition on="*" to="accept-command" listener="removeNoticeListener" />
</state>
</fsm>
As you can see I defined 4 states. Let’s ignore the “welcome”-state for the moment and examine the other three states. The state “accept-command” is the state that’ll be the origin for all our actions. It defines the commands “help”, “add notice”, “list” “remove notice”, “exit” and a catch-all-transition. Ignoring the “listener”-attribute I think it’s very obvious what’s the control-flow of this fsm.
That’s enough for part one. Feel free to build your own application that uses this fsm-definition. You can obtain the required library from my download-directory.
The next parts will discuss the creation of an interface, the definition of the listeners and last, but not least how to setup and run the bot.
The result of this series will be a simple application like the one shown below.