Java User's Guide for STAF Version 3

Last Updated: June 25, 2006


Table of Contents

1.0 Introduction

2.0 Installation

3.0 STAF Java APIs

3.1 Class STAFHandle
3.2 Class STAFException
3.3 Class STAFResult
3.4 Class STAFMapClassDefinition
3.5 Class STAFMarshallingContext 3.5.1 Static Method isMarshalledData
3.5.2 Static Method marshall
3.5.3 Static Method unmarshall
3.5.4 Static Method formatObject
3.6 Class STAFQueueMessage
3.7 Class STAFUtil 3.7.1 Static Method wrapData
3.7.2 Static Method unwrapData
3.7.3 Static Method stripPortFromEndpoint
3.7.4 Static Method validateTrust
3.7.5 Static Method resolveRequestVar
3.7.6 Static Method resolveRequestVarAndCheckInt
3.7.7 Static Method resolveInitVar
3.7.8 Static Method resolveInitVarAndCheckInt
3.7.9 Static Method compareSTAFVersion
3.7.10 Static Method addPrivacyDelimiters
3.7.11 Static Method escapePrivacyDelimiters
3.7.12 Static Method removePrivacyDelimiters
3.7.13 Static Method maskPrivateData
3.8 Class STAFVersion
3.9 Class STAFLog
3.10 Class STAFMonitor
3.11 Class STAFLogViewer

4.0 Java Samples

4.1 Java Sample 1
4.2 Java Sample 2


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.


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.

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.


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 Class STAFHandle

The STAFHandle class is used to register, unregister, and submit service requests to STAF. Each Java application should create one and only one STAFHandle object. The act of creating this object registers the Java application with STAF using the name passed to the constructor. Once this is done, service requests may be submitted by one of two methods:

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


3.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.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. It is typically used in places where you wish to avoid catching exceptions when using STAF. This class also contains the constant definitions for all the STAF return codes. These return codes are common to STAFResult and STAFException.

Definition

Examples

The following example shows the use of the STAFResult class in submitting a request to a STAF service.

3.4 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.5 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.5.1 Static Method isMarshalledData

Definition

Examples


3.5.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.5.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.5.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.6 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.7 Class STAFUtil

The STAFUtil class contains the following static functions that are general utility functions:


3.7.1 Static Method 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.7.2 Static Method unwrapData

Description

Definition

Examples


3.7.3 Static Method stripPortFromEndpoint

Description

Definition

Examples


3.7.4 Static Method validateTrust

Description

Definition

Examples


3.7.5 Static Method resolveRequestVar

Description

Definition

Examples


3.7.6 Static Method resolveRequestVarAndCheckInt

Description

Definition

Examples


3.7.7 Static Method resolveInitVar

Description

Definition

Examples


3.7.8 Static Method resolveInitVarAndCheckInt

Description

Definition

Examples


3.7.9 Static Method 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.7.10 Static Method 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.7.11 Static Method 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.7.12 Static Method removePrivacyDelimiters

Description

Definition

Examples

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

3.7.13 Static Method 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.8 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.9 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.10 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.11 Class STAFLogViewer

The STAFLogViewer class provides a Java GUI that can display any STAF log. It can be accessed via the command line or via another Java program.

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 parameters:

  -machine 
  -serviceName 
  -queryRequest 
  -levelMask 
  -fontName 
  -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:

    public STAFLogViewer(Component parent,
                         STAFHandle handle,
                         String queryRequest)

    public STAFLogViewer(Component parent,
                         STAFHandle handle,
                         String machine,
                         String queryRequest

    public STAFLogViewer(Component parent,
                         STAFHandle handle,
                         String machine,
                         String serviceName,
                         String queryRequest)

    public STAFLogViewer(Component parent,
                         STAFHandle handle,
                         String machine,
                         String serviceName,
                         String queryRequest,
                         String levelMask)

    public STAFLogViewer(Component parent,
                         STAFHandle handle,
                         String machine,
                         String serviceName,
                         String queryRequest,
                         String levelMask,
                         String fontName)

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"

STAFLogViewer

The STAFLogViewer menu bar provides the following menus:

Examples


4.0 Java Samples

4.1 Java Sample 1

This Java sample 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 Common Public License (CPL) 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 Java Sample 2

This Java sample 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 Common Public License (CPL) 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: 20050516-17:08:44
Message  : Loop #0


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

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

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

*** End of Document ***