Start changeBuilding AS/400 program calls with PCML

To build AS/400 program calls with PCML, you must start by creating the following:

Depending upon your design process, you must write one or more PCML source files where you describe the interfaces to the AS/400 programs that will be called by your Java application. Refer to PCML syntax for a detailed description of the language.

Then, your Java application, shown in yellow in Figure 1 below, interacts with the ProgramCallDocument class. The ProgramCallDocument class uses your PCML source file to pass information between your Java application and the AS/400 programs.

Figure 1. Making program calls to the AS/400 using PCML.
Flow chart that outlines the process of creating a program call with PCML

When your application constructs the ProgramCallDocument object, the IBM XML parser reads and parses the PCML source file.

After the ProgramCallDocument class has been created, the application program uses the ProgramCallDocument class's methods to retrieve the necessary information from the AS/400 through the AS/400 distributed program call (DPC) server.

To increase run-time performance, the ProgramCallDocument class can be serialized during your product build time. The ProgramCallDocument is then constructed using the serialized file. In this case, the IBM XML parser is not used at run-time. Refer to Using serialized PCML files.

Using PCML source files

Your Java application uses PCML by constructing a ProgramCallDocument with a reference to the PCML source file. The ProgramCallDocument considers the PCML source file to be a Java resource. Consequently, the PCML source file is found using the Java CLASSPATH.

The following Java code constructs a ProgramCallDocument:

    AS400 as400 = new AS400();
    ProgramCallDocument pcmlDoc = new ProgramCallDocument(as400, "myPcmlDoc");
The ProgramCallDocument will look for your PCML source in a file called myPcmlDoc.pcml. Notice that the .pcml extension is not specified on the constructor.

If you are developing a Java application in a Java "package," you can package-qualify the name of the PCML resource:

    AS400 as400 = new AS400();
    ProgramCallDocument pcmlDoc = new ProgramCallDocument(as400, "com.company.package.myPcmlDoc");

Using serialized PCML files

To increase run-time performance, you can use a serialized PCML file. A serialized PCML file contains serialized Java objects representing the PCML. The objects that are serialized are the same objects that are created when you construct the ProgramCallDocument from a source file as described above.

Using serialized PCML files gives you better performance because the IBM XML parser is not needed at run-time to process the PCML tags.

The PCML can be serialized using either of the following methods:

If your PCML is in a source file named myDoc.pcml, the result of serialization is a file named myDoc.pcml.ser.

PCML source files vs. serialized PCML files

Consider the following code to construct a ProgramCallDocument:
    AS400 as400 = new AS400();
    ProgramCallDocument pcmlDoc = new ProgramCallDocument(as400, "com.mycompany.mypackage.myPcmlDoc");
The ProgramCallDocument constructor will first try to find a serialized PCML file named myPcmlDoc.pcml.ser in the com.mycompany.mypackage package in the Java CLASSPATH. If a serialized PCML file does not exist, the constructor will then try to find a PCML source file named myPcmlDoc.pcml in the com.mycompany.mypackage package in the Java CLASSPATH. If a PCML source file does not exist, an exception is thrown.

Qualified names

Your Java application uses the ProgramCallDocument.setValue() method to set input values for the AS/400 program being called. Likewise, your application uses the ProgramCallDocument.getValue() method to retrieve output values from the AS/400 program.

When accessing values from the ProgramCallDocument, you must specify the fully qualified name of the document element or <data> tag. The qualified name is a concatenation of the names of all the containing tags with each name separated by a period.

For example, given the following PCML source, the qualified name for the "nbrPolygons" item is "polytest.parm1.nbrPolygons". The qualified name for accessing the "x" value for one of the points in one of the polygons is "polytest.parm1.polygon.point.x".

If any one of the elements needed to make the qualified name is unnamed, all descendents of that element do not have a qualified name. Any elements that do not have a qualified name cannot be accessed from your Java program.

<pcml version="1.0">
  <program name="polytest" path="/QSYS.lib/MYLIB.lib/POLYTEST.pgm">
    <!-- Parameter 1 contains a count of polygoins along with an array of polygons -->
    <struct name="parm1" usage="inputoutput">
      <data name="nbrPolygons" type="int" length="4" init="5" />
      <!-- Each polygon contains a count of the number of points along with an array of points -->
      <struct name="polygon" count="nbrPolygons">
        <data name="nbrPoints" type="int" length="4" init="3" />
        <struct name="point" count="nbrPoints" >
          <data name="x" type="int" length="4" init="100" />
          <data name="y" type="int" length="4" init="200" />
        </struct>
      </struct>
    </struct>
  </program>
</pcml>

Accessing data in arrays

Any <data> or <struct> element can be defined as an array using the count attribute. Or, a <data> or <struct> element can be contained within another <struct> element that is defined as an array.

Furthermore, a <data> or <struct> element can be in a multidimensional array if more than one containing element has a count attribute specified.

In order for your application to set or get values defined as an array or defined within an array, you must specify the array index for each dimension of the array. The array indices are passed as an array of int values. Given the source for the array of polygons shown above, the following Java code can be used to retrieve the information about the polygons:

    ProgramCallDocument polytest; // Initialized elsewhere
    Integer nbrPolygons, nbrPoints, pointX, pointY;
    nbrPolygons = (Integer) polytest.getValue("polytest.parm1.nbrPolygons");
    System.out.println("Number of polygons:" + nbrPolygons);
    indices = new int[2];
    for (int polygon = 0; polygon < nbrPolygons.intValue(); polygon++) 
    {
        indices[0] = polygon;
        nbrPoints = (Integer) polytest.getValue("polytest.parm1.polygon.nbrPoints", indices );
        System.out.println("  Number of points:" + nbrPoints);

        for (int point = 0; point < nbrPoints.intValue(); point++) 
        {
            indices[1] = point;
            pointX = (Integer) polytest.getValue("polytest.parm1.polygon.point.x", indices );
            pointY = (Integer) polytest.getValue("polytest.parm1.polygon.point.y", indices );
            System.out.println("    X:" + pointX + " Y:" + pointY);
        }
    }

Debugging

When you use PCML to call programs with complex data structures, it is easy to have errors in your PCML that result in exceptions from the ProgramCallDocument class. If the errors are related to incorrectly describing offsets and lengths of data, the exceptions can be difficult to debug.

The com.ibm.as400.data.PcmlMessageLog class allows you to turn on a tracing function that prints to the standard output stream information that can be helpful in problem determination. You can call the following method to turn the tracing function on:

    com.ibm.as400.data.PcmlMessageLog.setTraceEnabled(true);

When the tracing function is turned on, the following types of information are printed to the standard output stream:

End change


[ Legal | AS/400 Glossary ]