Sun ONE logo     Previous      Contents     Index      Next     
iPlanet Process Manager, Version 6.5 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

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 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 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 Custom Data Field

This section discusses the custom data field and has the following subsections:

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:


<xml version="1.0" encoding="us-ascii">
<ITEMSET>
   <ITEM>Apple Imac</ITEM>
   <ITEM>HP-4150 laptop</ITEM>
   <ITEM>HP-9150 laptop</ITEM>
   <ITEM>Sun Solaris workstation</ITEM>
   <ITEM>Windows NT/98</ITEM>
   <ITEM>Windows 2000</ITEM>
</ITEMSET>

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. The file UpdatableList.java, available in Appendix A "Scripts", contains the entire source code.

The Code in Detail

This section discusses the code for the methods on the custom data field.

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).


// Method from BasicCustomField that loads
// properties that were set in the Builder
protected void loadDataElementProperties (Hashtable entry)
   throws Exception
{
// Get the XML File name from the Builder properties
myFileName = (String)entry.get("xmlfile");
}

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:


<SELECT size="1" name="dfComputerChoice" >
   <OPTION selected>Choose now</OPTION>
   <OPTION value="Apple Imac">Apple Imac</OPTION>
   <OPTION value="HP-4150 laptop">HP-4150 laptop</OPTION>
   <OPTION value="HP-9150 laptop">HP-9150 laptop</OPTION>
   <OPTION value="Sun Solaris workstation">
      Sun Solaris workstation</OPTION>
   <OPTION value="Windows NT/98">Windows NT/98</OPTION>
   <OPTION value="Windows 2000">Windows 2000</OPTION>
</SELECT>

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.


