Java User's Guide for STAF Version 3

Last Updated: June 27, 2014


Table of Contents

1.0 Introduction

2.0 Installation

3.0 STAF Java APIs

3.1 Primary STAF APIs 3.1.1 Class STAFHandle
3.1.2 Class STAFException
3.1.3 Class STAFResult

3.2 Marshalling APIs 3.2.1 Class STAFMapClassDefinition
3.2.2 Class STAFMarshallingContext 3.2.2.1 Static Method isMarshalledData
3.2.2.2 Static Method marshall
3.2.2.3 Static Method unmarshall
3.2.2.4 Static Method formatObject

3.3 Private Data Manipulation APIs 3.3.1 Static Method STAFUtil.addPrivacyDelimiters
3.3.2 Static Method STAFUtil.escapePrivacyDelimiters
3.3.3 Static Method STAFUtil.removePrivacyDelimiters
3.3.4 Static Method STAFUtil.maskPrivateData

3.4 General Utility APIs 3.4.1 Static Method STAFUtil.wrapData
3.4.2 Static Method STAFUtil.unwrapData
3.4.3 Static Method STAFUtil.stripPortFromEndpoint
3.4.4 Static Method STAFUtil.validateTrust
3.4.5 Static Method STAFUtil.convertDurationString
3.4.6 Static Method STAFUtil.convertSizeString
3.4.7 Static Method STAFUtil.resolveRequestVar
3.4.8 Static Method STAFUtil.resolveRequestVarAndCheckInt
3.4.9 Static Method STAFUtil.resolveRequestVarAndConvertDuration
3.4.10 Static Method STAFUtil.resolveRequestVarAndConvertSize
3.4.11 Static Method STAFUtil.resolveInitVar
3.4.12 Static Method STAFUtil.resolveInitVarAndCheckInt
3.4.13 Static Method STAFUtil.compareSTAFVersion
3.4.14 Class STAFVersion
3.4.15 Class STAFQueueMessage

3.5 Wrappers for Log and Monitor Services' LOG Command 3.5.1 Class STAFLog
3.5.2 Class STAFMonitor

3.6 Log Viewer / Formatter APIs 3.6.1 Class STAFLogViewer
3.6.2 Class STAFJVMLogViewer
3.6.3 Class STAFLogFormatter

4.0 Java Program Examples

4.1 Example 1
4.2 Example 2
5.0 How to Test STAF Java Support 5.1 Class TestJSTAF


1.0 Introduction

This document describes STAF's V3 support for the Java language.  It includes information on the core STAF Java APIs as well as the wrappers provided for the Monitor and Log services.

STAF Java support must be installed in order to submit requests to STAF via a Java program or to register a STAF Java service such as STAX, Event, Cron, EventManager, Email, etc.


2.0 Installation

To install STAF's Java support, select to install "Java support" during the install. It is installed by default for a "typical" install of STAF by all STAF installer files except for the STAF FreeBSD 4.10 installer file which does not provide Java support.

STAF's Java support is provided in the JSTAF.jar file (located in either C:\STAF\bin\JSTAF.jar (by default) on Windows systems or /usr/local/staf/lib/JSTAF.jar (by default) on Unix systems. The STAF install adds the JSTAF.jar file to the CLASSPATH environment variable.

To verify that the version of Java you are using works with STAF Java support, run TestJSTAF as decribed in section 5.0 How to Test STAF Java Support.


3.0 STAF Java APIs

STAF externalizes the following primary classes to Java applications. These classes are:

These classes all reside in the com.ibm.staf package. In order to use them in a Java application, you must import the STAF package like so

import com.ibm.staf.*;

STAF externalizes two wrapper classes. These classes are

These classes all reside in the com.ibm.staf.wrapper package. In order to use them in a Java application, you must import the STAF wrapper package like so

import com.ibm.staf.wrapper.*;

3.1 Primary STAF APIs

These APIs allow you to register/unregister with STAF and submit STAF service requests.

3.1.1 Class STAFHandle

The STAFHandle class is the primary class used to communicate with STAF. It is used to register with STAF, submit service requests to STAF, and unregister with STAF. Each Java application should generally create one and only one STAFHandle object. The act of creating this object registers the Java application with STAF.

There are two constructors for the STAFHandle class:

Once you have a valid STAFHandle instance object, you can begin submitting requests to STAF services by one of two methods:

Note that a STAFHandle instance object has a auto-unmarshall result member variable that defaults to true when a STAFHandle instance object is created, but can be set to false via its setDoUnmarshallResult() method. When set to true, this causes STAF results to be automatically unmarshalled when using the submit2() method.

Before the Java application exits, it should unregister with STAF by calling the unRegister() method.

STAFHandle also defines the following constants which can be used as the syncOption parameter for the submit() and submit2() methods:

Definition

Examples

  1. This is an example of creating a new STAFHandle and using the submit2() method to submit some simple requests to STAF.

  2. This is an example of creating a new STAFHandle and using the submit() method (which throws a STAFException if am error in encountered) to submit requests to STAF.

  3. This is an example of creating a new static STAFHandle and using the static STAFHandle to submit requests to STAF.

  4. This is an example of creating a new STAFHandle and using the submit2() method to submit requests to STAF. Note that since auto-unmarshalling is enabled by default when creating a new STAFHandle, the STAFResult object returned by the submit2() method will contain the result's marshalling context and root object so that you don't have to call the unmarshall() method to unmarshall results that contain multiple values.

3.1.2 Class STAFException

The STAFException class is the exception class thrown by the STAFHandle class. It contains an rc variable which contains the actual return code from STAF. You may use the standard Throwable method getMessage() to retrieve any extra information provided by STAF.

Definition

Examples

The following example shows how to deal with a STAFException when registering with STAF.

3.1.3 Class STAFResult

The STAFResult class is returned by the STAFHandle.submit2() method. It contains both the STAF return code as well as the result string. In addition, if auto-unmarshalling is enabled for the handle (which it is by default), the STAFResult object also contains the marshalling context for the result (e.g. the unmarshalled result) and the result object (e.g. the root object of the marshalling context). Otherwise, if auto-unmarshalling is disabled for the handle that called the submit2() method, the resultContext and resultObj fields will be set to null. It is typically used in places where you wish to avoid catching exceptions when using STAF or where you want the result to be auto-unmarshalled. This class also contains the constant definitions for all the STAF return codes. These return codes are common to STAFResult and STAFException.

Definition

Examples

  1. The following example shows the use of the STAFResult class when submitting a request to a STAF service that returns a single string result.

  2. The following example shows the use of the STAFResult class when submitting a request to a STAF service that returns a marshalled result string.

3.2 Marshalling APIs

These APIs allow you to define, manipulate, and (un)marshall data structures, and print marshalled data in human-readable ("pretty" print) format.

STAF supports the automatic marshalling and unmarshalling of structured data. The act of marshalling takes a data structure and converts it into a string-based representation. The act of unmarshalling reverses this and converts the string-based representation back into a data structure. See Section 6.1, "Marshalling Structured Data" in the STAF User's Guide for more information.

3.2.1 Class STAFMapClassDefinition

The STAFMapClassDefinition class provides the metadata associated with a map class. In particular, it defines the keys associated with the map class. This class is used to create and/or access a STAF map class definition which can be useful if you want to generate a STAF marshalling context with map classes. The map class definition is used to reduce the size of a marshalling map class in comparison to a map containing the same data. It also contains information about how to display instances of the map class, such as the order in which to display the keys and the display names to use for the keys. You get and set map class definitions using the STAFMarshallingContext class setMapClassDefinition and getMapClassDefinition functions.

When constructing a new STAFMapClassDefinition object, the required argument name specifies the name of the STAF map class definition.

STAFMapClassDefinition defines the following methods:

Definition

Examples

This example shows how to create a marshalling context containing one map class definition and a map as the root object and how to create a string of marshalled data representing this marshalling context. The output from running this example would be:

3.2.2 Class STAFMarshallingContext

The STAFMarshallingContext class is used to create and/or access a STAF marshalling context which is used by STAF to help in marshalling and unmarshalling data. A marshalling context is simply a container for map class definitions and a data structure that uses (or is defined in terms of) them.

In order to use a map class when marshalling data, you must add the map class definition to the marshalling context, set the root object of the marshalling context to the object you want to marshall, and then marshall the marshalling context itself. When you unmarshall a data structure, you will always receive a marshalling context. Any map class definitions referenced by map classes within the data structure will be present in the marshalling context.

The primary use of this class is to represent multi-valued results that consist of a data structure (e.g. results from a QUERY/LIST service request, etc.) as a string that can also be converted back into the data structure. This string can be assigned to the string result buffer returned from the service request.

