Hello, it has been a while since I wrote my last blog. Anyway, I am back again. I have a nice blog today, I have been working for a while with a team which his main target is to use everything Microsoft has released. It is a good thing sometimes and a very bad thing the other times. They read a "workflow" word in the requirements document, the first came to their mind was WF (Windows Workflow Foundation). The problem was so simple using WF would be over engineering. So, I decided to think of a more simple solution. As I am a Spring.NET Freak and I think we can't build an application without using it, I thought of using it :).
First, Let us create a
State class first:
public class State
{
private string _id;
private string _name;
private List<link> _links;
public List NextStates
{
get
{
return Links.Select(l => l.State).ToList();
}
}
public string Id
{
get { return _id; }
set { _id = value; }
}
public List<link> Links
{
get { return _links; }
set { _links = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public bool IsEndState
{
get
{
return Links.Count == 0;
}
}
}
And a
Link class:
public class Link
{
//this condition will written used SPEL (Spring Expression Langauge)
public string Condition { get; internal set; }
public State State { get; internal set; }
}
Then create the interface for the state machine:
public interface IStateMachine
{
State InitialState { get; }
State CurrentState { get; }
void SetCurrentState(string id);
bool Advance();
List NextStates { get; }
}
Then comes spring to the rescue, Spring here will used for 2 main tasks:
- Configuration File for our Workflow (State Machine): Keeps the state information and the transitions between states.
- Spring Expression will be used to define the transition rules between different states.
I decided to implement a simple interview process as an illustration for my small framework:
The spring configuration file for the mentioned process will be as follows:
<xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object id="ExamToFirstInterview" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="ExamScore >= 25"/>
<property name="State" ref="FirstInterview" />
<object>
<object id="ExamToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="ExamScore < 25"/>
<property name="State" ref="Rejected" />
<object>
<object id="FirstInterviewToSecondInterview" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="FirstInterviewAccepted"/>
<property name="State" ref="SecondInterview" />
<object>
<object id="FirstInterviewToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="!FirstInterviewAccepted"/>
<property name="State" ref="Rejected" />
<object>
<object id="SecondInterviewToAccepted" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="SecondInterviewAccepted"/>
<property name="State" ref="Accepted" />
<object>
<object id="SecondInterviewToRejected" type="SimpleStateMachine.Link, SimpleStateMachine">
<property name="Condition" value="!SecondInterviewAccepted"/>
<property name="State" ref="Rejected" />
<object>
<object id="Exam" type="SimpleStateMachine.State, SimpleStateMachine">
<property name="Id" value="exam"/>
<property name="Name" value="Exam"/>
<property name="Links">
<list element-type="SimpleStateMachine.Link, SimpleStateMachine">
<ref object="ExamToFirstInterview"/>
<ref object="ExamToRejected"/>
<list>
<property>
<object>
<object id="FirstInterview" type="SimpleStateMachine.State, SimpleStateMachine">
<property name="Id" value="first_interview"/>
<property name="Name" value="First Interview"/>
<property name="Links">
<list element-type="SimpleStateMachine.Link, SimpleStateMachine">
<ref object="FirstInterviewToSecondInterview"/>
<ref object="FirstInterviewToRejected"/>
<list>
<property>
<object>
<object id="SecondInterview" type="SimpleStateMachine.State, SimpleStateMachine">
<property name="Id" value="second_interview"/>
<property name="Name" value="Second Interview"/>
<property name="Links">
<list element-type="SimpleStateMachine.Link, SimpleStateMachine">
<ref object="SecondInterviewToAccepted"/>
<ref object="SecondInterviewToRejected"/>
<list>
<property>
<object>
<object id="Accepted" type="SimpleStateMachine.State, SimpleStateMachine">
<property name="Id" value="accepted"/>
<property name="Name" value="Accepted"/>
<property name="Links">
<list element-type="SimpleStateMachine.Link, SimpleStateMachine">
<list>
<property>
<object>
<object id="Rejected" type="SimpleStateMachine.State, SimpleStateMachine">
<property name="Id" value="rejected"/>
<property name="Name" value="Rejected"/>
<property name="Links">
<list element-type="SimpleStateMachine.Link, SimpleStateMachine">
<list>
<property>
<object>
<object id="InterviewProcess.InterviewStateMachine" type="InterviewProcess.InterviewStateMachine, InterviewProcess">
<property name="AllStates">
<list element-type="SimpleStateMachine.State, SimpleStateMachine">
<ref object="Exam"/>
<ref object="FirstInterview"/>
<ref object="SecondInterview"/>
<ref object="Accepted"/>
<ref object="Rejected"/>
<list>
<property>
<property name="InitialState" ref="Exam"/>
<object>
<object id="SimpleStateMachine.IStateMachineManager" type="SimpleStateMachine.StateMachineManager, SimpleStateMachine">
<object>
<objects>
Quite Simple? I think so :) Let us try it.
At the end I am not saying that this a replacement for windows workflow foundation is a very powerful framework but I am only pushing people to think outside of the box.
You can refer to the full source code
here and don't forgot that I used Visual Studio 2010 Beta 2. Good Luck!
The initials of my blog are WWWW, isn't this cool? :D ... maybe this will be the next WWW ;).