Pool Manager: An Automation Server Sample
An Automation server exposes properties and methods that can be set and called from other Automation-capable applications.
All you need to do to create an Automation server is:
- Create a project.
- Add a .vcx file with an OLE Public class or a .prg file that defines a class with the OLEPUBLIC keyword.
- Create a .dll or an .exe file.
An Automation server can be deployed locally or remotely, exposing business functionality through methods that can be called and properties that can be set.
This is an example of a Pool Manager implemented in a custom Automation server. A client can send jobs to this Pool Manager, which can be located on a remote computer, and have it handle the job processing. This makes it possible for you to continue working because the resources of the pool manager handle all the work. The jobs in this sample are dummy simulation jobs.
To open the project for the Pool Manager sample
Type the following in the Command window:
MODIFY PROJECT (HOME(2) + 'servers\poolmgr\pool')
To run the Pool Manager sample
- Open Pool.pjx and choose Build.
- In the Build Options dialog box, select Build Executable and choose OK to create Pool.exe. The server is registered when you build the executable file.
- Run Pool.scx.
Pool Init Event
The first code to execute when you run the Pool form is the Init event, which creates a poolmgr object:
* Pool Init
SET PROC TO jobmgr.prg
THIS.oPoolMgr = CreateObject('Pool.Poolmgr')
When the oPoolMgr object is created, an array is dimensioned to keep track of jobs and a timer object, based on the PoolTimer class, is created to check for new or completed jobs.
Pool AddJob Method
When the user chooses the Print, Fax, or Excel Chart buttons on the pool form, the AddJob method of the form is called. AddJob performs the following:
Redimensions an array to keep track of outstanding jobs
Creates an object based on a specific subclass of NewJob: FaxJob, PrintJob, or GraphJob. These classes are defined in JOBMGR.prg, and take a reference to the form as an argument.
Passes the job object to the NewJob method of the PoolMgr object:
PARAMETER cJobType LOCAL oNewJobRef IF ALEN(THIS.aJobs)>1 OR TYPE('THIS.aJobs[1]') = 'O' DIMENSION THIS.aJobs[ALEN(THIS.aJobs)+1] ENDIF oNewJobRef = CreateObject(m.cJobType,THIS) THIS.oPoolMgr.NewJob(m.oNewJobRef)
PoolMgr NewJob Method
The NewJob method of the PoolMgr object redimensions the two dimensional PoolMgr job array and stores a reference to the job object in the first element of the new row and 0 to the second element, indicating that this is a new job.
PARAMETER oNewJob
IF TYPE('oNewJob') # 'O' OR ISNULL(m.oNewJob)
RETURN .F.
ENDIF
IF ALEN(THIS.aJobObjs,1) > 1 ;
OR ISNULL(THIS.aJobObjs[1])
DIMENSION THIS.aJobObjs[ALEN(THIS.aJobObjs,1)+1,2]
ENDIF
THIS.aJobObjs[ALEN(THIS.aJobObjs,1),1] = oNewJob
THIS.aJobObjs[ALEN(THIS.aJobObjs,1),2] = 0
PoolTimer Timer Event
Every three seconds, the PoolTimer timer event code is executed. This code loops through the job array. If the second element is 0, indicating a new job, then a new PrintJob, FaxJob, or GraphJob object (subclasses of Job in Poolmgr.prg) is created to manage the job. For example, the following line creates an object based on PrintJob and stores a reference to it in the timer's aJobs array:
THIS.aJobs[ALEN(THIS.aJobs)] = CREATEOBJECT('Pool.PrintJob')
The second element in the array for that row is then set to 1 to indicate that the job has been started and the SetupJob method of the new object is called. A reference to the job object is passed to the SetupJob method:
THIS.aJobs[ALEN(THIS.aJobs)].SetupJob(THIS.Parent.aJobObjs[m.i,1])
The Job Class
The Job class is defined in Poolmgr.prg:
DEFINE CLASS Job AS FORM
When an object based on the Job class, or any of its subclasses, is created, the StartJob method of the object is called.
PROCEDURE SetupJob
PARAMETER oJob
THIS.oJob = m.oJob
THIS.Caption = THIS.oJob.Jobtype
THIS.Visible = .T.
ENDPROC
The PrintJob class, for example, is a subclass of Job. If the object created is based on PrintJob, the StartJob method does the default processing of the parent class StartJob method, setting the caption of the form and displaying a label. Then the INKEY( ) function is called to set a timeout of 10 seconds. In a functional implementation of this sample, instead of the INKEY( ) function, you would include code at this point to process the print job.
DEFINE CLASS PrintJob AS Job OLEPublic
PROCEDURE StartJob
DoDefault()
=INKEY(10)
THIS.EndJob()
ENDPROC
ENDDEFINE
The EndJob method of the object calls the JobDone method of the original job object and releases the PrintJob, FaxJob, or GraphJob object.
PROCEDURE EndJob
THIS.lbl1.caption = 'Ending job...'
THIS.oJob.JobDone()
THIS.oJob = .null.
THIS.Visible = .F.
THISFORM.Release
ENDPROC
Code in the JobDone method of the original job object notifies the form that the job has been completed by calling the JobDone method of the form.
PROCEDURE jobdone
IF TYPE('THIS.oFormRef')='O'
THIS.oFormRef.JobDone(THIS.JobType)
ENDIF
ENDPROC
Finally, the JobDone method of the form displays the status of the job in the list box on the form:
PARAMETER cJob
THIS.lstJobs.AddItem(m.cJob+' job is complete.')
The Life of the Job Object
The job object (based on the PrintJob, FaxJob, or GraphJob class defined in JOBMGR.prg) is:
- Created in the AddJob method of the Pool form.
- Passed to the NewJob method of the PoolMgr class.
- Stored in the PoolMgr class to an element in an array
- Passed in the Timer event of the timer object in PoolMgr to the SetupJob method of the PrintJob, FaxJob, or GraphJob object (as defined in Poolmgr.prg, not JOBMGR.prg, and created in the Timer event).
- Stored to a property of the PrintJob, FaxJob, or GraphJob class in the SetupJob method.
- Set to .NULL. in the EndJob method of the PrintJob, FaxJob, or GraphJob object, after the JobDone method of the job is called.