When constructing a new STAFMarshalling class object, the optional argument obj specifies the root object to be marshalled. The default is null.

STAFMarshallingContext defines the following methods:

The STAFMarshallingContex class defines following static methods

More information on these static methods are provided later in this section.

Definition

Examples

This example shows how to create a marshalling context containing one map class definition and a map as the root object and how to create a string of marshalled data representing this marshalling context. The output from running this example would be:

3.2.2.1 Static Method isMarshalledData

Definition

Examples


3.2.2.2 Static Method marshall

Definition

Examples

This example shows how to marshall data without a marshalling context object. If you have a marshalling context object, then you'll probably just want to use the non-static marshall() method instead to marshall data (e.g. String result = mc.marshall();). The output from running this example would be:

3.2.2.3 Static Method unmarshall

Definition

Examples

  1. This example shows how to unmarshall the result from a "LIST DIRECTORY" request to the FS service which returns a marshalled list of strings. It then checks if an entry named "bin" exists in the directory list.

    Here is the STAF request that this example executes and its result as shown when run using the STAF executable which "pretty prints" the result.

    Here is a Java program that shows how to submit this STAF request and unmarshall its result: The output from running this example could be:

  2. This example shows how to unmarshall the result from a STAF request to the PROCESS service specifying the WAIT option and the RETURNSTDOUT option. The result buffer for this request will contain a marshalled <Map:STAF/Service/Process/CompletionInfo> which represents the completion information for the process, including the return code from the process, the key (if one was specified with the NOTIFY ONEND option), as well as any files specified by RETURNSTDOUT, RETURNSTDERR, and/or RETURNFILE.

    Here is the STAF request that this example executes and its result as shown when run using the STAF executable which "pretty prints" the result.

    Here is a Java program that shows how to submit this STAF request and unmarshall its result: The output from running this example could be:

3.2.2.4 Static Method formatObject

Definition

Examples

This example prints the result from a FS QUERY ENTRY request in a "pretty" verbose format: If successful, this could result in the following output printed:

3.3 Private Data Manipulation APIs

These APIs allow you to handle private data. These APIs are all static methods in the STAFUtil class:

See Section 7.3, "Private Data" in the STAF User's Guide for more information about handling private data.

3.3.1 Static Method STAFUtil.addPrivacyDelimiters

Description

Definition

Examples

  1. Here's an example of adding privacy delimiters to a password specified for the PASSWORD option when starting a process as another user.
  2. Here's an example of specifying adding privacy delimiters to a password used in the COMMAND option when starting a process.

3.3.2 Static Method STAFUtil.escapePrivacyDelimiters

Description

Definition

Examples

Here's an example of escaping privacy delimiters in password 'passw@!!d' before adding privacy delimiters to it and then uses the password in the PASSWORD option when starting a process as another user.

3.3.3 Static Method STAFUtil.removePrivacyDelimiters

Description

Definition

Examples

Here's an example of removing privacy delimiters from protected password "!!@secret@!!" and assigns "secret" as the password.

3.3.4 Static Method STAFUtil.maskPrivateData

Description

Definition

Examples

Here's an example of masking any private data indicated by privacy delimiters in a request string before displaying it. This example prints:
START COMMAND C:/tests/TestA.exe USERNAME Test1 PASSWORD **************

3.4 General Utility APIs

These are general utility APIs that you may find useful when writing test cases in Java or when writing a Java service.

The general utility APIs that are static functions in the STAFUtil class are:

Other general utility APIs are:


3.4.1 Static Method STAFUtil.wrapData

Description

Definition

Examples

Instead of enclosing an option value that contains spaces in double quotes (like you might do when using the STAF executable to submit a request from the command line), in a Java program use the STAFUtil.wrapData() method to wrap a value. For example:

3.4.2 Static Method STAFUtil.unwrapData

Description

Definition

Examples


3.4.3 Static Method STAFUtil.stripPortFromEndpoint

Description

Definition

Examples


3.4.4 Static Method STAFUtil.validateTrust

Description

Definition

Examples


3.4.5 Static Method STAFUtil.convertDurationString

Description

Definition

Examples


3.4.6 Static Method STAFUtil.convertSizeString

Description

Definition

Examples


3.4.7 Static Method STAFUtil.resolveRequestVar

Description

Definition

Examples


