Link to home
Start Free TrialLog in
Avatar of stevebeech
stevebeech

asked on

Java and PCML?

Hi,

I'm using a Java program with a PCML file to pass and retrieve parameters from a RPG service program, successfully. However, some of the RPG code I'm calling returns a value to indicate whether the program ran successfully or not. I have coded for this in the PCML file program element:

<program name="xx" entrypoint="xx" path="/QSYS.lib/XX.lib/XXXX.srvpgm" returnvalue="integer"/>

and ensured that the returned value is a 4byte integer (as per the PCML spec).

The problem is I can't figure out how to access this value within my Java code.

Can anyone tell me how?

Cheers,
Steve
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Are you running this in some way with Runtime.exec? If so, i suspect that the value you're talking about may well be the return value of the process, which of course you can read from waitFor
Avatar of stevebeech
stevebeech

ASKER

You've lost me.

Here's my code (in case it helps):

public class SystemName {

      /**  Constructor for the SystemName object */
      public SystemName() { }

      /**
       *  Description of the Method
       *
       *@param  argv  Description of the Parameter
       */
      public static void main(String argv[]) {

            // Create and instantiate an AS/400 Object
            System.out.println("Connecting to iSeries...");

            AS400 sys = new AS400("XXX001", "username", "password");

            // Create Data Objects
            ProgramCallDocument pcml;

            boolean rc = false;

            String name;
            // String for returned name value
            String msgId;
            // String for returned name value
            String msgText;
            // Strings for as400 messags/400

            try {

                  // Instantiate the Objects (assign the variables)
                  pcml = new ProgramCallDocument(sys, "CallProgramPcml");

                  pcml.setValue("GETSYSNAMJ.sysname", new String("xxxxxxxx"));
                  
                  // Call the Program
                  rc = pcml.callProgram("GETSYSNAMJ");

                  // If return code is false, get messages from the iSeries
                  if (rc == false) {
                        // Retrieve list of AS/400 messages
                        AS400Message[] msgs = pcml.getMessageList("GETSYSNAMJ");

                        // Loop through all messages and write them to standard output
                        for (int m = 0; m < msgs.length; m++) {
                              msgId = msgs[m].getID();
                              msgText = msgs[m].getText();
                              System.out.println("    " + msgId + " - " + msgText);
                        }
                        System.out.println("Call to GETSYSNAMJ failed. See messages listed above");
                        System.exit(0);
                  }
                  // Return code was true, call to GetSysNam succeeded - woo-hoo!
                  else {
                        // Process the returned Data
                        name = (String) pcml.getValue("GETSYSNAMJ.sysname");
                        System.out.print("Returned System Name: " + name);
                        System.exit(0);
                  }
            } catch (PcmlException e) {
                  System.out.println(e.getLocalizedMessage());
                  e.printStackTrace();
                  System.out.println("Call to GETSYSNAMJ failed");
                  System.exit(0);
            }
            // Disconnect from AS/400
            sys.disconnectAllServices();
      }
}

and my PCML file:

<pcml version="3.0">
      <program name="GETSYSNAMJ" entrypoint="GETSYSNAMJ" path="/QSYS.lib/XHAJN.lib/SRV_SYSNM2.srvpgm" returnvalue="integer">
        <data name="sysname" type="char" length="10" usage="inputoutput" init="XXXXXXX"/>
      </program>
</pcml>


It's the returnvalue that I want to get at, but it isn't passed as a parameter (like sysname is)

??
Can you show your imports?
import com.ibm.as400.data.ProgramCallDocument;
import com.ibm.as400.data.PcmlException;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400Message;
import java.math.BigDecimal;
I'd need quite a while to get into this very unfamiliar API, but it looks like output data is being obtained here:

http://www-919.ibm.com/servers/eserver/iseries/developer/java/documents/pcml.html. Look at the first Java source file
Yes, output data is being obtained, but not the returnvalue attribute. Its not used in either of these examples. This is a problem with legacy RPG code which uses a return value to determine if a procedure completed or not. I reckon that new code would avoid using a return value (when it knows its to be accessed from Java with PCML) so its a problem I'll have to work around for now (means not using PCML, so extra coding).

