Previous Contents Index DocHome Next |
Process Manager 6.0 (SP1) Programmer's Guide |
Chapter 3 Advanced Office Setup Application
This chapter discusses the AdvancedOfficeSetup sample application that is provided with Process Builder. This application, which is an advanced version of the OfficeSetup sample application, uses both a custom data field and a custom activity.The sections in this chapter are:
Changes in the Advanced Office Setup Application
Changes in the Advanced Office Setup Application
The advanced office setup sample application basically achieves the same goal as the simple office setup application, which is to get an office ready for a new employee. However, the advanced version has been fine-tuned to improve the process.The differences between the two versions are:
The advanced version uses a custom data field to dynamically generate the list of computers that can be purchased for the new employee.
- The intent here is to limit the choice a pre-defined selection of computers that have been approved for corporate use. Previously, the computer choice was represented as a text field, thus the administrative assistant could enter any computer they wanted in this field, from a Palm Pilot to a Cray supercomputer.
- The figure below shows the pop-up menu of computer choices.
Figure 3-1    Pop-up menu of computers
![]()
The advanced version has a custom activity that automatically schedules the new employee to attend a company orientation training.
The advanced version has an additional manual activity which requires the administrative assistant to print a page that tells the employee what day to attend company orientation training. This page is written by the custom activity.
- The day of the training depends on which department the employee is joining and what day they start work at the company. The following figure shows the custom activity in the process map, as well as a new user activity for printing the information about the training.
![]()
The Custom Data Field
This section discusses the custom data field and has the following subsections:
Overview
Overview
The advanced office setup application uses a custom data field called dfComputerChoice that presents a pop-up menu of computers that can be ordered for the new employee, as shown in Figure 3-1.This data field dynamically generates the list of computers every time it is displayed in edit mode. It gets the list by reading an XML file containing the choices. An example of the XML file is:
This XML file resides in the same folder as the application. When the process designer deploys the application from the Builder, the XML file is automatically copied to the correct location on the server. After the application has been deployed, users can modify the file whenever the company's computer purchase policy changes. The changes take effect immediately.
The selected value is stored externally as an object that is serialized to a file.
To see the entire source code file, click updatableList.java.
The Code in Detail
This section discusses the code for the methods on the custom data field.
loadDataElementProperties ()
loadDataElementProperties ()
This method reads the properties that were set in the Builder. In this case, it reads the value of the xmlfile property and stores it in a global variable, myFileName.Although as a general rule you should not store data in instance variables, in this case it is OK because this file name is constant for all process instances in the application -- it never changes. (The contents of the file might change, but the file name itself never changes).
display()
When a form containing the custom data field is displayed in an HTML page, the field's display() method is invoked. If the process is at an entry point, the entry point version of display() is invoked; if it is at a work item then the work item version is used.The purpose of this data field is to present a list of choices, store the selection, and retrieve the selection the next time the data field is displayed. Therefore, in an entry point, there is no point displaying the field in view mode, since there is no prior selection to view.
The data field shows a menu of computers, which is displayed as a SELECT list, for example:
At an entry point in edit mode, the data field reads the XML file and displays all the choices. At a work item in edit mode, the data field checks if there is a previously selected value. If a value has been chosen previously, the data field displays it as the current selection. If a value has not been chosen previously, the data field displays the default initial value.
The data field has no meaning when used in view mode at an entry point, thus is displayed as a simple warning. The data field is displayed as plain text showing the current selection in view mode at a work item.
Here is a discussion of the display() method for a work item. The code is similar but simpler for the a work item, since it does not need to consider whether there is a previously selected value or not.
display() at a Work Item
In edit mode, the display() method starts by calling getData() to get the value of the data field. If the value is already loaded, getData() simply returns it, otherwise getData() invokes load() to load the value. In this case, load() gets the value by reading it from a file. The retrieved value is an object that has a variable, myvalue, which indicates the current value. For example, if the hiring manager has previously selected Apple Imac as the computer for the new employee, then myvalue would be bound to Apple Imac.The setting of the myvalue variable happens in the store() method, which we will worry about later. For now, it's enough to know that the myvalue variable holds the selected option.
The display() method writes the HTML code to display a SELECT menu. Each menu item is embedded in an <OPTION> tag. The selected menu item is indicated by <OPTION SELECTED>.
The display() method reads all the menu items from the appropriate XML file. If no menu item has been previously selected, it uses a default value for the selected option, which in this case is <OPTION SELECTED>Choose now</OPTION>. Then the method writes <OPTION> tags for all the menu items.
If a menu item has been previously selected, the display() method writes the appropriate <OPTION SELECTED> tag. Then it takes each menu item in turn, checks if it is the selected item, and if not, writes an <OPTION> tag for it.
In view mode, the data field is displayed as plain text since it is not editable.
case MODE_VIEW:
// In View mode, display the selected option as a string
// The user cannot change the value in View mode
buffer.append(" "+ selectedOption);
break;
}Finally, the method writes the entire buffer to the HTML page.
// Write the contents to the HTML page
html.write(buffer.toString());
}
display() at an Entry Point
The display() method for the entry point is similar but simpler. It does not have any of the conditional code used in edit mode to check for an existing value, since there can be no existing value. In view mode, the data field displays a warning since there is no good reason to ever use this data field in view mode in an entry point. See the source code for updatableList.java for the definition for the display() method at an entry point.
update()
When a form containing the custom data field is submitted, the field's update() method is invoked. In this case, update() creates an object and sets the value of its myvalue variable, then puts the object into the process instance. Later, the store() method gets the value of the data field back out of the process instance and saves it to a file as a serialized object. The next time the data field value needs to be retrieved, the load() method reads the object from the file and puts it into the process instance.It may seem like overkill to create and save an object to store a single value, but the purpose of this example is to provide the groundwork for building your own custom data fields. You can use the same paradigm to store objects with multiple values, for example, if the data field needed to store the price and SKU of the chosen computer as well as just the name, it could use an object with three variables instead of one. The mechanism for saving the object to an external file would be exactly the same. The mechanism for storing the object is implemented by the store() method which is discussed later.
Code Discussion
The update() method parses the form parameters when the HTML form is submitted. An IPMRequest object containing all the values of the form elements is sent to the update() method. In this example, the update() method extracts the value of the form element that has the same name as the data field. (This form element was created by the display() method).Then the update() method creates a new instance of myObject and sets it myvalue variable to the extracted value. Finally it puts the new object into the process instance.
store()
This data field stores its value externally as a serialized object. (The object is created by the update() method.) The job of the store() method is to get the data field value out of the process instance and store it in a persistent storage. In this example, the store() method saves the value, which is an object, by serializing it to a file using standard object serialization techniques.
Code Discussion
The method generates a unique file name, consisting of the name of the data field plus the process instance ID.
When the data field value is needed in the future, the load() method retrieves it from the external storage. The load() method needs a key to help it find the data. The store method saves the key by calling setEntityKey(), and the load method retrieves the key by calling getEntityKey(). The load() method needs to know which file to access, thus the store() method saves the name of the file as the entity key.
// Store the file name as the entity key
pi.setEntityKey(getName(), thisFileName);Next, the store() method gets the value of the data field out of the process instance.
// Get the value of the data field from the pi.
// The value is an instance of myObject
myObject myobj = (myObject) pi.getData(getName());Now to the task of storing the value. In this case, store() saves the object to a file using standard Java object serialization techniques.
load()
When an attempt is made to access the value of the data field when it has not been loaded, the load() method is called. This happens, for example, when the data field is being displayed in an HTML form or when an automated activity calls getData() to get the value of the data field.The task of the load() method is to retrieve the data field value from external storage and put it in the process instance. In this case, the value is stored as an object in a file.
Code Discussion
The first thing this load() method needs to do is to find out which file to access. The name of the file is stored as the entity key, thus load() starts off by getting the entity key.
If the entity key is a file name, the next thing to do is to get generate the full path to the file. The load() method uses the user-defined getMyApplicationsPath() method to find the path to the directory where the application is stored. The file is in that directory.
Now comes the task of loading the value. In this case, the value is an instance of myObject that has been serialized to a file. The load() method uses standard Java techniques for reading the file and unserializing the object.
The load() method puts the retrieved value into the data field on the process instance, where it is now available for access by all comers (such as the display() method).
// Put the object in the data field in the process instance
pi.setData(getName(), newobj);Finally, the load() method closes the try clause, writes the catch clause, and takes account of the situation where getEntityKey() did not return a value.
// end try clause
}
catch (Exception e)
{
System.out.println("Error while reading value from file: "
+ e);
}
// end if (thisFileName != null)
}
else {
pi.setData(getName(), null);
}
// end load
}
Helper Functions
This class uses several helper methods:
getMyApplicationsPath()
getMyApplicationsPath()
This method returns the directory where the current application resides.
fetchDataFromXML()
This method reads the contents of an XML file that contains a series of items. The method adds each item to a vector and then returns the vector.To start with, the method creates an empty vector and gets the name of the file to read.
Next, the method reads the file into a string.
Next, the method iterates through every character in the content string contained in the charSet variable, looking for items. It uses the parseForItemTag() method to find items and add each one to the vector.
Finally the method returns the vector.
parseForItemTag()
This method iterates over a string, looking for substrings embedded between <ITEM> and </ITEM> tags. Each substring, or item, is added to a vector.
Complete Source Code
For the complete source code, click the following links:
updatableList.java
The Custom Activity
This section discusses the custom data field and has the following subsections:
Overview
Overview
The advanced office setup application uses a custom activity called employeeTrainingPerformer to schedule each new employee to attend a company orientation. The activity writes a web page telling the employee when to attend the orientation. The day that the employee should attend orientation depends on what department they are joining, for example, engineers attend on Mondays while marketing personnel attend on Tuesdays. The custom activity schedules the employee to attend training on the first appropriate day after they start work. Trainings are held at 2 pm so they can go to training on their start date if necessary.For example, the training day for marketing personnel is Tuesday. So if a marketing in the marketing department starts on Monday, they are scheduled for training the next day. If they start on Tuesday, they are scheduled for training on their first day. If they start on Wednesday, they are scheduled for training the following Tuesday.
The custom activity reads the training schedule from a file called trainingDays.xml. An example is:
This XML file resides in the same folder as the application. The process designer must manually copy this file into the correct place in the Builder directory. When the process designer deploys the application from the Builder, the XML file is automatically copied to the correct location on the server. After the application has been deployed, users can modify the file whenever the training schedule changes. The changes take effect immediately.
To see the entire source code file, click employeeTrainingPerformer.java.
The Code in Detail
This section discusses the code for the following.
EmployeeTrainingPerformer.xml
EmployeeTrainingPerformer.xml
A custom activity receives input data from an xml file that has the same base name as the activity. This xml file defines the elements in an input hashtable that is passed to the custom activity automatically. Typically, the elements in the input hashtable are data field values, but they can be any JavaScript expression. In this case, the input hashtable puts the value of the dfEmpname data field value into the Emp_name element, the dfDeptName data field value into the Dept element, and the dfStartDate data field value into the Start_Date element.
The EmployeeTrainingPerformer.xml file also puts the applications path into the element path and the process instance ID into the element id. The custom activity uses the applications path to identify where the training schedule resides and it uses the process instance id to generate a unique file name for the welcome page.
<PARAMETER NAME="path" DESCRIPTION="Applications path">
getApplicationPath()
</PARAMETER>
<PARAMETER NAME="id" DESCRIPTION="Process Instance ID">
getProcessInstance().getInstanceId()
</PARAMETER>A custom activity can put elements into an output hashtable. The same xml file that defines the input parameters also defines what happens to the elements in the output hashtable when the custom activity is completed. Typically, values are saved into data fields on the process instance. In this case, the output hashtable contains a filename which is saved into the dfWelcomePage data field.
<OUTPUT>
<PARAMETER NAME="welcomePage"
DESCRIPTION="Greeting for New Employeer">
mapTo("dfWelcomeURL")
</PARAMETER>
</OUTPUT>
<EXCEPTIONS></EXCEPTIONS>
<DESIGN></DESIGN>
</WORKPERFORMER>
perform()
The perform() method of a custom activity executes the activity's task. In this case, it generates an HTML page telling the new employee when to attend training. The method reads the employee's start date, name and department from the input hash table. It also gets the pathname where the application resides, as well as the process ID which is a number that uniquely identifies the process instance.
Then it calls the readSchedule() method to read the TrainingDays.xml file, which resides in the applications directory.
// Read the schedule from the TrainingDays.xml file
Hashtable trainingDays = readSchedule(appPath);Next, it calls the scheduleTraining() method to figure out which day the employee must attend training.
// Figure out what day of the week the employee goes to training
Date trainingDate = scheduleTraining(startDate, dept,
trainingDays);The perform() method then calls the writeWelcomePage() method to write an HTML page that informs the employee when to attend company orientation training.
// Write a welcome page containing the training info
String filename = writeWelcomePage(empName, thisID, appPath,
trainingDate);Finally, perform() puts the filename for the welcome page into the output hash table so that it can be saved into a data field on the process instance.
// Put the file name for the HTML page in the output hashtable
output.put("welcomePage", filename);
}
Helper Functions
The perform() method uses the following helper methods:
readSchedule()
- which uses the helper method
IncrementForDayOfWeek()
writeWelcomePage()
readSchedule()
This function reads the training schedule and returns a hashtable containing key:value pairs of dept:day. The method creates a hashtable to hold the results. It gets the full path to the file containing the training schedule.
private Hashtable readSchedule(String appPath)
{
Hashtable trainingDays = new Hashtable();
try{
// Get the full name for the training schedule
String Path = appPath + "\\" + "TrainingDays.xml";Then it creates a file reader.
// Create a file reader
java.io.File f = new java.io.File(Path);
FileReader fr = new FileReader(f);
BufferedReader in = new BufferedReader(fr);It reads the entire contents of the file into the String variable charSet.
// Read the entire file into the String "charSet"
int MAX_LENGTH = 500;
char xml[] = new char[MAX_LENGTH];
int count = 0;
count = in.read(xml, count, MAX_LENGTH);
String charSet = new String(xml);It gets some variables ready for parsing the file.
// Create variables in preparation for parsing the String "xml"
int charSetLength = charSet.length();
String temp = new String();
String dept = new String();
String day = new String();
count = 0;The method start parsing the string. First it looks for the substring <DEPT>. When it's found that, it reads the substring between the end of <DEPT> and the starting "<" in </DAY>. It stores this substring in the variable dept.
The parser has just reached the end of </DEPT> in the string. Now it looks for <DAY>, then reads the substring between the end of <DAY> and the starting "<" in </DAY> and stores the substring in the variable day. It puts an element representing the dept and day into the trainingDays hashtable.
scheduleTraining()
This method figures out what date the new employee is to attend orientation training. To do this, it figures out what day of the week the employee starts work, finds out what department the employee is joining, looks up the training day for that department in the trainingDays hashtable, and then calculates the date for the training.First, the method gets the day of week, day of month, month and year that the employee is starting work.
Then the method looks in the trainingDays hashtable to see what day of the week the employee goes to training, which depends on what department they are joining. The scheduleTraining() method then calls a helper function to find the date of the first appropriate day of the week on or after the start date. For example, if the employee should attend training on Monday, the helper function returns the start date if it is a Monday or else finds the date of the first Monday following the start date.
IncrementForDayOfWeek()
The scheduleTraining() method uses helper functions to find the first appropriate day of the week on or after the start date. All these methods have the same basic structure. Here is an example for IncrementForMonday(), which takes a week day and a day of the month. It returns the day of the month unchanged if the given week day is Monday, else returns the day of the month for the first Monday following the day of the month that was passed in.
writeWelcomePage()
This method generates an HTML page that informs the employee when to attend training, for example:The method starts by formatting the Date string to make it more readable and generating a unique pathname for a new file in the applications folder.
Note: For the code for formatDateString(), see the source code for EmployeeTrainingPerformer.java.
Then it creates a file with the name it has just derived, and writes a welcome message for the new employee into the file. This message includes the date of the employee's orientation training.
Complete Source Code
For the complete source code, click the following links:
EmployeeTrainingPerformer.java
Previous Contents Index DocHome Next
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.
Last Updated November 02, 2000