Saturday, December 26, 2009

Workflow Without Windows Workflow

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:
  1. Configuration File for our Workflow (State Machine): Keeps the state information and the transitions between states.
  2. 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 ;).

2 comments:

Unknown said...

This information is magnificent. I understand and respect your clear-cut points. I am impressed with your writing style and how well you express your thoughts.

Ahman Adam Money Marketing Software School Software Software Company

kumar said...

Firstly I want to say thanks for the useful information that you are giving here on this post. Every time I come to this site, I always walk away with a lot of new knowledge.Thanks for sharing.
Engineering Colleges in Chennai, Mechanical Engineering Colleges in Chennai