Do you mind if I leave this question open for a few days to see if anyone else comes up with an answer? (I don't think they will - I've crawled the web looking for references to the returnvalue attribute with little success) If nothing turns up, then the points are yours CEHJ.

Cheers,

Steve
try this code..

Example of retrieving a list of information
PCML source for calling QGYOLAUS
<pcml version="1.0">

<!-- PCML source for calling "Open List of Authorized Users" (QGYOLAUS) API -->
   
  <!-- Format AUTU0150 - Other formats are available -->
  <struct name="autu0150">
    <data name="name"         type="char" length="10" />
    <data name="userOrGroup"  type="char" length="1"  />
    <data name="groupMembers" type="char" length="1"  />
    <data name="description"  type="char" length="50" />
  </struct>
   
  <!-- List information structure (common for "Open List" type APIs) -->
  <struct name="listInfo">
    <data name="totalRcds"    type="int"  length="4" />
    <data name="rcdsReturned" type="int"  length="4" />
    <data name="rqsHandle"    type="byte" length="4" />
    <data name="rcdLength"    type="int"  length="4" />
    <data name="infoComplete" type="char" length="1" />
    <data name="dateCreated"  type="char" length="7" />
    <data name="timeCreated"  type="char" length="6" />
    <data name="listStatus"   type="char" length="1" />
    <data                     type="byte" length="1" />
    <data name="lengthOfInfo" type="int"  length="4" />
    <data name="firstRecord"  type="int"  length="4" />
    <data                     type="byte" length="40" />
  </struct>
       
  <!-- Program QGYOLAUS and its parameter list for retrieving AUTU0150 format -->
  <program name="qgyolaus" path="/QSYS.lib/QGY.lib/QGYOLAUS.pgm" parseorder="listInfo receiver">
    <data   name="receiver"       type="struct" struct="autu0150" usage="output"
              count="listInfo.rcdsReturned" outputsize="receiverLength" />
    <data   name="receiverLength" type="int"    length="4"  usage="input" init="16384" />
    <data   name="listInfo"       type="struct" struct="listInfo" usage="output" />
    <data   name="rcdsToReturn"   type="int"    length="4"  usage="input" init="264" />
    <data   name="format"         type="char"   length="10" usage="input" init="AUTU0150" />
    <data   name="selection"      type="char"   length="10" usage="input" init="*USER" />
    <data   name="member"         type="char"   length="10" usage="input" init="*NONE" />
    <data   name="errorCode"      type="int"    length="4"  usage="input" init="0" />

  </program>
   
  <!-- Program QGYGTLE returned additional "records" from the list
       created by QGYOLAUS. -->
  <program name="qgygtle" path="/QSYS.lib/QGY.lib/QGYGTLE.pgm" parseorder="listInfo receiver">
    <data   name="receiver"       type="struct" struct="autu0150" usage="output"
            count="listInfo.rcdsReturned" outputsize="receiverLength" />
    <data   name="receiverLength" type="int"    length="4" usage="input" init="16384" />
    <data   name="requestHandle"  type="byte"   length="4" usage="input" />
    <data   name="listInfo"       type="struct" struct="listInfo" usage="output" />
    <data   name="rcdsToReturn"   type="int"    length="4" usage="input" init="264" />
    <data   name="startingRcd"    type="int"    length="4" usage="input" />
    <data   name="errorCode"      type="int"    length="4" usage="input" init="0" />
  </program>
   
  <!-- Program QGYCLST closes the list, freeing resources on the AS/400 -->
  <program name="qgyclst" path="/QSYS.lib/QGY.lib/QGYCLST.pgm" >
    <data   name="requestHandle"  type="byte"   length="4" usage="input" />
    <data   name="errorCode"      type="int"    length="4" usage="input" init="0" />
  </program>