3.4.8 Static Method STAFUtil.resolveRequestVarAndCheckInt

Description

Definition

Examples


3.4.9 Static Method STAFUtil.resolveRequestVarAndConvertDuration

Description

Definition

Examples


3.4.10 Static Method STAFUtil.resolveRequestVarAndConvertSize

Description

Definition

Examples


3.4.11 Static Method STAFUtil.resolveInitVar

Description

Definition

Examples


3.4.12 Static Method STAFUtil.resolveInitVarAndCheckInt

Description

Definition

Examples


3.4.13 Static Method STAFUtil.compareSTAFVersion

Description

Definition

Examples

  1. Here's an example of a STAF Java service that uses this method to verify that the version of STAF required by this service is running.

  2. Here's another example of verifying that the version of the STAX service running on machine "server1" is at least version 3.1. For example:

3.4.14 Class STAFVersion

Definition

The STAFVersion class allows you to compare STAF versions. This class is useful if you want to verify that a STAF version or a version of a STAF service is at a particular level of STAF.

When constructing a new STAFVersion object, the required argument version is a string containing the STAF version. A STAF version must be of the following format unless it's blank or "", which equates to "no version" and is internally represented as 0.0.0.0:

  a[.b[.c[.d]]] [text]
where:

A NumberFormatException is thrown if a non-numeric value is specified in a, b, c, or d.

Since: STAF V3.1.0

STAFVersion defines the following methods:

Examples

Suppose you already had the STAF version that you wanted to compare in a String variable named versionStr and you wanted to make sure that it was at version 3.1.0 or higher. You could check this as follows:

3.4.15 Class STAFQueueMessage

The STAFQueueMessage class provides a wrapper around messages received via the STAF Queue service. It takes the received string as input and unmarshalls it and breaks it into its constituent parts.

Definition

Examples

The following example shows how to wait for a message to be queued (by submitting a GET WAIT request to the QUEUE service) and to use the STAFQueueMessage class to receive the marshalled queue message string as input and to unmarshall it and break it into separate fields including the queued message itself and its priority, timestamp, type, etc. If the above example is run and the following command is submitted when requested: the result could look like the following:

3.5 Wrapper APIs for Log and Monitor Services' LOG Command

These APIs are wrappers around the following LOG commands which can make it simple to submit LOG requests to the LOG and MONITOR services:

3.5.1 Class STAFLog

The STAFLog class provides a wrapper around the LOG command of the LOG service. It provides constants for the log type and log levels. It has instance and static methods for logging. The STAFLog class also interfaces with the MONITOR service. You may provide the STAFLog class a monitor mask. For the levels set in the monitor mask, STAFLog will log the message via the LOG service and then log the message via the MONITOR service. STAFLog will also log an error message to the MONITOR service, if it should receive an error while trying to log a message.

Definition

Examples


3.5.2 Class STAFMonitor

The STAFMonitor class provides a wrapper around the LOG command of the MONITOR service. It has instance and static methods for logging messages to the MONITOR service.

Definition

Examples

3.6 Log Viewer / Formatter APIs

These APIs are Java GUI classes that allow you to:

3.6.1 Class STAFLogViewer

Description

The STAFLogViewer class provides a Java GUI that can display any STAF log on any machine currently running STAF. A STAF log is a binary log file that has been created by the STAF Log service. This Java class submits requests to STAF, so STAF has to be running. This Java class can be run as an application via the command line or can be run via another Java program.

Note that the STAX Monitor Java application uses the STAFLogViewer class to display the STAX job logs and the STAX service log.

Since: STAF V3.1.0

Definition

To execute and get help from the STAFLogViewer class from the command line, specify the following:

java com.ibm.staf.STAFLogViewer -help

The STAFLogViewer class accepts the following command line options:

  -queryRequest <LOG QUERY Request>
  -machine <Log Service Machine Name>
  -serviceName <Log Service Name>
  -levelMask <LEVELMASK option>
  -fontName <Font Name>
  -saveAsDirectory <Directory Name>
  -help
  -version
You must specify -queryRequest or -help or -version.

You may also call the STAFLogViewer class from a Java application. The following constructors for STAFLogViewer are provided:

Here is an example of the Java GUI that is displayed for the following command:

java com.ibm.staf.STAFLogViewer -machine staf1f.austin.ibm.com -queryRequest "QUERY machine {STAF/Config/MachineNickname} logname email all"