public void display(IProcessInstance pi, IHTMLPage html,
   int displayMode, String displayFormat ) throws Exception
{

StringBuffer buffer = new StringBuffer();
String selectedOption = null;

// Get the value of the data field
// If the value is not loaded, getData invokes load()
myObject myobj = (myObject) pi.getData(getName());

// If an object is found, set the selected option
// to the value of the object's myvalue variable.
if (myobj != null) {
   selectedOption = myobj.myvalue;
}


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.


switch(displayMode){
// In edit mode, display the data field as a SELECT menu
// The menu options are stored in an xml file

case MODE_EDIT:
   // Get the option names from the xml file and store
   // them in the vector optionNames.
   Vector optionNames = fetchDataFromXML();

   // Write the opening <SELECT> tag.
   // The name is the same as the data field name.
   buffer.append("<select size=1 name=" + getName() + " >");

   // If the option was not selected previously show default
   String optName = "";
   if (selectedOption==null)
   {
      buffer.append("<option selected>Choose now</option>");

      // For each option in the vector optionNames
      // write <OPTION> value="optionName"</OPTION>
            for(int i=0; i<optionNames.size(); i++)
      {
         optName = (String)optionNames.elementAt(i);
         buffer.append("<option value=\"" + optName + "\">");
         buffer.append(optName);
         buffer.append("</option>");
      }
   }


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.


// Else write <OPTION SELECTED> value=selectedOption</OPTION>
// and the rest of the options below that

else
{
   buffer.append("<option selected>" + selectedOption +
      "</option>");

   // For each option in the vector optionNames, check if this
   // option is the selected one. If it is, ignore it since we
   // already wrote the HTML code for the selected option.
   // If it is not the selected one,
   // write <OPTION> value="optionName"</OPTION>
   for(int i=0; i<optionNames.size(); i++)
   {
      optName = (String)optionNames.elementAt(i);   
      if(! optName.equals(selectedOption))
      {
         buffer.append("<option value=\""+ optName +"\">");
         buffer.append(optName);
         buffer.append("</option>");
      }
   }
}
// End the Select list
buffer.append("</select>");
break;
}


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.


public void update(IProcessInstance pi, IPMRequest rq )
   throws Exception
{

try {   
   // Get the value of the form element
   String thisValue = rq.getParameter(getName());

   // Create a new myObject to hold the results
   myObject obj1 = new myObject();

   // Put the value into the object
   obj1.myvalue = thisValue;

   // put the object into the pi
   pi.setData(getName(), obj1);
   }
catch (Exception e) {   
   System.out.println("Problem translating form values: " + e);
   }
}


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.


public void store(IProcessInstance pi) throws Exception
{
   // Get the data field name
   String thisID = getName();

   // Get the process instance ID
   long procID = pi.getInstanceId();

   // Concatenate the data field name with the PID
   // to keep the name unique across all process instances
   thisID = thisID + procID;
   String thisFileName = thisID + ".txt";

   // Get the application directory
   String appdir = getMyApplicationsPath();

   // Generate the full path to the file
   // where the value will be stored
   String fullPath = appdir + "\\" + thisFileName;


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.


// Write the object to a file
try {
   FileOutputStream fileout = new FileOutputStream(fullPath);
    ObjectOutputStream objout = new ObjectOutputStream(fileout);
   objout.writeObject(myobj);
}
catch (Exception e) {
  System.out.println("Error while saving field value to file:"
   + e);
}
// end store
}

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.


public void load(IProcessInstance pi) throws Exception
{
   // Get the name of the file where the value is stored.
   // The file name is saved as the entity key.
   // An example is thisfield123.txt
   String thisFileName = (String) pi.getEntityKey(getName());

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.


if (thisFileName != null)
{
   try {
      // getMyApplicationsPath is a user-defined function
      // that returns the path to the dir for the application
      String myPath = getMyApplicationsPath();

      // Get the full path to the file in the Applications dir
      // eg rootdir\Applications\myApp\thisfield123.html
      thisFileName = myPath + "\\" + thisFileName;

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.


// Get a file reader and read in the object
FileInputStream filein = new FileInputStream(thisFileName);
ObjectInputStream objectin = new ObjectInputStream(filein);
myObject newobj = (myObject) objectin.readObject();

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()

This method returns the directory where the current application resides.


// Returns the path to the folder where the application is saved
String getMyApplicationsPath ()
{   String path = "";
    try {
       path = getPMApplication().getHomePath();
    }
    catch (Exception e) {
       System.out.println("Exception while getting app path"
         + e);
    }
return path;
}

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.


// Fetch the set of menu options from the XML file
public Vector fetchDataFromXML()
{
   Vector optionNames = new Vector();

   try {
      // Get the path for the xml file
      // myFileName is a global variable
      // It is the same for all process instances
      String Path = getMyApplicationsPath();
      Path = Path + "\\" + myFileName;

Next, the method reads the file into a string.


// Get a file reader
java.io.File f = new java.io.File(Path);
FileReader fr = new FileReader(f);
BufferedReader in = new BufferedReader(fr);

// Create variables in preparation for reading the file
int MAX_LENGTH = 2000;
char xml[] = new char[MAX_LENGTH];

// Read the entire xml file into the array xml
int count =0;
count = in.read(xml, count, MAX_LENGTH);

// Create a string of the content and get its length
String charSet = new String(xml);
int charSetLength = charSet.length();

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.


   count = 0;
   for(; count < charSetLength; count++)
   {
    parseForItemTag(count, charSetLength, charSet, optionNames);
   }
// end try
}
catch(Exception e){
   System.out.println("Error while getting data from xml file: "
      + e);
   }

// return the vector of option names
return optionNames;
}

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.


/// This method parses an array of characters
// to extract the items embedded in <ITEM>...</ITEM> tags
public void parseForItemTag (int count, int charSetLength,
   String charSet, Vector optionNames)
{
   String temp;
   Object tempobj;
   // Looking for "<" character
   if(charSet.charAt(count) == '<' )
   {
      // Read characters between "<" and ">" into temp string
      temp = "";
      for(; charSet.charAt(count) != '>'; count++)
      {
         temp = temp + charSet.charAt(count);
      }
      temp = temp + charSet.charAt(count);
      count++;
      // Check if the temp string is <ITEM>
      if(temp.equalsIgnoreCase("<ITEM>"))
      
      // if so, empty out temp and then read
      // the characters between ">" and "<" into temp
      {
      for (temp = ""; charSet.charAt(count) != '<' ;
            temp = temp + charSet.charAt(count++))
      // We now have an item
      // Convert the string temp to an object and
      // add the object to the vector of options
      tempobj = (Object) temp;
      optionNames.addElement(tempobj);
      }
   }
// end of method
}

Complete Source Code

For the complete source code, click the following links:

The Custom Activity

This section discusses the custom data field and has the following subsections:

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:


<xml version="1.0" encoding="us-ascii">
   <DEPT>Engineering</DEPT>
   <DAY>monday</DAY>
   <DEPT>Marketing</DEPT>
   <DAY>tuesday</DAY>
   <DEPT>Human Resource</DEPT>
   <DAY>wednesday</DAY>
   <DEPT>Sales</DEPT>
   <DAY>thursday</DAY>

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

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.


<?xml version = "1.0" ?>
<WORKPERFORMER TYPE="com.netscape.pm.model.ISimpleWorkPerformer"
   NAME="EmployeeTrainingPerformer"
CLASS_ID="customer.activities.EmployeeTrainingPerformer"
   VERSION="1.1">
<ENVIRONMENT>
</ENVIRONMENT>

<INPUT>
   <PARAMETER NAME="Emp_Name" DESCRIPTION="Employee Name">
      getData("dfEmpName")
   </PARAMETER>

   <PARAMETER NAME="Dept" DESCRIPTION="Dept. Name">
      getData("dfDeptName")
   </PARAMETER>

   <PARAMETER NAME="Start_Date" DESCRIPTION="Start Date">
      getData("dfStartDate")
   </PARAMETER>
</INPUT>

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.


// The perform() method defines what the custom activity does.

public void perform(Hashtable input, Hashtable output)
{

// Get the employee's start date, name and department
// from the input hashtable.
Date startDate = (java.sql.Date)input.get("Start_Date");
String dept = (String) input.get( "Dept" );
String empName = (String) input.get( "Emp_Name" );

// Get the application path from the input hashtable
String appPath = (String)input.get("path");

// Get the process instance id from the input hashtable
int thisID = ((Double)input.get("id")).intValue();

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()

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.


for(; count < charSetLength; count++)
{
   if(charSet.charAt(count) == '<' )
   {
      temp = "";
      for(; charSet.charAt(count) != '>'; count++)
      { temp = temp + charSet.charAt(count);
      }
      temp = temp + charSet.charAt(count);
      count++;

      // When temp = <DEPT>, find the name of the department
      if(temp.equalsIgnoreCase("<DEPT>"))
      {
         for(dept = ""; charSet.charAt(count) != '<' ;
            dept = dept + charSet.charAt(count++));
      }

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.


   // Now we know the current DEPT. Find the day.
   if(temp.equalsIgnoreCase("<DAY>"))
   {
      for(day = ""; charSet.charAt(count) != '<' ;
         day = day + charSet.charAt(count++));
      
      trainingDays.put(dept, day);
   }
  }
 }
// end of function
}

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.


public Date scheduleTraining (String startDate, String dept,
   Hashtable trainingDays)
{
   // Get info about the start date
   date = new Date(startDate);
   int thisDay = date.getDay();
   int dayOfMonth = date.getDate();
   int month = date.getMonth();
   int year = date.getYear();

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.


// Using the dept as the key, get the value of the
// training day from the the trainingDays hashtable
if(((String)trainingDays.get(dept)).equals("monday") ){
   dayOfMonth=IncrementForMonday(thisDay, dayOfMonth);
   }
else if(((String)trainingDays.get(dept)).equals("tuesday") ){
   dayOfMonth=IncrementForTuesday(thisDay, dayOfMonth);
   }
else if(((String)trainingDays.get(dept)).equals("wednesday") ){
   dayOfMonth=IncrementForWednesday(thisDay, dayOfMonth);
   }
else if(((String)trainingDays.get(dept)).equals("thursday") ){
   dayOfMonth=IncrementForThursday(thisDay, dayOfMonth);
   }
else if(((String)trainingDays.get(dept)).equals("friday") ){
   dayOfMonth=IncrementForFriday(thisDay, dayOfMonth);
   }
if(((String)trainingDays.get(dept)).equals("saturday") ){
   dayOfMonth=IncrementForSaturday(thisDay, dayOfMonth);
   }
else if(((String)trainingDays.get(dept)).equals("sunday") ){
   dayOfMonth=IncrementForSunday(thisDay, dayOfMonth);
}
Date trainingDate = new Date(year, month, dayOfMonth);
return trainingDate;
}

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.


// helper functions to find training date
private int IncrementForMonday(int thisDay, int dayOfMonth ){
if(thisDay == SUN)
   // for Monday increment 1 from Sunday
   dayOfMonth = dayOfMonth+1;
if(thisDay == TUE)
   // for Monday increment 6 from Tue
   dayOfMonth = dayOfMonth+6;
if(thisDay == WED)
   // for Monday increment 5 from Wed
   dayOfMonth = dayOfMonth+5;
if(thisDay == THU)
   // for Monday increment 4 from Thursday
   dayOfMonth = dayOfMonth+4;
if(thisDay == FRI)
   // for Monday increment 3 from Friday
   dayOfMonth = dayOfMonth+3;
if(thisDay == SAT)
   // for Monday increment 2 from Saturday
dayOfMonth = dayOfMonth+2;

return dayOfMonth;
}

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.




public String writeWelcomePage(String employeeName, int thisID,
   String appPath, Date trainingDate)
{
   // Format the date string to remove "00:00:00 PDT/PST"
   String finalDate = formatDateString(trainingDate);

   // File name is Employee name + ProcessInstance
   String fileName = employeeName + thisID + ".html";

   // Remove all white spaces from the filename
   // URLS cannot have white spaces
   fileName = fileName.replace(' ', '_');

   // Get the pathname to the file in the Application's folder
   String thisPath = appPath + fileName;

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.


// Make a file in this Application's folder
try {
   RandomAccessFile HTMLfile = new RandomAccessFile (
      thisPath, "rw");

   HTMLfile.writeUTF("<HTML><HEAD>");
   HTMLfile.writeUTF("<TITLE>New Employee Training</TITLE>");
   HTMLfile.writeUTF("</HEAD>");
   HTMLfile.writeUTF("<BODY>");
   HTMLfile.writeUTF("<CENTER>");
   HTMLfile.writeUTF(<H1><FONT COLOR=MAGENTA>Hello <I> ");
   HTMLfile.writeUTF(employeeName);
   HTMLfile.writeUTF("</I></FONT></H1></CENTER>");
   HTMLfile.writeUTF("<H3>Welcome to our company. </H3>");
   HTMLfile.writeUTF("<P> Please attend new employee ");
   HTMLfile.writeUTF("orientation training on ");
   HTMLfile.writeUTF("<I>" + finalDate + " at 2 pm.</I>");
   HTMLfile.writeUTF("in Room B3 above the cafeteria.</P>");
   HTMLfile.writeUTF("<P>We'll have a tee-shirt and cap and ");
   HTMLfile.writeUTF("other corporate goodies for you");
   HTMLfile.writeUTF("at the training!</P>");
   HTMLfile.writeUTF("</BODY>");
   HTMLfile.writeUTF("</HTML>");
   HTMLfile.close();
}

Complete Source Code

For the complete source code, click the following links:


Previous      Contents     Index      Next     
Copyright 2002 Sun Microsystems, Inc. All rights reserved.


816-6353-10