</pcml>

 
Java program source for calling QGYOLAUS
import com.ibm.as400.data.ProgramCallDocument;
import com.ibm.as400.data.PcmlException;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400Message;

// Example program to call "Retrieve List of Authorized Users" (QGYOLAUS) API
public class qgyolaus
{
   
  public static void main(String[] argv)  
  {
    AS400 as400System;         // com.ibm.as400.access.AS400
    ProgramCallDocument pcml;  // com.ibm.as400.data.ProgramCallDocument
    boolean rc = false;        // Return code from ProgramCallDocument.callProgram()
    String msgId, msgText;     // Messages returned from AS/400
    Object value;              // Return value from ProgramCallDocument.getValue()
     
    int[] indices = new int[1]; // Indices for access array value
    int nbrRcds,                // Number of records returned from QGYOLAUS and QGYGTLE
        nbrUsers;               // Total number of users retrieved
    String listStatus;          // Status of list on AS/400
    byte[] requestHandle = new byte[4];

    System.setErr(System.out);
       
    // Construct AS400 without parameters, user will be prompted
    as400System = new AS400();
     
    try
    {
      // Uncomment the following to get debugging information
      //com.ibm.as400.data.PcmlMessageLog.setTraceEnabled(true);
     
      System.out.println("Beginning PCML Example..");
      System.out.println("    Constructing ProgramCallDocument for QGYOLAUS API...");
     
      // Construct ProgramCallDocument
      // First parameter is system to connect to
      // Second parameter is pcml resource name. In this example,
      // serialized PCML file "qgyolaus.pcml.ser" or
      // PCML source file "qgyolaus.pcml" must be found in the classpath.
      pcml = new ProgramCallDocument(as400System, "qgyolaus");
     
      // All input parameters have default values specified in the PCML source.
      // Do not need to set them using Java code.
     
      // Request to call the API
      // User will be prompted to sign on to the system
      System.out.println("    Calling QGYOLAUS API requesting information for the sign-on user.");
      rc = pcml.callProgram("qgyolaus");

      // If return code is false, we received messages from the AS/400
      if(rc == false)
      {
        // Retrieve list of AS/400 messages
        AS400Message[] msgs = pcml.getMessageList("qgyolaus");
       
        // Iterate through messages and write them to standard output
        for (int m = 0; m < msgs.length; m++)
        {
            msgId = msgs[m].getID();
            msgText = msgs[m].getText();
            System.out.println("    " + msgId + " - " + msgText);
        }
        System.out.println("** Call to QGYOLAUS failed. See messages above **");
        System.exit(0);
      }
      // Return code was true, call to QGYOLAUS succeeded
      // Write some of the results to standard output
      else
      {
        boolean doneProcessingList = false;
        String programName = "qgyolaus";
        nbrUsers = 0;
        while (!doneProcessingList)
        {
          nbrRcds = pcml.getIntValue(programName + ".listInfo.rcdsReturned");
          requestHandle = (byte[]) pcml.getValue(programName + ".listInfo.rqsHandle");
         
          // Iterate through list of users
          for (indices[0] = 0; indices[0] < nbrRcds; indices[0]++)
          {
               value = pcml.getValue(programName + ".receiver.name", indices);
               System.out.println("User:  " + value);
           
               value = pcml.getValue(programName + ".receiver.description", indices);
               System.out.println("\t\t" + value);    
          }
         
          nbrUsers += nbrRcds;
         
          // See if we retrieved all the users.
          // If not, subsequent calls to "Get List Entries" (QGYGTLE)
          // would need to be made to retrieve the remaining users in the list.
          listStatus = (String) pcml.getValue(programName + ".listInfo.listStatus");
          if ( listStatus.equals("2")   // List is marked as "Complete"
            || listStatus.equals("3") ) // Or list is marked "Error building"
          {
            doneProcessingList = true;
          }
          else
          {
            programName = "qgygtle";
           
            // Set input parameters for QGYGTLE
            pcml.setValue("qgygtle.requestHandle", requestHandle);
            pcml.setIntValue("qgygtle.startingRcd", nbrUsers + 1);
           
            // Call "Get List Entries" (QGYGTLE) to get more users from list
            rc = pcml.callProgram("qgygtle");
     
            // If return code is false, we received messages from the AS/400
            if(rc == false)
            {
              // Retrieve list of AS/400 messages
              AS400Message[] msgs = pcml.getMessageList("qgygtle");
             
              // Iterate through messages and write them to standard output
              for (int m = 0; m < msgs.length; m++)
              {
                  msgId = msgs[m].getID();
                  msgText = msgs[m].getText();
                  System.out.println("    " + msgId + " - " + msgText);
              }
              System.out.println("** Call to QGYGTLE failed. See messages above **");
              System.exit(0);
            }
            // Return code was true, call to QGYGTLE succeeded
           
          }
        }
        System.out.println("Number of users returned:  " + nbrUsers);
       
        // Call the "Close List" (QGYCLST) API
        pcml.setValue("qgyclst.requestHandle", requestHandle);
        rc = pcml.callProgram("qgyclst");
      }
    }
    catch(PcmlException e)
    {
      System.out.println(e.getLocalizedMessage());    
      e.printStackTrace();
      System.out.println("*** Call to QGYOLAUS failed. ***");
      System.exit(0);
    }

    System.exit(0);
  }
}