STAFLogViewer

The STAFLogViewer's menu bar provides the following menus:

Examples

3.6.2 Class STAFJVMLogViewer

Description

The STAFJVMLogViewer class provides a Java GUI that can display a JVM Log for any STAF Java service that is currently registered. Each Java service that is registered with STAF runs in a JVM (Java Virtual Machine). A JVM Log is a text log file that is asociated with each JVM created by STAF. Note that more than one Java service may use the same JVM (and thus share the same JVM Log file) depending on the options used when registering the service. Section 4.4 Service Registration in the STAF User's Guide provides more information on registering STAF Java services using the JSTAF library.

A JVM Log file contains JVM start information such as the date/time when the JVM was created, the JVM executable, and the J2 options used to start the JVM. It also any other information logged by the JVM. This includes any errors that may have occurred while the JVM was running and any debug information output by a Java service. Also, the JVM Log for the STAX service contains the output from any print statements that are used within a <script> element in a STAX xml job file which is useful when debugging Python code contained in a <script> element. When a problem occurs with a STAF Java service, you should always check it's JVM Log as it may contain information to help debug the problem.

STAF stores JVM Log files in the {STAF/DataDir}/lang/java/jvm/<JVMName> directory. STAF retains a configurable number of JVM Logs (five by default) for each JVM. The current JVM log file is named JVMLog.1 and older saved JVM log files, if any, are named JVMLog.2 to JVMLog.<MAXLOGS>. When a JVM is started, if the size of the JVMLog.1 file exceeds the maximum configurable size (1M by default), the JVMLog.1 file is copied to JVMLog.2 and so on for any older JVM Logs, and a new JVMLog.1 file will be created.

When using the STAFJVMLogViewer, you can specify the machine where the STAF JVM log resides (e.g. where the Java service is registered) and you can specify/select the name of the STAF service whose JVM Log you want to display. This Java class submits requests to STAF, so STAF has to be running. This Java class can be run as an application via the command line or can be run via another Java program.

Note that the STAX Monitor Java application uses the STAFJVMLogViewer class to display the JVM log for the STAX service and for other services.

Since: STAF V3.2.1

Definition

To execute and get help for the STAFJVMLogViewer class from the command line, specify the following:

The STAFJVMLogViewer class accepts the following command line options:

  -machine <Machine where the STAF Java service is registered>
  -serviceName <Java Service Name>
  -displayAll
  -fontName <Font Name>
  -help
  -version

All of the options are optional. If specifying the -help or -version option, this option must be the first (and only) option specified.

You may also call the STAFJVMLogViewer class from a Java application. The following constructors for STAFJVMLogViewer are provided:

Here is an example of the Java dialogs that are displayed for the following command:

If you don't specify the -service <Java Service Name> option, the following dialog is displayed which shows a list of Java services currently registered on machine staf1a.

STAFJVMLogViewer 1

Click on the drop-down list to see all of the Java services registered on this machine. Select a Java service, and then select the OK button to display the JVM Log for this Java service.

Here is an example of the dialog that is shown when the JVM Log is displayed.

STAFJVMLogViewer 2

The STAFJVMLogViewer's menu bar provides the following menus:

Examples

3.6.3 Class STAFLogFormatter

Description

The STAFLogFormatter class allows you to format a STAF log (which is a binary file that has been created by the STAF Log service) as html or text.

This Java class can be run as an application via the command line or can be run via another Java program. When run as an application, it submits the specified Log query request to query a STAF log on any machine currently running STAF and then formats the output as either html or text. Or, when run via a Java program that has already submitted a LOG QUERY request, you can use the STAFLogFormatter class to format the log query result as either html or text. You can specify various options including whether you want the formatted output written to a file.

Two format types are supported:

Note that the STAFLogViewer class uses the STAFLogFormatter class when you select File->Save As Text... or File->Save As Html....

Since: STAF V3.3.2

Definition (when run as an application)

To execute and get help from the STAFLogFormatter class from the command line, specify the following:

java com.ibm.staf.STAFLogFormatter -help

The STAFLogFormatter class accepts the following command line options:

  -queryRequest <LOG QUERY Request>
  -fileName <File Name>
  -type <html | text>
  -fontName <Font Name>
  -title <Title>
  -machine <Log Service Machine Name>
  -serviceName <Log Service Name>
  -help
  -version
