IBM i bindings

EGL code that is generated to Java can access IBM® i called programs, as well as procedures in IBM service programs. The language also supports access of those programs from a Rich UI application, by way of an EGL service type generated to Java.
Sections in this topic are as follows:

Use of the JTOpen Toolkit

Direct access to IBM i host programs is by way of the JTOpen toolkit, which determines what program types are supported. Details on that toolkit are here: JTOpen (http://jt400.sourceforge.net/).

Two cases apply:
  • The EDT nightly build includes the JTOpen toolkit and makes it available at development time.

    When you deploy code that requires use of the toolkit, the EGL deployer places the JTOpen jar file (org.jtopen_0.8.1.jar) in the WebContent/WEB-INF/lib folder.

  • Neither the EDT 0.80 version nor the EDT 0.81 milestone builds include the toolkit.
    Here is the prerequisite task for those versions:
    1. Download the toolkit: JTOpen (http://jt400.sourceforge.net/).
    2. Extract the jt400.jar file.
    3. Reference that file in the Java class path.
    4. Add the jar file to the classpath of the server that will receive your deployed application. For example, during EGL deployment, you might add the file to the lib folder of the target project.

In either case, when you deploy your code outside of the IDE, you might need to add the JTOpen jar file as a resource in the server classpath.

Development overview

Your coding task has the following aspects:
  • You write an EGL proxy function. In relation to IBM i, the proxy function might be in any of the following types: an EGL Library, Service, Program, or Handler. The function has no logic, and any logic you place there will be ignored. Instead, you include one or more annotations.

    As in service access, the main annotations in the EGL proxy function are Resource, which tells "where" the backend code resides, and a second annotation that tells "what more" is required by the EGL generator. The "what more" annotation for IBM i is IBMiProgram.

    One runtime effect of referencing a resource binding is that you gain the performance benefits of using a connection from the AS400 connection pool.

  • When you write the EGL code that calls the function, you might access the proxy function and rely on the details provided there. Two variations apply:
    • If you access the function remotely, you cannot override the Resource annotation. At this time, remote access is possible only from a Rich UI application.
    • If access the function locally in generated Java code, you might do as follows:
      1. Code a binding variable that references a different resource binding or that specifies new detail.
      2. Refer to that variable in the using clause of the call statement.

      When you include a using clause, the coded detail overrides the Resource annotation. If the using clause references a different deployment-descriptor entry, you still gain the performance benefits of using a pooled connection. However, the using clause might represent a connection that you define in your code; and in that case, you typically do not use a pooled connection, but rely on the AS400 connection object that is available in the JTOpen toolkit.

  • The parameters of the EGL proxy function represent the parameters of the host program, and your call can pass simple data, as well as records and handlers. If a value is returned from the proxy function, the type of value is an EGL Int. (On IBM i, a return value is possible from a service program but not from a called program.)

In general, a Rich UI application uses an asynchronous version of the call statement to get enterprise data from a service. In relation to an IBM i program, the application calls a public proxy function that is defined in an EGL Service type.

Runtime process

At run time, the proxy function is an endpoint for accessing an IBM i program. That function acts as follows:
  1. Retrieves a connection for the AS400 connection pool, if you are using that kind of connection.
  2. Converts your data from an EGL format to byte arrays. The structure of those arrays is based on a set of AS400DataType classes that are provided by the JTOpen toolkit.
  3. Creates a JTOpen ProgramCall or ServiceProgramCall object, depending on whether the call is to an IBM i called program or service program.
  4. Creates JTOpen ProgramParameter objects and passes the byte arrays to them.
  5. Calls the host program by calling the run method on the ProgramCall or ServiceProgramCall object.
  6. Reformats the returned value (if any) to EGL format.
  7. Converts the returned byte arrays to EGL format. The structure of those arrays is based on a set of AS400DataType classes that are provided by the JTOpen toolkit.
  8. Returns the connection to the AS400 connection pool, if you are using that kind of connection.

Coding details

The objects expected by the host are based on fixed-size types, whereas many EGL types are variably sized. You handle the difference by annotating the variably sized objects.

The annotations you specify are in the eglx.jtopen.annotations package, with annotation type names that of the form Structxxxx. The xxxx part of an annotation type name correspond to a class name in the JTOpen com.ibm.as400.access.AS400Datatype package.

To determine which annotations to specify, refer to the table shown later, along with the Javadoc for the com.ibm.as400.access.AS400Datatype classes.

EGL proxy function for IBM i

Here is an example of an EGL proxy function, including the annotations named ExternalName and IBMiProgram:
function GETRECA(CUST CUST[] inout, 
                 EOF   string inout, 
                 COUNT decimal (2,0) inout) 
   {
      @ExternalName{value="MyHostProc"},
      
      @Resource{uri = "binding:file:EGLDDFile#MyConnection"},
      
      @IBMiProgram {         
         programName = "GETREC",
         libraryName = "/QSYS.LIB/VARLABXX.LIB/",
         isServiceProgram=true,
         parameterAnnotations = [
            @AS400Array{elementCount = 10},
            @AS400Text{length = 1},
           	null 
         ]
      }
   }
end   

The ExternalName annotation is optional. It holds the name of the IBM i procedure and defaults to the name of the EGL proxy function.

The Resource annotation is optional. It provides a default value; specifically, a reference to a binding that is defined in the EGL deployment descriptor. See the earlier "Development overview" section for details about the different implications of a local and remote call. Also note that any value specified in the library field of the deployment descriptor entry replaces the library field in the IBMiProgram annotation, which is the primary annotation that structures the call.

The IBMiProgram is the primary annotation that structures the call. The annotation holds the following detail:
  • The path of the library and program on IBM i.

    You can specify both details on the programName field; in the current example, the field value would be "/QSYS.LIB/VARLABXX.LIB/GETREC". In any case, the EGL runtime code appends a file extension to the value of the programName field: .SRVPGM for service programs, .PGM for called programs.

  • A flag as to whether a service program is being invoked.
  • Annotations for each parameter, as described later.

Annotations for data conversion

The data-conversion annotations cause the use of converters that are found in the following JTOpen package: com.ibm.as400.access. The EGL annotation is similar to the Java class name: the annotation name begins with "Struct" and ends with a substring such as "Bin4." The use of the more general "Struct" substring in place of "AS400" facilitates the future use of System z or other backend code.

When you set a value for the parameterAnnotations field, you specify an annotation or the null keyword for every annotation:
  • Values of simple reference types require an annotation. Example types are String, Decimal, and Timestamp.
  • Values of simple value types require an annotation only if you do not want to accept the defaults. Example types are String(7), Decimal (5,2), and Timestamp("yyyyMMddHHmm").
  • Lists require a parameter annotation.
  • null is always used for a variable that is based on a Record or Handler type.

If you do not set a value for the parameterAnnotations field, the defaults are used for every parameter.

Equivalent rules are in effect for the fields that are in a container; that is, in a variable that is based on a Record or Handler type. For example, here is a Record type with annotations:
Record Example

   //Convert using the default StructBin4
   f1 int;

   //After the host program call, f2 is resized using the data returned in f3
   f2 int[]{@StructArray{elementCount = 10, returnCountVariable = f3}};

   //A fixed text with a length 2 characters using the default encoding
   f3 string{@StructText{length = 2}};

   //Convert a number to a StructDecFloat
   f4 number?{@StructDecFloat{length = 34}};

   //Convert using the default StructPackedDecimal
   f5 decimal(10,2);

   //Convert using the StructZonedDecimal
   f6 decimal(10,4){@StructZonedDecimal{}};
end

If that Record type included a record, you would not specify an annotation for the included record, but might specify annotations for the fields in that record.

Call statements

You write a call statement to invoke the EGL proxy function. A using clause, if present, refers to a connection. If a using clause is not present in the call statement or if the call statement is in a Rich UI application, the proxy function must reference a deployment descriptor entry.

Consider the following proxy function, which resides in an EGL Program type:
Program TestSimpleProgram

   //On IBM i, only service programs support a return
   function MyHostProcedure(p1 string, p2 string)RETURNS(INT)
   {
      @Resource{ uri = "binding:someEntry" },
      @IBMiProgram{
         programName = "/QSYS.LIB/VARLABXX.LIB/GETREC",
         isServiceProgram= true,
         parameterAnnotations = [@StructText{length = 10}, @StructText{length = 10}]
      }
   }
   end

   function main()
      
   end
end
Here is a call from another function in the same program, including reference to a Customer Record type. The call relies on the binding detail that was just shown in the Resource annotation:
cust Customer;
result Int;
myString String = "abc";
try
   call MyHostProcedure(myString, cust) returns (result);
   onexception(exception AnyException)
	    //handle exception
end

Here is an alternative call, which provides binding detail that overrides the binding detail, if any, that is specified in the proxy function:

cust Customer;
result int;
myString String = "abc";
conn IBMiConnection? = Resource.getResource("binding:someOtherConnection");
try
   call MyHostProcedure(myString, cust) 
      using conn
      returns (result);
   onexception(exception AnyException)
	     //handle exception
end
The following code is equivalent to the previous logic:
cust Customer;
result int;
myString String = "abc";
try
   call MyHostProcedure(myString, cust) 
      using Resource.getResource("binding:someOtherConnection") 
         as IBMiConnection
      returns (result);
   onexception(exception AnyException)
	     //handle exception
end
Here is yet another alternative call, which might provide a value of type IBMiConnection instead of referencing the EGL deployment descriptor:
cust Customer;
result int;
myString String = "abc";

conn IBMiConnection? = getMyDefinedConnection();
try
   call MyHostProcedure(myString, cust) 
      using conn
      returns (result);
   onexception(exception AnyException)
   //handle exception
end
If you want to access the AS400 connection pool from your code, you also assign connection detail to a variable of type IBMiConnection; but for that purpose, you invoke the static Java function that is referenced in the following EGL external type:
externalType JTOpenConnections type JavaObject
   private constructor();
   static function getAS400ConnectionPool()returns(AS400ConnectionPool);
end

For details on that function, see the JTOpen documentation for the AS400ConnectionPool object.

Fields in the EGL deployment descriptor entry

You can set a variety of fields in the EGL deployment descriptor entry. The type of each entry is AS400Connection, which is compatible with the IBMiConnection type that is used in the code examples.

You can use the fields in the deployment descriptor to override default behavior. In addition, you can set annotations on a field or parameter that is being passed to the proxy function, and that annotation overrides all other settings.

Here are the fields of the deployment descriptor entry:
dateFormat
The date format for AS400Date objects.

This value overrides the default date format, which is com.ibm.as400.access.AS400Date.FORMAT_ISO. The format specifies a separator character, but that character can be overridden; for details, see dateSeparator.

dateSeparator
The date separator for AS400Date objects.

This value overrides the date separator that is specified in the dateFormat field value.

encoding
The character encoding for AS400Text objects.

This value overrides the default encoding, which is obtained from the CCSID value of the AS400 connection.

library
The library where the program is located. If you specify a value for this field, you replace any value specified in the IBMiProgram annotation, library field.
password
The password for the specified user ID.
system
The IBM i system name.
timeFormat
The time format for AS400Time objects.

This value overrides the default time format, which is com.ibm.as400.access.AS400Time.FORMAT_ISO. The format specifies a separator character, but that character can be overridden; for details, see timeSeparator.

timeSeparator
The time separator for AS400Time objects.

This value overrides the date separator that is specified in the timeFormat field value.

timeZone
The time zone for AS400Date, AS400Time, and AS400Timestamp objects.

This value overrides the default time zone, which is obtained from the timezone value of the AS400 connection.

userid
The user ID that provides access to the IBM i system.

For more detail on what input is valid, see the annotation-specific entries in the next section.

Reference details for the data-conversion annotations

If you download the JTOpen from the web page listed at the start of this topic, you can review the Javadoc for the classes that convert data between EGL and IBM i. The following web page provides similar detail, but might be out of date:
In the following table, the name of each EGL annotation is related to the name of the corresponding Java class in the JTOpen com.ibm.as400.access package, with the EGL "Struct" substring in place of the JTOpen "AS400" substring.
EGL type EGL annotation Annotation fields
bigint StructBin8 (the default) or StructUnsignedBin4.
bytes (not yet supported) StructArray For a non-parameterized bytes type:
length
Total number of bytes.
date StructDate
ibmiFormat
Controls the conversion to an IBM i date format. You can specify a field of the following class: com.ibm.as400.access.AS400Date.

An example field is com.ibm.as400.access.AS400Date.FORMAT_USA.

The default format is com.ibm.as400.access.AS400Date.FORMAT_ISO.

ibmiSeparatorChar
One of the following values: "&" (ampersand), " " (blank), "," (comma), "-" (hyphen), "." (period), "/" (forward slash), or null. The null indicates no separator.

For details on what characters are valid for a given format, see the IBM i programming reference.

ibmiTimezoneID
The timezone for the host variable.

For details on what characters are valid, see the Java documentation for the java.util.TimeZone class.

decimal StructPackedDecimal; StructZonedDecimal; or StructDecFloat. For a non-parameterized decimal type:
length
Total number of digits. For the StructDecFloat annotation, the value must be 16 or 34.
decimals
Number of decimal places. For the StructDecFloat annotation, this field is not available.

See the paragraph after this table.

float AS400Float8 (the default).  
Handler types No annotation. Conversion is controlled by the AS400Structure Java class.  
int StructBin4 (the default) or StructUnsignedBin2.  
List types StructArray (the default).

You must specify the annotation if you need to use any of the annotation fields. None of those fields has a default value.

For examples, see a later section.

elementCount

The number of elements in the list that is sent to the host.

The elementCount field is necessary because host programs do not support EGL lists, which can change in size at run time. The host program handles only fixed-length arrays.

In COBOL terms, the value of elementCount is an occurs value.

elementTypeAnnotation
Takes the value of another annotation, to guide the conversion of the elements. See the examples in a later section.
returnCountVariable
Many host programs return a variable that defines how many valid elements are in the structured array. This field is used to by the runtime code to resize the returned array so that only the valid elements are returned to the application.

The field definition must be in the context of the record, handler or function where the array is defined. If you are annotating a parameter, the variable referenced by this annotation field must be a parameter. If you are annotating a record or handler, the referenced variable must be a field in that record or handler.

This field is not supported for multidimensional lists.

Record types No annotation. Conversion is controlled by the AS400Structure Java class.  
string StructText (the default). For a non-parameterized string type:
length
Total number of bytes.
For any string type:
encoding
The name of a character encoding.
preserveTrailingSpaces
A boolean value that indicates whether to retain whitespace at the right side of the string. The default is false.

See the paragraph after this table.

smallfloat StructFloat4 (the default).  
smallint StructBin2 (the default), StructBin1, or StructUnsignedBin1.  
time StructTime (the default).
ibmiFormat
Controls the conversion to an IBM i time format. You can specify a field of the following class: com.ibm.as400.access.AS400Time.

An example field is com.ibm.as400.access.AS400Time.FORMAT_USA.

The default format is com.ibm.as400.access.AS400Time.FORMAT_ISO.

ibmiSeparatorChar
One of the following values: "&" (ampersand), " " (blank), "," (comma), ":" (colon), "." (period), or null. The null indicates no separator.

For details on what characters are valid for a given format, see the IBM i programming reference.

ibmiTimezoneID
The timezone for the host variable.

For details on what characters are valid, see the Java documentation for the java.util.TimeZone class.

timestamp StructTimestamp (the default). The conversion to an IBM i timestamp format is in accordance with the Java FORMAT_DEFAULT field in the following class: com.ibm.as400.access.AS400Timestamp.
eglPattern
Controls the conversion back to an EGL format. For details on the patterns, see the following help topic: "Pattern characters used to format non-string values to strings."
ibmiTimezoneID
The timezone for the host variable.

For details on what characters are valid, see the Java documentation for the java.util.TimeZone class.

To fulfill the need for fixed-length values on IBM i, you must specify the parameters such as length for types that might be parameterized (such as Decimal (5,2)) or non-parameterized (such as Decimal):
  • For parameterized types, rely on the type definition to set those parameters. Assignment to the related annotation fields are not valid. However, if you use the StructDecFloat annotation, you must set the length annotation field.
  • For non-parameterized types, assign values to the annotation fields.

The following types can be parameterized: Bytes, Decimal, String, Timestamp.

Example annotations for lists

Here is an example of how you might annotate lists in a Record or Handler type:
f1 String[]
   {@StructArray{elementCount = 10, 
                elementTypeAnnotation = @StructText{length= 25},
                returnCountVariable = f3}};
f2 Int[] = new Int[5]{@StructArray{elementCount = 5}}; 
f3 Int;
Here is an explanation:
  • The StructArray annotation guides the conversion of the f1 field. The list will include 10 elements at run time, and the StructText annotation guides the conversion of the elements, which are of length 25. The f3 field contains the number of elements to accept when f1 is assigned the values that are returned from IBM i.
  • The StructArray also guides the conversion of the f2 field. The list will include 5 elements at run time. By default, the StructBin4 annotation guides the conversion of each element.
Here is an example of how you might annotate parameters of an EGL proxy function:
function TEST(length1 String, f1 String[], f2 String[] ){
   @IBMiProgram{
      programName = "/QSYS.LIB/VARLABXX.LIB/GETREC",
      parameterAnnotations = [
         @StructText{length=2},
         @StructArray{elementCount = 10, 
                     elementTypeAnnotation = @StructText{length= 25},
                     returnCountVariable = length1},
                     @StructArray{
                        elementCount = 5, 
                        elementTypeAnnotation = @StructText{length= 10}
            }
         }
      ]
   }
Here is an explanation:
  • The StructText annotation guides the conversion of the length1 field. The field length is 2 characters.
  • The StructArray annotation guides the conversion of the f1 field. The list will include 10 elements at run time, and the StructText annotation guides the conversion of the elements, which are of length 25. The length1 field contains the number of elements to accept when f1 is assigned the values that are returned from IBM i.

    Any value that is used to resize an array must be assignment compatible with an EGL int. An example is length1, which is of type String.

Current restrictions

At this writing, the following capabilities are not supported:
  • Values of type Bytes.
  • Parameterized strings.
  • Multidimensional lists.