Example of retrieving a list of information
PCML source for calling QGYOLAUS
<pcml version="1.0">

<!-- PCML source for calling "Open List of Authorized Users" (QGYOLAUS) API -->
   
  <!-- Format AUTU0150 - Other formats are available -->
  <struct name="autu0150">
    <data name="name"         type="char" length="10" />
    <data name="userOrGroup"  type="char" length="1"  />
    <data name="groupMembers" type="char" length="1"  />
    <data name="description"  type="char" length="50" />
  </struct>
   
  <!-- List information structure (common for "Open List" type APIs) -->
  <struct name="listInfo">
    <data name="totalRcds"    type="int"  length="4" />
    <data name="rcdsReturned" type="int"  length="4" />
    <data name="rqsHandle"    type="byte" length="4" />
    <data name="rcdLength"    type="int"  length="4" />
    <data name="infoComplete" type="char" length="1" />
    <data name="dateCreated"  type="char" length="7" />
    <data name="timeCreated"  type="char" length="6" />
    <data name="listStatus"   type="char" length="1" />
    <data                     type="byte" length="1" />
    <data name="lengthOfInfo" type="int"  length="4" />
    <data name="firstRecord"  type="int"  length="4" />
    <data                     type="byte" length="40" />
  </struct>
       
  <!-- Program QGYOLAUS and its parameter list for retrieving AUTU0150 format -->
  <program name="qgyolaus" path="/QSYS.lib/QGY.lib/QGYOLAUS.pgm" parseorder="listInfo receiver">
    <data   name="receiver"       type="struct" struct="autu0150" usage="output"
              count="listInfo.rcdsReturned" outputsize="receiverLength" />
    <data   name="receiverLength" type="int"    length="4"  usage="input" init="16384" />
    <data   name="listInfo"       type="struct" struct="listInfo" usage="output" />
    <data   name="rcdsToReturn"   type="int"    length="4"  usage="input" init="264" />
    <data   name="format"         type="char"   length="10" usage="input" init="AUTU0150" />
    <data   name="selection"      type="char"   length="10" usage="input" init="*USER" />
    <data   name="member"         type="char"   length="10" usage="input" init="*NONE" />
    <data   name="errorCode"      type="int"    length="4"  usage="input" init="0" />

  </program>
   
  <!-- Program QGYGTLE returned additional "records" from the list
       created by QGYOLAUS. -->
  <program name="qgygtle" path="/QSYS.lib/QGY.lib/QGYGTLE.pgm" parseorder="listInfo receiver">
    <data   name="receiver"       type="struct" struct="autu0150" usage="output"
            count="listInfo.rcdsReturned" outputsize="receiverLength" />
    <data   name="receiverLength" type="int"    length="4" usage="input" init="16384" />
    <data   name="requestHandle"  type="byte"   length="4" usage="input" />
    <data   name="listInfo"       type="struct" struct="listInfo" usage="output" />
    <data   name="rcdsToReturn"   type="int"    length="4" usage="input" init="264" />
    <data   name="startingRcd"    type="int"    length="4" usage="input" />
    <data   name="errorCode"      type="int"    length="4" usage="input" init="0" />
  </program>
   
  <!-- Program QGYCLST closes the list, freeing resources on the AS/400 -->
  <program name="qgyclst" path="/QSYS.lib/QGY.lib/QGYCLST.pgm" >
    <data   name="requestHandle"  type="byte"   length="4" usage="input" />
    <data   name="errorCode"      type="int"    length="4" usage="input" init="0" />
  </program>