You must specify one of the following options: -queryRequest or -help or -version. If specifying the -help or -version option, it must be the first and only option specified. All of the other options require the -queryRequest option to be specified.

Here's a description of all of the options:

Definition (when constructed and used from a Java application)

When constructing a new STAFLogFormatter object, the required argument context must be a STAFMarshallingContext object containing a LOG QUERY result's marshalling context. >A STAFException is thrown if an invalid STAFMarshallingContext object is specified.

Class STAFLogFormatter defines the following methods:

Examples


4.0 Java Program Examples

4.1 Example 1

This Java example program is a multi-threaded STAF PING test. The syntax to run this program is:
C:\>java JPing

Usage: java JPing  [# Threads] [# Loops per thread] [Display Modulus]

Defaults:

  # Threads          = 5
  # Loops per thread = 10000
  Display Modulus    = 250

Examples:

java JPing local
java JPing SomeServer 3 1000 100
For each thread specified by the "# Threads" parameter), this program submits a PING request to the PING service to ping the machine specified by the "Where" parameter, repeating the request the number of times specified by the "# Loops per thread" parameter. A status message is displayed each time a number of loops have completed based on the "Display Modulus" parameter. When complete, an average number of pings per seconds is printed.
/*****************************************************************************/
/* Software Testing Automation Framework (STAF)                              */
/* (C) Copyright IBM Corp. 2001                                              */
/*                                                                           */
/* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
/*****************************************************************************/

//===========================================================================
// JPing - A multi-threaded STAF PING test
//===========================================================================
// Accepts: Where to PING
//          Optionally, the number of threads to use (default = 5)
//          Optionally, the number of loops per thread (default = 10000)
//          Optionally, the display modulus (default = 250)
//
// Returns: 0 , on success
//          >0, if an error is encountered
//===========================================================================
// Date        Who           Comment
// ----------  ------------  ------------------------------------------
// 04/25/1998  C. Rankin     File Created
//===========================================================================

import com.ibm.staf.*;
import java.util.Date;
import java.util.Calendar;
import java.text.DateFormat;

public class JPing implements Runnable
{
    // Constructor

    public JPing(int numLoops, int displayModulus, int myThreadNum)
    {
        loopCount = numLoops;
        modulus = displayModulus;
        threadNum = myThreadNum;
        errors = 0;
    }

    // This is the main command line entry point

    public static void main(String [] argv)
    {
        // Verify the command line arguments

        if ((argv.length < 1) || (argv.length > 4))
        {
            System.out.println();
            System.out.println("Usage: java JPing <Where> [# Threads] " +
                               "[# Loops per thread] [Display Modulus]");
            System.out.println();
            System.out.println("Defaults:");
            System.out.println();
            System.out.println("  # Threads          = 5");
            System.out.println("  # Loops per thread = 10000");
            System.out.println("  Display Modulus    = 250");
            System.out.println();
            System.out.println("Examples:");
            System.out.println();
            System.out.println("java JPing local");
            System.out.println("java JPing SomeServer 3 1000 100");
            System.exit(1);
        }

        // Register with STAF

        try
        {
            handle = new STAFHandle("Java_Ping_Test");
        }
        catch (STAFException e)
        {
            System.out.println("Error registering with STAF, RC: " + e.rc);
            System.exit(1);
        }

        // Initialize variables

        timeFormatter = DateFormat.getTimeInstance(DateFormat.MEDIUM);

        where = argv[0];
        int numThreads = 5;
        int numLoops = 10000;
        int displayModulus = 250;

        if (argv.length > 1) numThreads = Integer.parseInt(argv[1]);
        if (argv.length > 2) numLoops = Integer.parseInt(argv[2]);
        if (argv.length > 3) displayModulus = Integer.parseInt(argv[3]);

        JPing [] pingers = new JPing[numThreads];
        Thread [] threads = new Thread[numThreads];

        System.out.println("(0)" + timeFormatter.format(new Date()) +
                           " - Started");
        long startSecs = (new Date()).getTime();

        // Start the threads

        for(int i = 0; i < numThreads; ++i)
        {
            pingers[i] = new JPing(numLoops, displayModulus, i + 1);
            threads[i] = new Thread(pingers[i]);
            threads[i].start();
        }

        // Wait for all the threads to finish

        for(int i = 0; i < numThreads; ++i)
        {
            try
            {
                threads[i].join();
            }
            catch (Exception e)
            {
                System.out.println("Exception: " + e);
                System.out.println(e.getMessage());
            }
        }

        // Output final pings/sec

        long stopSecs = (new Date()).getTime();
        System.out.println("(0)" + timeFormatter.format(new Date()) +
                           " - Ended");

        System.out.println("Average: " + ((numLoops * numThreads * 1000) /
                           (stopSecs - startSecs)) + " pings/sec");

        // Unregister with STAF

        try
        {
            handle.unRegister();
        }
        catch (STAFException e)
        {
            System.out.println("Error unregistering with STAF, RC: " + e.rc);
            System.exit(1);
        }
    }

    // This is the method called when each thread starts

    public void run()
    {
        for(int i = 1; i <= loopCount; ++i)
        {
            STAFResult result = handle.submit2(where, "PING", "PING");

            // If we get a non-zero return code, or a response of something
            // other than "PONG", display an error

            if (result.rc != 0)
            {
                System.out.println("(" + threadNum + ")" +
                                   timeFormatter.format(new Date()) +
                                   " - Loop #" + i + ", Error #" +
                                   ++errors + ", RC: " + result.rc);
            }
            else if (result.result.compareTo("PONG") != 0)
            {
                System.out.println("(" + threadNum + ")" +
                                   timeFormatter.format(new Date()) +
                                   " - Loop #" + i + ", Error #" +
                                   ++errors + ", RESULT = " + result.result);
            }

            // If we are at our display modulus display a status message

            if ((i % modulus) == 0)
            {
                System.out.println("(" + threadNum + ")" +
                                   timeFormatter.format(new Date()) +
                                   " - Ended Loop #" + i + ", Errors = " +
                                   errors);
            }
        }
    }

    private static STAFHandle handle;
    private static String where;
    private static DateFormat timeFormatter;

    private int loopCount;
    private int modulus;
    private int threadNum;
    private int errors;
}
Sample results could be:
C:\>java JPing local
(0)4:20:49 PM - Started
(1)4:20:50 PM - Ended Loop #250, Errors = 0
(3)4:20:50 PM - Ended Loop #250, Errors = 0
(2)4:20:50 PM - Ended Loop #250, Errors = 0
(5)4:20:50 PM - Ended Loop #250, Errors = 0
(4)4:20:50 PM - Ended Loop #250, Errors = 0
(3)4:20:51 PM - Ended Loop #500, Errors = 0
(1)4:20:51 PM - Ended Loop #500, Errors = 0
(2)4:20:51 PM - Ended Loop #500, Errors = 0
(5)4:20:51 PM - Ended Loop #500, Errors = 0
(4)4:20:51 PM - Ended Loop #500, Errors = 0
(3)4:20:52 PM - Ended Loop #750, Errors = 0
(1)4:20:52 PM - Ended Loop #750, Errors = 0
(2)4:20:52 PM - Ended Loop #750, Errors = 0
(5)4:20:52 PM - Ended Loop #750, Errors = 0
(4)4:20:52 PM - Ended Loop #750, Errors = 0
...

(2)4:21:19 PM - Ended Loop #9500, Errors = 0
(1)4:21:19 PM - Ended Loop #9500, Errors = 0
(3)4:21:19 PM - Ended Loop #9500, Errors = 0
(4)4:21:20 PM - Ended Loop #9500, Errors = 0
(5)4:21:20 PM - Ended Loop #9500, Errors = 0
(2)4:21:20 PM - Ended Loop #9750, Errors = 0
(1)4:21:20 PM - Ended Loop #9750, Errors = 0
(3)4:21:20 PM - Ended Loop #9750, Errors = 0
(4)4:21:20 PM - Ended Loop #9750, Errors = 0
(5)4:21:20 PM - Ended Loop #9750, Errors = 0
(2)4:21:21 PM - Ended Loop #10000, Errors = 0
(1)4:21:21 PM - Ended Loop #10000, Errors = 0
(3)4:21:21 PM - Ended Loop #10000, Errors = 0
(4)4:21:21 PM - Ended Loop #10000, Errors = 0
(5)4:21:21 PM - Ended Loop #10000, Errors = 0
(0)4:21:21 PM - Ended
Average: 1566 pings/sec

C:\>

4.2 Example 2

This Java example program shows how you can use the MONITOR service to log a message to update the status of the test. The syntax to run this program is:
C:\>java com.ibm.staf.service.stax.TestProcess
Usage: java TestProcess loopCount incrementSeconds returnCode
where: This program submits a LOG request to the MONITOR service stating which loop it is currently running. It submits a MONITOR LOG request at the beginning of each loop and then sleeps the specified number of incrementSeconds. When complete, it returns the specified returnCode.
/*****************************************************************************/
/* Software Testing Automation Framework (STAF)                              */
/* (C) Copyright IBM Corp. 2002                                              */
/*                                                                           */
/* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
/*****************************************************************************/

import com.ibm.staf.*;
import java.util.*;

public class TestProcess implements Runnable
{    
    private STAFHandle handle = null;    
    private int counter;
    private int loopCounter;
    private int incrementSeconds;
    private int returnCode;
            
    public static void main(String[] args)
    {
        if (args.length < 3)
        {
            System.out.println("Usage: java TestProcess loopCount" +
                               " incrementSeconds returnCode");
            System.exit(1);
        }
        
        try
        {
            int loopCounter = (new Integer(args[0])).intValue();
            int incrementSeconds = (new Integer(args[1])).intValue();
            int returnCode = (new Integer(args[2])).intValue();
            TestProcess testProcess = new TestProcess(loopCounter,
                                                      incrementSeconds,
                                                      returnCode);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public TestProcess(int loopCounter, int incrementSeconds, 
                       int returnCode)    
    {
        this.loopCounter = loopCounter;
        this.incrementSeconds = incrementSeconds;
        this.returnCode = returnCode;
        this.run();
    }

    public void run()
    {
        try
        {
            // register with STAF
            handle = new STAFHandle("TestProcess");
            System.out.println("STAF handle: " + handle.getHandle());

            STAFResult res = handle.submit2(
                "local", "VAR",
                "RESOLVE STRING {STAF/Config/MachineNickname}");

            if (res.rc != 0)
            {
                System.out.println(
                    "Error resolving {STAF/Config/MachineNickname}." +
                    " RC: " + res.rc + " Result: " + res.result);                
                terminate();
            }

            System.out.println(
                "STAF/Config/MachineNickname: " + res.result);
        }
        catch(STAFException e)
        {
            System.out.println("Error registering with STAF");
            terminate();
        }        
        
        for (int i=0; i < loopCounter; i++)
        {
            STAFResult result = handle.submit2(
                "local", "monitor", "log message " + 
                STAFUtil.wrapData("Loop #" + String.valueOf(i)));

            System.out.println("Loop #" + String.valueOf(i));
           
            try
            {
                Thread.sleep(incrementSeconds * 1000);
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }                    
        }
        
        terminate();
    }      

    public void terminate()
    {
        try
        {
            if (handle != null)
            {                
                handle.submit2("local", "monitor", "log message " +
                               STAFUtil.wrapData("Terminating "));                

                // unregister
                handle.unRegister();
            }
        }
        catch(STAFException e)
        {
            /* do nothing */
        }
        finally
        {
            System.exit(returnCode);
        }
    }
}
Here's an example of running the sample program:
C:\dev\sf\src\staf\test>java TestProcess 3 2 0
STAF handle: 127
STAF/Config/MachineNickname: sharon
Loop #0
Loop #1
Loop #2
C:\>
While this program is running, you can query the MONITOR service to see get the latest message that the TestProcess program logged. For example:
C:\>staf local monitor query machine sharon handle 118
Response
--------
Date-Time: 20140516-17:08:44
Message  : Loop #0


C:\>staf local monitor query machine sharon handle 118
Response
--------
Date-Time: 20140516-17:08:49
Message  : Loop #1

C:\>staf local monitor query machine sharon handle 118
Response
--------
Date-Time: 20140516-17:08:54
Message  : Loop #2

C:\>staf local monitor query machine sharon handle 118
Response
--------
Date-Time: 20140516-17:08:59
Message  : Terminating

5.0 How to Test STAF Java Support

5.1 Class TestJSTAF

Definition

The TestJSTAF class allows you to submit a command-line STAF request using the STAF Java support. This class is useful if you want to verify that the STAF Java support is working correctly, without requiring a GUI display or any modifications to the CLASSPATH.

The syntax of this class is:

Usage: java com.ibm.staf.TestJSTAF <Endpoint | LOCAL> <Service> <Request>

Examples

*** End of Document ***