home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Module Name: wfl.cpp
- //
- // Description: Demonstration of workflow management system.
- // Built on top of the link-list and binary tree algorithms.
- //
- // Written by: John Tal
- //
- //
- // Modification History:
- //
- // Date Programmer Mod# Modification
- // ---------------------------------------------------------------------------
- // 03-JUL-1991 J. Tal V1.0-000 New
- //
- //
- //
-
- #include <iostream.h>
- #include <string.h>
-
-
- #include "cmemlib.h"
-
- #include "wfl.h"
-
-
-
- //
- // CompareState used for SHORT to node comparison of short ids
- // by search routines
- //
-
- SHORT CompareState(PVOID pvData1,PVOID pvData2)
- {
-
- PSHORT psState1;
- PSHORT psState2;
- WORK_ITEM_P pstWorkItem;
- LLIST_CP pclList;
-
-
- psState1 = (PSHORT) pvData1; // get direct state in short
-
- pclList = (LLIST_CP) pvData2; // ptr to list class
-
- pclList -> FindFirst((PPVOID) &pstWorkItem); // get first object/item in list class
-
- psState2 = &(pstWorkItem -> sState); // get state
-
- if(*psState1 == *psState2)
- return(0);
- else if(*psState1 > *psState2)
- return(-1);
- else
- return(1);
-
- }
-
- //
- // May want to make function more sophisticated in future, now just
- // takes first one
- //
-
-
- SHORT PROFILE_C::Get(PROFILE_PP ppclProfile)
- {
- C_DEF_MODULE("PROFILE_C::Get")
-
-
- C_STATUS = clProfiles.FindFirst((PPVOID) ppclProfile);
-
- C_RETURN
- }
-
-
-
- //
- // CompareNodeState used for node to node comparison of short ids
- // by delete routines
- //
-
- SHORT CompareNodeState(PVOID pvData1,PVOID pvData2)
- {
- PSHORT psState1;
- PSHORT psState2;
-
- LLIST_CP pclList1;
- LLIST_CP pclList2;
-
- WORK_ITEM_P pstWorkItem1;
- WORK_ITEM_P pstWorkItem2;
-
-
- pclList1 = (LLIST_CP) pvData1; // class is at this ptr
-
- pclList1 -> FindFirst((PPVOID) &pstWorkItem1); // get first object/item in list class
-
- psState1 = &(pstWorkItem1 -> sState); // ptr to state
-
-
-
- pclList2 = (LLIST_CP) pvData2; // class of link list at this ptr
-
- pclList2 -> FindFirst((PPVOID) &pstWorkItem2); // get first object/item in list class
-
- psState1 = &(pstWorkItem2 -> sState); // ptr to state
-
-
-
- if(*psState1 == *psState2)
- return(0);
- else if(*psState1 > *psState2)
- return(-1);
- else
- return(1);
-
- }
-
- //
- // CompareIdNode
- //
-
-
- SHORT CompareIdNode(PVOID pvData1,PVOID pvData2)
- {
- PCHAR pcId1;
- PCHAR pcId2;
-
- pcId1 = (PCHAR) pvData1;
- pcId2 = (PCHAR) pvData2;
-
- return(strcmp(pcId1,pcId2));
- }
-
-
- //
- // WrkProAdd
- //
- // Adds a profile for a process to the process' profile list
- //
-
- SHORT PROFILE_C::Add(PROFILE_P pstAProfile)
- {
- C_DEF_MODULE("WrkProAdd")
-
- PROFILE_P pstProfile;
- PVOID pvData;
-
-
- pstProfile = new PROFILE_T;
-
- memcpy(pstProfile,pstAProfile,sizeof(PROFILE_T));
-
-
- C_STATUS = clProfiles.FindLast(&pvData);
-
- C_STATUS = clProfiles.AddAfterCur((PVOID) pstProfile);
-
- C_RETURN
- }
-
-
- //
- // Add another job.
- // Each workflow_T is in a linked-list off of a single binary tree node
- //
-
- SHORT
- WORK_FLOW_C::Add(PCHAR szId, SHORT sState, PVOID pvData)
- {
- C_DEF_MODULE("WORK_FLOW_C::Add")
-
- PVOID pvData1;
- PVOID pvData2;
- LLIST_CP pclLlist;
- WORK_ITEM_P pstWorkItem;
-
- pstWorkItem = new WORK_ITEM_T;
-
-
- //
- // Check if in Id Tree, if so, is error
- //
-
- C_STATUS = clIdTree.SetCompareFunc(CompareIdNode);
-
- C_STATUS = clIdTree.Find((PVOID) szId,&pvData1); // fix 16-Feb-92 was pvData
-
- if(pvData1 != NULL) // fix 16-Feb-92 was pvData
- {
- C_LEAVE(WRK_DUPLICATE_ID)
- }
-
-
- //
- // Add to Id Tree
- //
-
- C_STATUS = clIdTree.Insert((PVOID) szId);
-
- //
- // Populate new item
- //
-
- pstWorkItem -> sState = sState;
- strcpy(pstWorkItem -> szId, szId);
- pstWorkItem -> fLocked = C_FALSE;
- pstWorkItem -> pvData = pvData;
-
-
- C_STATUS = clStateTree.SetCompareFunc(CompareNodeState);
-
- C_STATUS = clStateTree.Find((PVOID) &sState,(PPVOID) &pvData1);
-
- if(pvData1 == NULL)
- {
-
- #if DEBUG
- cout << "WrkJobAdd: Adding entry for state " << pstWorkItem -> sState << "\n";
- #endif
-
- //
- // Must add entry for this state
- //
-
- pclLlist = new (LLIST_C);
-
- //
- // Put info on Work Item into link list
- //
-
- pclLlist -> Insert((PVOID) pstWorkItem);
-
- //
- // Put info on Link List into Tree
- //
-
- C_STATUS = clStateTree.Insert((PVOID) pclLlist);
-
- }
- else
- {
- #if DEBUG
- cout << "WrkJobAdd: Appending entry for state " << pstWorkItem -> sState << "\n";
- #endif
-
- //
- // Find current llist
- //
-
- pclLlist = (LLIST_CP) pvData1;
-
- //
- // Find last one of current list
- //
-
- C_STATUS = pclLlist -> FindLast((PPVOID) pvData2);
-
- //
- // Add new one after current last one
- // Maintains FIFO ordering
- //
-
- C_STATUS = pclLlist -> AddAfterCur((PVOID) pstWorkItem);
- }
-
- C_MODULE_EXIT:
-
- C_RETURN
- }
-
-
-
-
- //
- // WrkJobSelect, select a job to work on
- // Automatically locks a job when selected
- //
-
- SHORT WORK_FLOW_C::Select(PROFILE_CP pclProfile, PCHAR * ppcId, PVOID * ppvData)
- {
- C_DEF_MODULE("WORK_FLOW::Select")
-
- WORK_ITEM_P pstWorkItem;
- PROFILE_P pstProfile;
- BOOL fFoundJob = C_FALSE;
- LLIST_CP pclStateList;
-
- *ppvData = NULL;
-
-
-
- C_STATUS = pclProfile -> Get(&pstProfile);
-
- //
- // Check all jobs based on jobs which this process can process
- //
-
- C_STATUS = clStateTree.SetCompareFunc(CompareState);
-
-
- while(!C_STATUS && (pstProfile != NULL) && !fFoundJob)
- {
- C_STATUS = clStateTree.Find((PVOID)
- &(pstProfile -> sTrnState[WRK_SEL_STATE]),
- (PPVOID) &pclStateList);
-
- if(pclStateList == NULL)
- break;
-
- if(pclStateList != NULL && !fFoundJob)
- {
- //
- // Found 1 or more jobs at this state
- //
- // Check each member in linked list till no more or got one
- //
-
- C_STATUS = pclStateList -> FindFirst((PPVOID) &pstWorkItem);
-
- while(pstWorkItem != NULL && !fFoundJob)
- {
- if(!pstWorkItem -> fLocked)
- {
-
- //
- // Mark job as locked, we are new owners
- //
-
- pstWorkItem -> fLocked = C_TRUE;
-
- strcpy(pstWorkItem -> szKey, pstProfile -> szKey);
-
- *ppcId = pstWorkItem -> szId;
-
- *ppvData = pstWorkItem -> pvData;
-
- fFoundJob = C_TRUE;
-
- }
-
- //
- // If still looking, check next job
- //
-
- if(!fFoundJob)
- {
- C_STATUS = pclStateList -> GetNext((PPVOID) &pstWorkItem);
- if(C_STATUS)
- break;
- }
- }
-
- }
-
- //
- // If still looking, check next profile
- //
-
- //if((pclStateList == NULL) && !fFoundJob)
- // C_STATUS = pclProfile -> Get(&pstProfile);
- }
-
- if(!fFoundJob)
- C_SET_STATUS(WRK_NO_JOB);
-
- C_RETURN
-
- }
-
-
- //
- // WrkJobTrans
- //
- // Set the job to the appropriate transition state
- // and unlocks job if told to
- //
-
- SHORT WORK_FLOW_C::SetTrans(PCHAR szId, PROFILE_CP pclProfile, SHORT sTrnStateNdx)
- {
- C_DEF_MODULE("WORK_FLOW_C::SetTrans")
-
- SHORT sSaveState;
- WORK_ITEM_P pstWorkItem;
- PVOID pvData;
- PROFILE_P pstProfile;
- BOOL fFoundJob;
- LLIST_CP pclStateList;
-
- #if DEBUG
- cout << "WrkJobTrans: Setting " << szId << " to state ndx " << sTrnStateNdx << "\n";
- #endif
-
- #ifdef WHY
-
- //
- // Get WORK_ITEM based on szId
- //
-
- C_STATUS = clIdTree.SetCompareFunc(CompareIdNode);
-
- C_STATUS = clIdTree.Find((PVOID) szId, (PPVOID)&pstWorkItem);
-
-
- //
- // Must also unlink from link list in workflow tree
- // and add to new link list
- //
-
- #endif
-
-
-
- C_STATUS = pclProfile -> Get(&pstProfile);
-
- sSaveState = pstProfile -> sTrnState[sTrnStateNdx];
-
-
-
- C_STATUS = clStateTree.SetCompareFunc(CompareState);
-
- while(!C_STATUS && (pstProfile != NULL) && !fFoundJob)
- {
- C_STATUS = clStateTree.Find((PVOID)
- &(pstProfile -> sTrnState[WRK_SEL_STATE]),
- (PPVOID) &pclStateList);
-
- if(pclStateList != NULL && !fFoundJob)
- {
- //
- // Found 1 or more jobs at this state
- //
- // Check each member in linked list till no more or got one
- //
-
- C_STATUS = pclStateList -> FindFirst((PPVOID) &pstWorkItem);
-
- while(pstWorkItem != NULL && !fFoundJob)
- {
-
- //
- // All same states, check if match on owner
- //
-
- if(strcmp(pstWorkItem -> szKey,pstProfile -> szKey) == 0)
- {
-
- //
- // Found it, delete from old list, add to new/current one
- //
-
- fFoundJob = C_TRUE;
-
- C_STATUS = pclStateList -> DeleteCur();
-
- C_STATUS = pclStateList -> FindFirst((PPVOID) & pvData);
-
- if(pvData == NULL)
- {
-
- //
- // Delete tree entry because no more at this state
- //
-
- C_STATUS = clStateTree.Delete((PVOID) &sSaveState);
- #if DEBUG
- cout << "WORK_FLOW_C::Trans: Deleting state " << sSaveState << "\n";
- #endif
-
- }
- else
- {
- #if DEBUG
- cout << "WrkJobTrans: Resetting node for state " << sSaveState << "\n";
- #endif
- }
-
- //
- // Add to new/current list
- //
-
- C_STATUS = pclProfile -> Get(&pstProfile);
-
- pstWorkItem -> sState = pstProfile -> sTrnState[sTrnStateNdx];
-
-
- C_STATUS = Add(szId,pstWorkItem -> sState,(PVOID) pstWorkItem);
-
- }
-
- C_STATUS = pclStateList -> GetNext((PPVOID) &pstWorkItem);
-
- }
-
- }
-
- }
-
-
- C_RETURN
-
- }
-
-
-
- //
- //
- //
-
-
- SHORT WORK_FLOW_C::UnLock(PCHAR pcId, PROFILE_CP pclProfile)
- {
- C_DEF_MODULE("WORK_FLOW_C::UnLock")
-
- PVOID pvData;
- BOOL fFoundJob = C_FALSE;
- SHORT sCnt;
- WORK_ITEM_P pstWorkItem;
- PROFILE_P pstProfile;
-
- LLIST_CP pclStateList;
-
- #if 0
-
- //
- // Look in Id Tree
- //
-
- C_STATUS = clIdTree.SetCompareFunc(CompareIdNode);
-
- C_STATUS = clIdTree.Find((PVOID) pcId,&pvData);
-
- if(pvData == NULL)
- {
- C_LEAVE(WRK_NO_JOB)
- }
-
-
- pclProfile -> Get(&pst
- pstWorkItem = (WORK_ITEM_P) pvData;
-
- //
- // See if profiles have access to pcId
- //
- // This is done by comparing pcId current state to selection or
- // activation state of profile
- //
-
- pstProfile = NULL;
-
- C_STATUS = pclProfile -> Get(&pstProfile);
-
- while(!C_STATUS && (pstProfile != NULL) && !fFoundJob)
- {
-
- for(sCnt = 0; sCnt < pstProfile -> sTrnStates; sCnt++)
- if(pstWorkItem -> sState == pstProfile -> sTrnState[sCnt])
- {
- fTrnOk = C_TRUE;
- break;
- }
-
- if(
- (fTrnOk)
- &&
- (pstWorkItem -> fLocked)
- &&
- (strcmp(pstWorkItem -> szKey,pstProfile -> szKey) == 0)
- )
- {
- pstWorkItem -> fLocked = C_FALSE;
- fFoundJob = C_TRUE;
- }
-
-
- }
-
-
- C_MODULE_EXIT:
-
- C_RETURN
-
- #endif
-
-
- C_STATUS = pclProfile -> Get(&pstProfile);
-
- //
- // Check all jobs based on jobs which this process can process
- //
-
- C_STATUS = clStateTree.SetCompareFunc(CompareState);
-
-
- while(!C_STATUS && (pstProfile != NULL) && !fFoundJob)
- {
- C_STATUS = clStateTree.Find((PVOID)
- &(pstProfile -> sTrnState[WRK_ACT_STATE]),
- (PPVOID) &pclStateList);
-
- if(pclStateList == NULL)
- break;
-
- if(pclStateList != NULL && !fFoundJob)
- {
- //
- // Found 1 or more jobs at this state
- //
-
- C_STATUS = pclStateList -> FindFirst((PPVOID) &pstWorkItem);
-
- while(pstWorkItem != NULL && !fFoundJob)
- {
- if(pstWorkItem -> fLocked)
- {
-
- //
- // Mark job as locked, we are new owners
- //
-
- pstWorkItem -> fLocked = C_TRUE;
-
- fFoundJob = C_TRUE;
-
- }
-
- //
- // If still looking, check next job
- //
-
- if(!fFoundJob)
- {
- C_STATUS = pclStateList -> GetNext((PPVOID) &pstWorkItem);
- if(C_STATUS)
- break;
- }
- }
-
- }
-
- }
-
- C_RETURN
-
- }
-
-
- /////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////////
-
-
- #define TEST 1
- #define DEBUG 1
-
-
-
- #ifdef TEST
-
- //
- // Beginning of test program
- //
-
-
- struct JOB_S // a dummy 'job' to process //
- {
- SHORT sData1;
- SHORT sData2;
- };
-
- typedef struct JOB_S JOB_T;
- typedef JOB_T * JOB_P;
-
-
- JOB_T stJob1; // some jobs //
- JOB_T stJob2;
- JOB_T stJob3;
- JOB_T stJob4;
-
-
- int Process1(); // processes to process the jobs //
- int Process2();
- int Process3();
-
-
- int (*Procs[3])() = { Process1, Process2, Process3 }; // array of processes //
-
-
- WORK_FLOW_C clWorkFlow;
-
- PROFILE_C clProfile1;
- PROFILE_C clProfile2;
- PROFILE_C clProfile3;
-
- int DoProcs();
-
-
-
- main()
- {
- C_DEF_MODULE("main")
-
- SHORT s1,s2,s3,s4,s5,s6;
-
- PROFILE_T stProfile;
-
- //
- // Initialize 'Job' data
- //
-
- stJob1.sData1 = 0; // 'bad data' , will get sent 1, to 2, to 1, to 3 //
- stJob1.sData2 = 0;
-
- stJob2.sData1 = 1;
- stJob2.sData2 = 1;
-
- stJob3.sData1 = 1;
- stJob3.sData2 = 1;
-
- stJob4.sData1 = 1;
- stJob4.sData2 = 1;
-
- //
- // Initialize data for each 'process'
- //
-
- strcpy(stProfile.szKey,"PRE_PROC");
- stProfile.sTrnStates = 5;
- stProfile.sTrnState[0] = 100; // Selection //
- stProfile.sTrnState[1] = 101; // Activation //
- stProfile.sTrnState[2] = 300; // successful completion //
- stProfile.sTrnState[3] = 200; // error 1 //
- stProfile.sTrnState[4] = 250; // error 2 //
-
- clProfile1.Add(&stProfile);
-
- strcpy(stProfile.szKey,"ERR_PROC");
- stProfile.sTrnStates = 5;
- stProfile.sTrnState[0] = 200; // Selection //
- stProfile.sTrnState[1] = 201; // Activation //
- stProfile.sTrnState[2] = 100; // successful completion //
- stProfile.sTrnState[3] = 999; // error 1 //
- stProfile.sTrnState[4] = 998; // error 2 //
-
- clProfile2.Add(&stProfile);
-
- strcpy(stProfile.szKey,"END_PROC");
- stProfile.sTrnStates = 5;
- stProfile.sTrnState[0] = 300; // Selection //
- stProfile.sTrnState[1] = 301; // Activation //
- stProfile.sTrnState[2] = 700; // successful completion //
- stProfile.sTrnState[3] = 970; // error 1 //
- stProfile.sTrnState[4] = 980; // error 2 //
-
- clProfile3.Add(&stProfile);
-
-
- //
- // Initialize each job
- //
-
-
- clWorkFlow.Add("Job1",100,(PVOID) &stJob1);
- clWorkFlow.Add("Job2",200,(PVOID) &stJob2);
- clWorkFlow.Add("Job3",300,(PVOID) &stJob3);
- clWorkFlow.Add("Job4",400,(PVOID) &stJob4);
-
- C_SET_STATUS(0);
-
- s1 = 1; // remember results of last 5 process executions //
- s2 = 0;
- s3 = 0;
- s4 = 0;
- s5 = 0;
- s6 = 0;
-
- do
- {
- s6 = s5;
- s5 = s4;
- s4 = s3;
- s3 = s2;
- s2 = s1;
-
- C_STATUS = DoProcs(); // simple 'multi-tasker' //
-
- if(!C_STATUS)
- s1 = 1;
- else
- s1 = 0;
-
- } while( (s1+s2+s3+s4+s5+s6) > 0);
-
-
- }
-
-
- //
- // 'Multi-task' (round-robin) the different processes
- //
-
- int DoProcs()
- {
- C_DEF_MODULE("DoProcs")
-
- static SHORT sLastProc = 0;
-
- C_STATUS = Procs[sLastProc]();
-
- sLastProc++;
-
- if(sLastProc > 2)
- sLastProc = 0;
-
- C_RETURN
-
- }
-
-
- //
- // Process 1
- //
-
- int Process1()
- {
- C_DEF_MODULE("Process 1")
-
- PCHAR pcId;
- JOB_P pstJob;
-
- cout << "Process 1 - Executing\n";
-
- C_STATUS = clWorkFlow.Select(&clProfile1,&pcId,(PPVOID) &pstJob);
-
- if(pstJob == NULL)
- {
- cout << "Process 1 - Found nothing to work on\n";
- C_STATUS = -1;
- }
- else
- {
-
- cout << "Process 1 - Working on job " << pcId << "\n";
-
- clWorkFlow.SetTrans(pcId,&clProfile1,WRK_ACT_STATE);
-
- if(pstJob -> sData1 == 0)
- {
- cout << "Process 1 - Incorrect Data on job " << pcId << "\n";
-
- clWorkFlow.UnLock(pcId,&clProfile1);
- clWorkFlow.SetTrans(pcId,&clProfile1,WRK_TRN_STATE+WRK_TRN_ERR_1);
- }
- else
- {
- cout << "Process 1 - Completing job " << pcId << "\n";
-
- clWorkFlow.UnLock(pcId,&clProfile1);
- clWorkFlow.SetTrans(pcId,&clProfile1,WRK_TRN_STATE+WRK_TRN_OK);
- }
- }
-
- C_RETURN
- }
-
-
- //
- // Process 2, is sent 'bad' data by process 1 for correction if possible
- //
-
- int Process2()
- {
- C_DEF_MODULE("Process 2")
-
- JOB_P pstJob;
- PCHAR pcId;
-
- cout << "\nProcess 2 - Executing\n";
-
-
- C_STATUS = clWorkFlow.Select(&clProfile2,&pcId,(PPVOID) &pstJob);
-
- if(pstJob == NULL)
- {
- cout << "Process 2 - Found nothing to work on\n";
- C_STATUS = -1;
- }
- else
- {
-
- cout << "Process 2 - Working on job " << pcId << "\n";
-
- clWorkFlow.SetTrans(pcId,&clProfile2,WRK_ACT_STATE);
-
- pstJob -> sData1 = 1; // Correct problem which sent it here //
-
- cout << "Process 2 - Completing job " << pcId << "\n";
-
- clWorkFlow.SetTrans(pcId,&clProfile2,WRK_TRN_STATE+WRK_TRN_OK);
-
- }
-
- C_RETURN
- }
-
-
- int Process3()
- {
- C_DEF_MODULE("Process 3")
-
- JOB_P pstJob;
- PCHAR pcId;
-
- cout << "\nProcess 3 - Executing\n";
-
- C_STATUS = clWorkFlow.Select(&clProfile3,&pcId,(PPVOID) &pstJob);
-
- if(pstJob == NULL)
- {
- cout << "Process 3 - Found nothing to work on\n";
- C_STATUS = -1;
- }
- else
- {
-
- cout << "Process 3 - Working on job " << pcId << "\n";
-
- clWorkFlow.SetTrans(pcId,&clProfile3,WRK_ACT_STATE);
-
- clWorkFlow.UnLock(pcId,&clProfile3);
- clWorkFlow.SetTrans(pcId,&clProfile3,WRK_TRN_STATE+WRK_TRN_OK);
-
- }
-
- C_RETURN
- }
-
- #endif
-