</pcml>

 
Java program source for calling QGYOLAUS
import com.ibm.as400.data.ProgramCallDocument;
import com.ibm.as400.data.PcmlException;
import com.ibm.as400.access.AS400;
import com.ibm.as400.access.AS400Message;

// Example program to call "Retrieve List of Authorized Users" (QGYOLAUS) API
public class qgyolaus
{
   
  public static void main(String[] argv)  
  {
    AS400 as400System;         // com.ibm.as400.access.AS400
    ProgramCallDocument pcml;  // com.ibm.as400.data.ProgramCallDocument
    boolean rc = false;        // Return code from ProgramCallDocument.callProgram()
    String msgId, msgText;     // Messages returned from AS/400
    Object value;              // Return value from ProgramCallDocument.getValue()
     
    int[] indices = new int[1]; // Indices for access array value
    int nbrRcds,                // Number of records returned from QGYOLAUS and QGYGTLE
        nbrUsers;               // Total number of users retrieved
    String listStatus;          // Status of list on AS/400
    byte[] requestHandle = new byte[4];

    System.setErr(System.out);
       
    // Construct AS400 without parameters, user will be prompted
    as400System = new AS400();
     
    try
    {
      // Uncomment the following to get debugging information
      //com.ibm.as400.data.PcmlMessageLog.setTraceEnabled(true);
     
      System.out.println("Beginning PCML Example..");
      System.out.println("    Constructing ProgramCallDocument for QGYOLAUS API...");
     
      // Construct ProgramCallDocument
      // First parameter is system to connect to
      // Second parameter is pcml resource name. In this example,
      // serialized PCML file "qgyolaus.pcml.ser" or
      // PCML source file "qgyolaus.pcml" must be found in the classpath.
      pcml = new ProgramCallDocument(as400System, "qgyolaus");
     
      // All input parameters have default values specified in the PCML source.
      // Do not need to set them using Java code.
     
      // Request to call the API
      // User will be prompted to sign on to the system
      System.out.println("    Calling QGYOLAUS API requesting information for the sign-on user.");
      rc = pcml.callProgram("qgyolaus");

      // If return code is false, we received messages from the AS/400
      if(rc == false)
      {
        // Retrieve list of AS/400 messages
        AS400Message[] msgs = pcml.getMessageList("qgyolaus");
       
        // Iterate through messages and write them to standard output
        for (int m = 0; m < msgs.length; m++)
        {
            msgId = msgs[m].getID();
            msgText = msgs[m].getText();
            System.out.println("    " + msgId + " - " + msgText);
        }
        System.out.println("** Call to QGYOLAUS failed. See messages above **");
        System.exit(0);
      }
      // Return code was true, call to QGYOLAUS succeeded
      // Write some of the results to standard output
      else
      {
        boolean doneProcessingList = false;
        String programName = "qgyolaus";
        nbrUsers = 0;
        while (!doneProcessingList)
        {
          nbrRcds = pcml.getIntValue(programName + ".listInfo.rcdsReturned");
          requestHandle = (byte[]) pcml.getValue(programName + ".listInfo.rqsHandle");
         
          // Iterate through list of users
          for (indices[0] = 0; indices[0] < nbrRcds; indices[0]++)
          {
               value = pcml.getValue(programName + ".receiver.name", indices);
               System.out.println("User:  " + value);
           
               value = pcml.getValue(programName + ".receiver.description", indices);
               System.out.println("\t\t" + value);    
          }
         
          nbrUsers += nbrRcds;
         
          // See if we retrieved all the users.
          // If not, subsequent calls to "Get List Entries" (QGYGTLE)
          // would need to be made to retrieve the remaining users in the list.
          listStatus = (String) pcml.getValue(programName + ".listInfo.listStatus");
          if ( listStatus.equals("2")   // List is marked as "Complete"
            || listStatus.equals("3") ) // Or list is marked "Error building"
          {
            doneProcessingList = true;
          }
          else
          {
            programName = "qgygtle";
           
            // Set input parameters for QGYGTLE
            pcml.setValue("qgygtle.requestHandle", requestHandle);
            pcml.setIntValue("qgygtle.startingRcd", nbrUsers + 1);
           
            // Call "Get List Entries" (QGYGTLE) to get more users from list
            rc = pcml.callProgram("qgygtle");
     
            // If return code is false, we received messages from the AS/400
            if(rc == false)
            {
              // Retrieve list of AS/400 messages
              AS400Message[] msgs = pcml.getMessageList("qgygtle");
             
              // Iterate through messages and write them to standard output
              for (int m = 0; m < msgs.length; m++)
              {
                  msgId = msgs[m].getID();
                  msgText = msgs[m].getText();
                  System.out.println("    " + msgId + " - " + msgText);
              }
              System.out.println("** Call to QGYGTLE failed. See messages above **");
              System.exit(0);
            }
            // Return code was true, call to QGYGTLE succeeded
           
          }
        }
        System.out.println("Number of users returned:  " + nbrUsers);
       
        // Call the "Close List" (QGYCLST) API
        pcml.setValue("qgyclst.requestHandle", requestHandle);
        rc = pcml.callProgram("qgyclst");
      }
    }
    catch(PcmlException e)
    {
      System.out.println(e.getLocalizedMessage());    
      e.printStackTrace();
      System.out.println("*** Call to QGYOLAUS failed. ***");
      System.exit(0);
    }

    System.exit(0);
  }
}

