Simple Workflow Engine, Re-designed and Simplified (even more)

Redesigning SWE, a simple workflow engine:

I totally redesigned the SWE project, as I had to use the state machines in one of my own projects, and learned from its experience. The API for SWE is highly simplified. Everything gets done with only one public class “SateMachine<SO, RT>”. This class implements  four interfaces:

  • IStateMachineBuilder
  • IStateMachineController
  • IStateMchine
  • IStableStateMachine

To create and use a state machine is very simple. Each state has also got a very simple concept.

All that matters is:
State: Has a name, does some stuff, and decides what the next step is.

Below is a simple Light; on – off example:

Var smBuilder = StateMachine<Lamp, Lamp>.Create("On")
.State("On", (s, l) =>
{
    l.IsOn = true;
    return StateMachine.NamedState("Off");
})
.State("Off", (s, l) =>
{
    l.IsOn = false;
    return StateMachine.NamedState("On");
});
Var sm = smBuilder.BindTo(theLamp);

//Usage: each call, alternates the lamp between on and off.
While(true){
    sm.Process();
    Thread.Sleep(10);
}

In another post, I show a more advanced use of swe, with a csv parser.

Solving a typical interview question with SWE

Lets assume a typical interview question:

Write some code to reverse words in a sentence without using .Net string functions. For example, “this and that” should become “sith dna taht”. We want to preserve space patterns also.

This is the state machine for this purpose:

And I can write it as follows:


public class TextContext
{
public string Text;
public int Pos; //Current position
public string Word;
public string Result;
}

public static void Main()
{
var tc = new TextContex{Text="This and That"};
var sm = new StateMachineBuilder()
.State("Space", c => true, c => { c.Word += " "; c.Pos++; })
.Then(c => c.Pos >= c.Text.Length, "Fine")
.Then(c => c.Text[c.Pos] == ' ', "Space")
.Then("Word", c => {c.Result += c.Word; c.Word = '';})
.State("Word", c => true, c => {c.Word = c.Text[c.Pos] + c.Word; c.Pos++;})
.Then(c => c.Pos >= c.Text.Length, "Fine")
.Then(c => c.Text[c.Pos] != ' ', "Word")
.Then("Space", c => {c.Result += c.Word; c.Word = '';})
.Finish("Fine")
.BindTo(tc);

sm.Start();
while(sm.MoveNext()){};

Console.WriteLn(tc.Result);
}

UPDATE: SWE is re-design. With the new version, the above code will look like the following:

var str = "This and That";
var word = new StringBuilder(); 
var smbuilder = StateMachine<int,string>.Create("word")
.State("leters", (s, i) => {
    if (str[i]==' ') { s.Return(word.ToString()); word.Clear(); return StateMachine.Named("spaces");};
    word.Append(str[i]);
    s.UpldateObject(i+1); //Update the pointer
    return StateMachine.Loop })
.State("spaces", (s, i) => {
    s.UpdateObject(i+1);
    if(str[i]==' ') { return StateMachine.Loop; }
    return StateMachine.Named("letters");
}); 
var sm = smbuilder.BindTo(0);
while(sm.Process()){ if (sm.HasReturn) { Console.WriteLn (sm.GetReturned();) } }

Simple Workflow Engine

In the last post I talked about a workflow engine to define workflows over object quickly and efficiently.

Last night I had some time and implemented the basics of the engine. The lamp example in the previous post works and the code I wrote tend to be really simple and small.

The project is hosted in codeplex (http://swengine.codeplex.com/). Download it and play with it.