Listing of Source rappapi/client/TestAPI.java
package client;

import java.io.IOException;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import se.entra.phantom.rapp.RAPPElement;
import se.entra.phantom.rapp.RAPPTransaction;
import se.entra.phantom.rapp.RAPPCallClass;
import se.entra.phantom.rapp.RAPPCallHost;
import se.entra.phantom.rapp.RAPPCallObject;
import se.entra.phantom.rapp.RAPPHostScreen;
import se.entra.phantom.rapp.RAPPHostCell;
import se.entra.phantom.rapp.RAPPHostCells;
import se.entra.phantom.rapp.RAPPGlobVar;
import se.entra.phantom.rapp.RAPPGlobVars;
import se.entra.phantom.rapp.RAPPCallPanel;
import se.entra.phantom.rapp.RAPPLine;
import se.entra.phantom.rapp.RAPPLines;
import se.entra.phantom.rapp.RemoteApplication;
import se.entra.phantom.rapp.RemoteTransaction;

/**
 * This class is used to test the RAPP API with all the available
 * function actions. It also serves as a sample.
 *
 * <p>Run the sample in the "server/samples/rappapi" directory sample as:
 *
 * <pre>
 *   java -classpath bin client.TestAPI hostName:portNumber
 * </pre>
 *
 * This application requires that the application SAMPLES_RAPPAPI
 * is configured as a Web Resource. This web resource should point
 * out the Remote Application RAPPAPI with the host session ID
 * "R" (the modified Tutorial EE application) and an application
 * time-out value of minimum 1 minute.
 */
public class TestAPI
{
  /**
   * The application name to contact in the server.
   */
  private static final String APP_NAME = "SAMPLES_RAPPAPI";
  
  ///
  
  /**
   * The only instance of the application.
   */
  private static TestAPI testAPI;
  
  ///

  /**
   * The instance of this class that allows SSLTestAPI to
   * override creation of a RemoteApplication.
   */
  protected TestAPI()
    {
    // Nothing.
    }
  
  /**
   * Creates the [SSL]RemoteApplication instance.
   */
  protected RemoteApplication createRemoteApplication(String app)
    {
    return new RemoteApplication(app);
    }
  
  /**
   * Creates the [SSL]RemoteApplication instance.
   */
  protected RemoteApplication createRemoteApplication(String app,String sessID)
    {
    return new RemoteApplication(app,sessID);
    }
  
  ///

  /**
   * Starts the application, check for available parameter
   * "hostName:portNumber".
   */
  public static void main(String [] arg)
    {
    main(new TestAPI(),arg);
    }

  /**
   * Starts the application, check for available parameter
   * "hostName:portNumber".
   */
  public static void main(TestAPI api,String [] arg)
    {
    // Save the instance for connection creation.
    testAPI=api;
    
    // Check the arguments.
    if ( arg.length!=1 )
      displaySyntax();

    int d=arg[0].indexOf(':');
    if ( d<0 )
      displaySyntax();

    System.out.println("\nTestAPI, Version 1.0\n--------------------\n");

    String host =arg[0].substring(0,d);
    int port=-1;
    try
      {
      port=Integer.parseInt(arg[0].substring(d+1));
      }
    catch(NumberFormatException e)
      {
      System.out.println("Error: invalid port number");
      displaySyntax();
      }

    // Set static trace mode.
    RemoteApplication.setStaticDebugMode(true);

    try
      {
      // Contact the server.
      RemoteApplication ra=connectFirst(host,port);

      // Get information about the Sign on screen.
      if ( !getSignonScreenInfo(ra) )
        {
        // Probably wrong host ID. Request a close now,
        // wait 5 seconds and exit.
        System.out.println("\nWrong screen, requesting close");
        ra.requestClose();
        try { Thread.sleep(5000L); }
        catch(Exception e) {}
        System.out.println("\nClosing...");
        ra.close();
        return;
        }

      // Manipulate global variables.
      globVar(ra);

      // Call object, disconnect and reconnect.
      ra=logonDisconnectReconnect(ra);

      // Request the entire list of customers.
      requestCustomers(ra);

      // Gets customer data from the CUSTDATA panel.
      getCustomerData(ra);

      // Shows how the CallPanel API works.
      showCallPanelAPI(ra);

      // Logoff from the host.
      logoffHost(ra);

      // Perform an "advanced" function using the CallClass
      // action.
      performCallClass(ra);

      // Make sure to dispose of the application session
      // Immediately in the server.
      ra.requestClose();

      // Close connection (this call is not required in the code
      // below, because the connection has already been closed
      // using "requestClose" above).
      ra.close();
      }
    catch(Exception e)
      {
      // Error.
      System.out.println("\nError: "+e);
      e.printStackTrace();
      System.exit(1);
      }
    }

  /**
   * Displays the arguments for the program.
   */
  private static void displaySyntax()
    {
    System.out.println("TestAPI: syntax: TestAPI hostName:portName");
    System.exit(9);
    }

  /**
   * Connects the remote application to the server and application.
   * This method may be changed in order to provide support for
   * user authentication and optionally SSL (by using the class
   * SSLRemoteApplication instead of SSLRemoteApplication).
   *
   * @throws  IOException  for error in the connection to the server.
   */
  private static RemoteApplication connectFirst(String host,int port) throws IOException
    {
    // The Web Resource name is SAMPLES_RAPPAPI.
    RemoteApplication ra=testAPI.createRemoteApplication(APP_NAME);

    // Just one server in this case, use "setServers" for
    // backup servers.
    ra.setServer(host,port);
    //ra.setServers(new String [] {host, host2},new int [] {port, port2});

    // To use user authentication in case the resource has an
    // access control requiring this, call the setAuthentication
    // method.
    //ra.setAuthentication("RAPPUSER","password");

    // Do connect to the server.
    ra.connect();

    // Return the remote application instance.
    return ra;
    }

  /**
   * Gets information about the Sign on screen.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static boolean getSignonScreenInfo(RemoteApplication ra) throws IOException, SAXException
    {
    // Get current screen info with screen data.
    RAPPTransaction trans=new RAPPTransaction();
    RAPPCallHost ch1=new RAPPCallHost(true);
    trans.addAction(ch1);

    // Then get all host fields starting with "S".
    RAPPCallHost ch2=new RAPPCallHost("SIGNON","S*");
    trans.addAction(ch2);

    // Then get the TERM host field.
    RAPPCallHost ch3=new RAPPCallHost("SIGNON","TERM");
    trans.addAction(ch3);

    // Request these 3 actions.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);

    // Request the reply now (wait until available).
    rt=ra.getReply(requestID,true);

    // Update the current RAPPCallHost instances ch1, ch2 and ch3.
    rt.updateTransaction(trans);

    // Print out info about current screen (from action ch1).
    RAPPHostScreen screen=ch1.getScreen();
    System.out.println("\nScreen information:"
                      +"\n  error, lock    = "+ch1.hasError()+", "+ch1.isLocked()
                      +"\n  status         = "+ch1.getStatus()
                      +"\n  screen name    = "+screen.getScreenName()
                      +"\n  current field  = "+screen.getFieldName()
                      +"\n  text at line 1 = "+screen.getScreenData().substring(0,80).trim());
    
    // Check for probable wrong host ID, screen is not recognized...
    if ( screen.getScreenName()==null )
      return false;

    // Print out all available fields (from action ch2).
    RAPPHostCells hcs=ch2.getFields();
    int count=hcs.getCount();
    System.out.println("\nHost fields starting with 'S'"
                      +"\n  count = "+count);
    for ( int ii=0; ii<count; ++ii )
      {
      RAPPHostCell hc=hcs.getCell(ii);
      System.out.println("\n  field "+ii+":"
                        +"\n    name            = "+hc.getName()
                        +"\n    length          = "+hc.getLength()
                        +"\n    hostLength      = "+hc.getHostLength()
                        +"\n    column          = "+hc.getColumn()
                        +"\n    hostColumn      = "+hc.getHostColumn()
                        +"\n    hostFieldColumn = "+hc.getHostFieldColumn()
                        +"\n    row             = "+hc.getRow()
                        +"\n    hostRow         = "+hc.getHostRow()
                        +"\n    hostFieldRow    = "+hc.getHostFieldRow()
                        +"\n    protected       = "+hc.isProtected()
                        +"\n    hidden          = "+hc.isHidden()
                        +"\n    color           = 0x"+Integer.toHexString(hc.getColor())
                        +"\n    value           = "+hc.getValue());
      }

    // Print out the host field "TERM" (from action ch3).
    RAPPHostCell hc=ch3.getField();
    System.out.println("\nTERM field:"
                      +"\n  name            = "+hc.getName()
                      +"\n  length          = "+hc.getLength()
                      +"\n  hostLength      = "+hc.getHostLength()
                      +"\n  column          = "+hc.getColumn()
                      +"\n  hostColumn      = "+hc.getHostColumn()
                      +"\n  hostFieldColumn = "+hc.getHostFieldColumn()
                      +"\n  row             = "+hc.getRow()
                      +"\n  hostRow         = "+hc.getHostRow()
                      +"\n  hostFieldRow    = "+hc.getHostFieldRow()
                      +"\n  protected       = "+hc.isProtected()
                      +"\n  hidden          = "+hc.isHidden()
                      +"\n  color           = 0x"+Integer.toHexString(hc.getColor())
                      +"\n  value           = "+hc.getValue());

    // Extra space line.
    System.out.println("");
    return true;
    }

  /**
   * Manipulates global variables.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void globVar(RemoteApplication ra) throws IOException, SAXException
    {
    // Get all global variables starting containing "_HOST".
    RAPPTransaction trans=new RAPPTransaction();
    RAPPGlobVar gv1=new RAPPGlobVar("*_HOST*",RAPPGlobVar.GLOB_VAR_GET);
    trans.addAction(gv1);

    // Then set User ID and Password to logon to the host from REXX.
    trans.addAction(new RAPPGlobVar("USERID"  ,"TestUser"));
    trans.addAction(new RAPPGlobVar("PASSWORD","Secret"  ));

    // Get all variables.
    RAPPGlobVar gv2=new RAPPGlobVar("*",RAPPGlobVar.GLOB_VAR_GET);
    trans.addAction(gv2);

    // Now delete all variables containing "_SERVER_".
    trans.addAction(new RAPPGlobVar("*_SERVER_*",RAPPGlobVar.GLOB_VAR_DELETE));

    // To finish, get all the variables again to see what's left.
    RAPPGlobVar gv3=new RAPPGlobVar("*",RAPPGlobVar.GLOB_VAR_GET);
    trans.addAction(gv3);

    // Request these 6 GlobVar actions.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);

    // Request the reply now (wait until available).
    rt=ra.getReply(requestID,true);

    // Update the current RAPPGlobVar instances gv1, gv2 and gv3.
    rt.updateTransaction(trans);

    // Print out results from "*_HOST*".
    RAPPGlobVars vars=gv1.getVariables();
    int cc=vars.getCount();
    System.out.println("\nGLOBAL VARIABLES *_HOST*, count = "+cc);
    for ( int ii=0; ii<cc; ++ii )
      {
      RAPPGlobVar v=vars.getVariable(ii);
      System.out.println("  "+v.getName()+" = \""+v.getValue()+"\"");
      }

    // Print out results, all variables.
    vars=gv2.getVariables();
    cc=vars.getCount();
    System.out.println("\nALL GLOBAL VARIABLES #1, count = "+cc);
    for ( int ii=0; ii<cc; ++ii )
      {
      RAPPGlobVar v=vars.getVariable(ii);
      System.out.println("  "+v.getName()+" = \""+v.getValue()+"\"");
      }

    // Print out results, all variables after delete of "*_SERVER_*".
    vars=gv3.getVariables();
    cc=vars.getCount();
    System.out.println("\nALL GLOBAL VARIABLES #2, count = "+cc);
    for ( int ii=0; ii<cc; ++ii )
      {
      RAPPGlobVar v=vars.getVariable(ii);
      System.out.println("  "+v.getName()+" = \""+v.getValue()+"\"");
      }

    // Extra space line.
    System.out.println("");
    }

  /**
   * Calls logon object and disconnects the session.
   * The session is then reconnected and the reply for the
   * CallObject is retrieved.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static RemoteApplication logonDisconnectReconnect(RemoteApplication ra) throws IOException, SAXException
    {
    // Get all global variables starting containing "_HOST".
    RAPPTransaction trans=new RAPPTransaction();
    RAPPCallObject co=new RAPPCallObject("SIGNON","argIDNotUsedHere",RAPPCallObject.CMD,"argStrNotUsedHere");
    trans.addAction(co);

    // Request the call object.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);

    // Save the session ID + server address and port (if load
    // balancing is present) to "fake" a complete reconnect
    // without having the first instance of RemoteApplication (ra).
    String sessID=ra.getSessionID();
    String server=ra.getServerHostAddress();
    int    port  =ra.getServerPort();
    ra.close();

    // Not needed, but to show that the instance is gone!
    ra=null;

    // Reconnect (here we don't use user authentication because
    // we would have to set the user ID and password).
    ra=testAPI.createRemoteApplication(APP_NAME,sessID);
    ra.setServer(server,port);
    //ra.setAuthentication("RAPPUSER","password");
    ra.connect();

    // Request the reply now (wait until available).
    rt=ra.getReply(requestID,true);

    // Update the current RAPPCallObject instance "co".
    rt.updateTransaction(trans);

    // For demonstration purpose, we can also get a fresh
    // instance of "co" by creating a new transaction and
    // then extracting the "co" instance (as it is the first
    // action we performed).
    trans=rt.getTransaction();
    RAPPCallObject co2=(RAPPCallObject)trans.getAction(0);

    // Print out the results from both "co" and "co2" instances.
    System.out.println("\nCALL OBJECT LOGON #1, return = \""+co .getReturnString()+"\"");
    System.out.println("\nCALL OBJECT LOGON #2, return = \""+co2.getReturnString()+"\"");

    // Extra space line.
    System.out.println("");

    // Now make sure we're on the CUSTLIST screen by getting the
    // current screen without screen data (the screen name could
    // be null, so be careful!)
    trans=new RAPPTransaction();
    RAPPCallHost ch=new RAPPCallHost(false);
    trans.addAction(ch);

    // Send transaction and get reply.
    rt=new RemoteTransaction(trans);
    requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print out current screen.
    RAPPHostScreen scr=ch.getScreen();
    System.out.println("\nCURRENT SCREEN = "+scr.getScreenName());

    // Extra space line.
    System.out.println("");

    // Return the new instance of RemoteApplication since we
    // faked a complete disconnect/reconnect.
    return ra;
    }

  /**
   * Requests all customers from a listbox. Prior to getting the
   * list data, an object to collect all information is called.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void requestCustomers(RemoteApplication ra) throws IOException, SAXException
    {
    // Perform collection of all lines in list.
    RAPPTransaction trans=new RAPPTransaction();
    RAPPCallObject co=new RAPPCallObject("GETCUSTS","",RAPPCallObject.CMD,"");
    trans.addAction(co);

    // Request the customer list.
    RAPPCallPanel cp=new RAPPCallPanel("CUSTLIST");
    cp.request_getListData();
    trans.addAction(cp);

    // Send the request and get the reply.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print out the list data.
    RAPPLines lines=cp.get_getListData();
    if ( lines==null )
      {
      System.out.println("\nCUSTOMER LIST: no data!");
      }
    else
      {
      int cc=lines.getCount();
      System.out.println("\nCUSTOMER LIST: lineCount = "+cc);
      for ( int ii=0; ii<cc; ++ii )
        {
        String [] items=lines.getLineItems(ii);
        String s="  ";
        for ( int jj=0; jj<items.length; ++jj )
          {
          if ( jj>0 )
            s+=", ";
          s+="\""+items[jj]+"\"";
          }
        System.out.println(s);
        }
      }

    // Extra space line.
    System.out.println("");
    }

  /**
   * Gets customer data by selecting one (the first one) from
   * the list in the host using a call to an object. The data
   * is then retrieved from the panel CUSTDATA.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void getCustomerData(RemoteApplication ra) throws IOException, SAXException
    {
    // Navigate to the CUSTDATA panel.
    RAPPTransaction trans=new RAPPTransaction();
    RAPPCallObject co=new RAPPCallObject("CUSTDATA","",RAPPCallObject.CMD,"");
    trans.addAction(co);

    // Get all texts from the controls.
    // Data retrieval in this case would probably have been easier
    // to perform against the host screen rather than the panel,
    // but it's a sample! In real world, the data in the panel could
    // have been fetched from multiple screen, thus getting the data
    // from the host screen must be done in several steps (but from
    // the panel it can be done in a single step).
    RAPPCallPanel name    =new RAPPCallPanel("NAME"    );
    RAPPCallPanel addr1   =new RAPPCallPanel("ADDR1"   );
    RAPPCallPanel addr2   =new RAPPCallPanel("ADDR2"   );
    RAPPCallPanel lastpur =new RAPPCallPanel("LASTPUR" );
    RAPPCallPanel amount  =new RAPPCallPanel("AMOUNT"  );
    RAPPCallPanel firstpur=new RAPPCallPanel("FIRSTPUR");
    RAPPCallPanel credlim =new RAPPCallPanel("CREDLIM" );
    RAPPCallPanel credused=new RAPPCallPanel("CREDUSED");
    RAPPCallPanel credrest=new RAPPCallPanel("CREDREST");
    RAPPCallPanel credrate=new RAPPCallPanel("CREDRATE");
    RAPPCallPanel goldmbr =new RAPPCallPanel("GOLDMBR" );
    RAPPCallPanel selladdr=new RAPPCallPanel("SELLADDR");

    name    .request_getText();
    addr1   .request_getText();
    addr2   .request_getText();
    lastpur .request_getText();
    amount  .request_getText();
    firstpur.request_getText();
    credlim .request_getText();
    credused.request_getText();
    credrest.request_getText();
    credrate.request_getText();
    goldmbr .request_getText();
    selladdr.request_getText();

    // Add the getText actions.
    trans.addAction(name    );
    trans.addAction(addr1   );
    trans.addAction(addr2   );
    trans.addAction(lastpur );
    trans.addAction(amount  );
    trans.addAction(firstpur);
    trans.addAction(credlim );
    trans.addAction(credused);
    trans.addAction(credrest);
    trans.addAction(credrate);
    trans.addAction(goldmbr );
    trans.addAction(selladdr);

    // Send the request and get the reply.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print out the variables.
    System.out.println("CUSTOMER DATA:"
                      +"\n  NAME     = \""+name    .get_getText()+"\""
                      +"\n  ADDR1    = \""+addr1   .get_getText()+"\""
                      +"\n  ADDR2    = \""+addr2   .get_getText()+"\""
                      +"\n  LASTPUR  = \""+lastpur .get_getText()+"\""
                      +"\n  AMOUNT   = \""+amount  .get_getText()+"\""
                      +"\n  FIRSTPUR = \""+firstpur.get_getText()+"\""
                      +"\n  CREDLIM  = \""+credlim .get_getText()+"\""
                      +"\n  CREDUSED = \""+credused.get_getText()+"\""
                      +"\n  CREDREST = \""+credrest.get_getText()+"\""
                      +"\n  CREDRATE = \""+credrate.get_getText()+"\""
                      +"\n  GOLDMBR  = \""+goldmbr .get_getText()+"\""
                      +"\n  SELLADDR = \""+selladdr.get_getText()+"\"");

    // Extra space line.
    System.out.println("");
    }

  /**
   * Shows how the CallPanel API works.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void showCallPanelAPI(RemoteApplication ra) throws IOException, SAXException
    {
    RAPPTransaction trans=new RAPPTransaction();

    RAPPCallPanel setText=new RAPPCallPanel("OUTPUT");
    setText.request_setText("Sets the text for a control");

    RAPPCallPanel getText=new RAPPCallPanel("ADDR1");
    getText.request_getText();

    RAPPCallPanel setEnabled=new RAPPCallPanel("RADIO3");
    setEnabled.request_setEnabled(false);

    RAPPCallPanel isEnabled=new RAPPCallPanel("RADIO2");
    isEnabled.request_isEnabled();

    RAPPCallPanel setVisible=new RAPPCallPanel("HIDDEN");
    setVisible.request_setVisible(false);

    RAPPCallPanel isVisible=new RAPPCallPanel("VISIBLE");
    isVisible.request_isVisible();

    RAPPCallPanel setChecked=new RAPPCallPanel("RADIO2");
    setChecked.request_setChecked(1);

    RAPPCallPanel isChecked=new RAPPCallPanel("RADIO2");
    isChecked.request_isChecked();

    RAPPCallPanel getLineCount=new RAPPCallPanel("OUTLIST");
    getLineCount.request_getLineCount();

    RAPPCallPanel insertLine=new RAPPCallPanel("OUTLIST");
    String [] line=new String []
      {
      "Line 0",
      "### Line inserted at beginning of list ###"
      };
    insertLine.request_insertLine(new RAPPLine(line),0);

    RAPPCallPanel setLine=new RAPPCallPanel("OUTLIST");
    line=new String []
      {
      "Used to be line 3, is now line 4",
      "The file \"outlist.txt\" is located..."
      };
    setLine.request_setLine(new RAPPLine(line),3);

    RAPPCallPanel getLine=new RAPPCallPanel("OUTLIST");
    getLine.request_getLine(1);

    RAPPCallPanel deleteLine=new RAPPCallPanel("OUTLIST");
    deleteLine.request_deleteLine(4);

    RAPPCallPanel setCell=new RAPPCallPanel("OUTLIST");
    setCell.request_setCell(0,1,"Cell at current Line 1");

    RAPPCallPanel getCell=new RAPPCallPanel("OUTLIST");
    getCell.request_getCell(1,0);

    RAPPCallPanel setSelection=new RAPPCallPanel("INLIST");
    setSelection.request_setSelection(2,true);

    RAPPCallPanel getNextSelection=new RAPPCallPanel("INLIST");
    getNextSelection.request_getNextSelection(-1);

    RAPPCallPanel deleteAll=new RAPPCallPanel("INLIST");
    deleteAll.request_deleteAll(); // The list is host connected, so this is unpredictable.

    RAPPCallPanel getListData=new RAPPCallPanel("OUTLIST");
    getListData.request_getListData();

    RAPPCallPanel setListData=new RAPPCallPanel("OUTLIST");
    RAPPLines list=new RAPPLines();
    list.addLine(new String [] { "row 1, col 1", "row 1, col 2" });
    list.addLine(new String [] { "row 2, col 1", "row 2, col 2" });
    list.addLine(new String [] { "row 3, col 1", "row 3, col 2" });
    list.addLine(new String [] { "row 4, col 1", "row 4, col 2" });
    list.addLine(new String [] { "row 5, col 1", "row 5, col 2" });
    list.addLine(new String [] { "row 6, col 1", "row 6, col 2" });
    list.addLine(new String [] { "row 7, col 1", "row 7, col 2" });
    list.addLine(new String [] { "row 8, col 1", "row 8, col 2" });
    list.addLine(new String [] { "row 9, col 1", "row 9, col 2" });
    setListData.request_setListData(list);

    RAPPCallPanel callControl=new RAPPCallPanel("END");
    callControl.request_callControl();

    trans.addAction(setText);
    trans.addAction(getText);
    trans.addAction(setEnabled);
    trans.addAction(isEnabled);
    trans.addAction(setVisible);
    trans.addAction(isVisible);
    trans.addAction(setChecked);
    trans.addAction(isChecked);
    trans.addAction(getLineCount);
    trans.addAction(insertLine);
    trans.addAction(setLine);
    trans.addAction(getLine);
    trans.addAction(deleteLine);
    trans.addAction(setCell);
    trans.addAction(getCell);
    trans.addAction(setSelection);
    trans.addAction(getNextSelection);
    trans.addAction(deleteAll);
    trans.addAction(getListData);
    trans.addAction(setListData);
    trans.addAction(callControl);

    // Send the request and get the reply.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print out the result.
    System.out.println("CALL PANEL FUNCTIONS:"
                      +"\n  getText          = \""+getText       .get_getText()+"\""
                      +"\n  setText          = "+setText         .get_setText()
                      +"\n  setEnabled       = "+setEnabled      .get_setEnabled()
                      +"\n  isEnabled        = "+isEnabled       .get_isEnabled()
                      +"\n  setVisible       = "+setVisible      .get_setVisible()
                      +"\n  isVisible        = "+isVisible       .get_isVisible()
                      +"\n  setChecked       = "+setChecked      .get_setChecked()
                      +"\n  isChecked        = "+isChecked       .get_isChecked()
                      +"\n  getLineCount     = "+getLineCount    .get_getLineCount()
                      +"\n  insertLine       = "+insertLine      .get_insertLine()
                      +"\n  setLine          = "+setLine         .get_setLine()
                      +"\n  getLine          = \""+getLine       .get_getLine()+"\""
                      +"\n  deleteLine       = "+deleteLine      .get_deleteLine()
                      +"\n  setCell          = "+setCell         .get_setCell()
                      +"\n  getCell          = \""+getCell       .get_getCell()+"\""
                      +"\n  setSelection     = "+setSelection    .get_setSelection()
                      +"\n  getNextSelection = "+getNextSelection.get_getNextSelection()
                      +"\n  deleteAll        = "+deleteAll       .get_deleteAll()
                      +"\n  setListData      = "+setListData     .get_setListData()
                      +"\n  callControl      = "+callControl     .get_callControl());

    // Print the list data.
    RAPPLines lines=getListData.get_getListData();
    int cc=lines.getCount();
    System.out.println("  list data, lineCount = "+cc+":");
    for ( int ii=0; ii<cc; ++ii )
      System.out.println("    line "+ii+" = "+lines.getLine(ii));

    // Extra space line.
    System.out.println("");
    }

  /**
   * Logs off from the host.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void logoffHost(RemoteApplication ra) throws IOException, SAXException
    {
    // Call the LOGOFF object.
    RAPPTransaction trans=new RAPPTransaction();
    RAPPCallObject co=new RAPPCallObject("LOGOFF","",RAPPCallObject.CMD,"");
    trans.addAction(co);

    // Send the request and get the reply.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print result.
    System.out.println("\nLOGOFF returned \""+co.getReturnString()+"\"");

    // Extra space line.
    System.out.println("");
    }

  /**
   * Calls a "user" class in the server with user-defined data
   * in an Element. The reply is returned from the called class,
   * also as an Element. The caller must then extract the information
   * as required.
   *
   * @throws  IOException   for error in the connection to the server.
   * @throws  SAXException  for errors in parsing the <code>xmlDocument</code> to a <code>org.w3c.dom.Document</code>.
   */
  private static void performCallClass(RemoteApplication ra) throws IOException, SAXException
    {
    // Create the transaction and our user-defined Element.
    RAPPTransaction trans=new RAPPTransaction();
    Element requestData=trans.createElement("myRequest");

    // The RAPPElement class has helper methods to manipulate
    // elements. Below, we create the element without an
    // XML namespace. In this element, we set 3 attributes
    // of different kind.
    RAPPElement e=new RAPPElement(requestData,null);
    e.setAttribute("myStringAttribute" ,"myValue");
    e.setAttribute("myIntegerAttribute",123);
    e.setAttribute("myBooleanAttribute",true);

    // In the element, a child element is added with "special"
    // data.
    RAPPElement c=e.createAppendedChild("myChildElement");
    c.setAttribute("myChildAttribute","childValue");

    // Create the CallClass action calling the class
    // "server.CallClassTest" with the newly created
    // Element.
    RAPPCallClass cc=new RAPPCallClass("server.CallClassTest",
                                       requestData);
    trans.addAction(cc);

    // Add a second CallClass action with an unknown class to
    // the test error handling in the server. This CallClass
    // action does not have any request data.
    RAPPCallClass cc2=new RAPPCallClass("undefined.class.Nowhere");
    trans.addAction(cc2);

    // Add a third CallClass action with a known class that does
    // not implement the CallClassInterface in order to test error
    // handling in the server.
    RAPPCallClass cc3=new RAPPCallClass("se.entra.phantom.server.HostField");
    trans.addAction(cc3);

    // Use the Remote Application to log an event in the
    // NetPhantom Server log.
    ra.logServerEvent(RemoteApplication.EVENT_INFORMATIONAL,
                      "About to call server.CallClassTest action");

    // Send the request and get the reply.
    RemoteTransaction rt=new RemoteTransaction(trans);
    int requestID=ra.requestTransaction(rt);
    rt=ra.getReply(requestID,true);
    rt.updateTransaction(trans);

    // Print out all data from the reply (note that it might
    // be null, depending on the server CallClass implementation).
    // The string for the element is retrieved from the RAPPElement
    // class that also has static helper methods.
    Element replyData=cc.getReply();
    if ( replyData==null )
      {
      System.out.println("\nCALL CLASS server.CallClassTest: no reply data"
                        +"\n  errorCode   = "+cc.getErrorCode()
                        +"\n  description = "+cc.getErrorDescription());
      }
    else
      {
      // Log the reply (if debug is present).
      String s=RAPPElement.getElementString(replyData);
      ra.logDebugOutput("Reply from server.CallClassTest action: "+s);
      System.out.println("\nCALL CLASS server.CallClassTest: reply data:\n"
                        +"  "+s);
      }

    // Print out information about the two CallClass actions
    // that fails.
    System.out.println("\nCALL CLASS undefined.class.Nowhere:"
                      +"\n  errorCode   = "+cc2.getErrorCode()
                      +"\n  description = "+cc2.getErrorDescription());

    System.out.println("\nCALL CLASS se.entra.phantom.server.HostField:"
                      +"\n  errorCode   = "+cc3.getErrorCode()
                      +"\n  description = "+cc3.getErrorDescription());

    // Extra space line.
    System.out.println("");
    }
}