http://publib.boulder.ibm.com/iseries/v5r1/ic2924/index.htm?info/rzahh/page1.htm

best of luck..
R.K
 
I would, but it doesn't address my problem.

Let me clarify - I can get the PCML and Java working, in order to pass and retrieve parameters - that isn't the problem.

The problem is with the returnvalue attribute in the program element:

<program name="GETSYSNAMJ" entrypoint="GETSYSNAMJ" path="/QSYS.lib/XHAJN.lib/SRV_SYSNM2.srvpgm" returnvalue="integer">

i.e. returnvalue="integer"

This is the value I'd like to get hold of. Unfortunately it doesn't appear to be available (as its never assigned a name).

I know that its being passed back though, because I get an AS400 error if its not in the form of a PackedDecimal (in RPG) AND if I've specified it within the PCML file.

Steve.

>>Do you mind if I leave this question open for a few days ...

No of course not. What i'd look for is the abstraction in the api that encapsulates the actual machine process. You should be able to get the process return value from this.
Well, I found the solution!!!

The ProgramCallDocument class (which is the class used to call the PCML-specified program) has a method named getIntReturnValue(String name), and the name to be specified as a parameter is the name of the program element in the PCML document (in my case GETSYSNAMJ).

So adding the method:

int x  = pcml.getIntReturnValue("GETSYSNAMJ");

copies the returnvalue into x.

Phew.

Thanks all for your help.

Cheers,

Steve
ASKER CERTIFIED SOLUTION
Avatar of modulo
modulo

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial