Other parts of this material show how to expose ILE programs through industry standard methods such as XML or JSON web services, SSH, and TCP/IP sockets. Java applications work comfortably with those protocols. Beyond the standard approaches there are several direct ways for Java to call or work with ILE code. This section walks through the most common and practical techniques.

IBM Toolbox for Java

The IBM Toolbox for Java (part of the JTOpen family) is the most popular route for calling ILE from Java. It gives you a solid set of classes that let a Java program reach almost anything on IBM i.

With the toolbox you can:

  • Run CL commands
  • Call programs and service programs
  • Access DB2 for i through JDBC or record level access
  • Work with IFS files, spooled files, data queues, environment variables, system values, users, jobs, user spaces and more

Because everything runs over TCP/IP, the same code works for remote or multi tier solutions. Many IBM products are built on top of the toolbox.

You can download JTOpen | Overview but it is also shipped free with the JC1 licensed program. The JAR files land in /QIBM/ProdData/HTTP/Public/jt400/lib/. The two files you care about most are:

  • jt400.jar – the standard cross platform APIs
  • jt400Native.jar – the same APIs with extra optimisations when the Java code runs on IBM i itself

A quick start with the toolbox

Almost everything begins with an AS400 connection object.

AS400 as400 = new AS400();
as400.setSystemName("mySystem");
as400.setUserId("myUID");
as400.setPassword("myPWD");

// or the shorter form
AS400 as400_2 = new AS400("mySystem", "myUID", "myPWD");

Once you have the connection you can create the other objects you need.

Running a simple command

CommandCall cc = new CommandCall(as400);
try {
    boolean isSuccessful = cc.run("CRTLIB FRED");
    // check isSuccessful
    for (AS400Message msg : cc.getMessageList()) {
        // handle messages
    }
} catch (Exception e) {
    log(e);
}

Calling a service program with ServiceProgramCall

The ServiceProgramCall class lets you invoke procedures inside an ILE service program. You must know the parameter types and whether they are passed by value or by reference.

Here is a complete example that passes two zoned decimal values by reference:

ProgramParameter[] parmList = new ProgramParameter[2];

// Input parameter
AS400ZonedDecimal tempVar = new AS400ZonedDecimal(10, 2);
// Output parameter
AS400ZonedDecimal outVar = new AS400ZonedDecimal(10, 2);

// "inParam" is a BigDecimal passed into this method
parmList[0] = new ProgramParameter(
    ProgramParameter.PASS_BY_REFERENCE,
    tempVar.toBytes(inParam));
parmList[1] = new ProgramParameter(
    ProgramParameter.PASS_BY_REFERENCE, 10);

ServiceProgramCall svcpgm = new ServiceProgramCall(conn);
svcpgm.setProgram(
    "/QSYS.lib/FLGHT400C.lib/SMPLAPISVC.srvpgm", parmList);
svcpgm.setProcedureName("CONVERTTEMP");

if (svcpgm.run() == false) {
    AS400Message[] msgs = svcpgm.getMessageList();
    for (int i = 0; i < msgs.length; ++i) {
        System.out.println(msgs[i].getID() + ": " + msgs[i].getText());
    }
} else {
    byte[] outData = parmList[1].getOutputData();
    BigDecimal outParam = (BigDecimal) outVar.toObject(outData);
    // use outParam
}

The toolbox supplies a family of helper classes that map Java types to IBM i data types. The most common ones are:

Java data typeIBM i data type
Object[]Array
short2 byte binary
int4 byte binary
long8 byte binary
byte[]Byte array
float4 byte floating point
double8 byte floating point
BigDecimalPacked decimal
BigDecimalZoned decimal
Object[]Structure
StringText

The toolbox takes care of code page conversion, byte order and the actual data movement for you.

Using PCML to simplify the call

Instead of coding every data type in Java you can let the compiler generate PCML (an XML description of the parameters) when you build the ILE service program. The toolbox then reads that description.

Example PCML:

<pcml version="4.0">
  <program name="CONVERTTEMP" entrypoint="CONVERTTEMP"
           path="/QSYS.lib/FLGHT400C.lib/SMPLAPISVC.srvpgm">
    <data name="TEMPIN"  type="zoned" length="10" precision="2" usage="input" />
    <data name="TEMPOUT" type="zoned" length="10" precision="2" usage="output" />
  </program>
</pcml>

Calling it becomes much cleaner:

ProgramCallDocument pcmlDoc =
    new ProgramCallDocument(conn, "com.ibm.sample.pcall.simpleapi");

pcmlDoc.setValue("CONVERTTEMP.TEMPIN", inParam);
boolean result = pcmlDoc.callProgram("CONVERTTEMP");

if (!result) {
    AS400Message[] msgs = pcmlDoc.getMessageList("CONVERTTEMP");
    // handle errors
} else {
    BigDecimal outParam =
        (BigDecimal) pcmlDoc.getValue("CONVERTTEMP.TEMPOUT");
    // use outParam
}

If the service program signature changes you only update the PCML. The Java code stays the same.

*Calling a regular PGM with ProgramCall

ProgramCall works almost exactly like ServiceProgramCall. The only difference is that it targets a program object instead of a service program procedure. The same parameter classes and PCML support apply.

Calling SQL stored procedures through JDBC

Another clean route is to wrap the ILE logic in an SQL stored procedure and call it with ordinary JDBC. This approach has a few advantages:

  • You can pass up to 1 024 parameters (Toolbox ProgramCall is limited to 35, ServiceProgramCall to 7)
  • The procedure can return a result set of any size
  • You stay inside the familiar JDBC world

You do need to know how to write and register the stored procedure, but once that is done the Java side is straightforward.

Using Data Queues

Data queues remain a solid, language neutral way for programs to talk to each other. The toolbox gives full support for both sequential and keyed data queues, LIFO or FIFO ordering, and non destructive peeks.

Example that writes a simple customer record:

AS400 conn = // obtain connection

BinaryFieldDescription custNumberField =
    new BinaryFieldDescription(new AS400Bin4(), "CUSTOMER_NUMBER");
CharacterFieldDescription custNameField =
    new CharacterFieldDescription(new AS400Text(50, conn), "CUSTOMER_NAME");

RecordFormat sampleRecord = new RecordFormat();
sampleRecord.addFieldDescription(custNumberField);
sampleRecord.addFieldDescription(custNameField);

DataQueue dq = new DataQueue(conn,
    "/QSYS.LIB/FLGHT400C.LIB/CUSTINFO.DTAQ");

try {
    dq.create(96);          // max entry size 96 bytes
} catch (ObjectAlreadyExistsException e) {
    // already exists – fine
}

Record data = new Record(sampleRecord);
data.setField("CUSTOMER_NUMBER", Integer.valueOf(customerNumber));
data.setField("CUSTOMER_NAME", customerName);

byte[] byteData = data.getContents();
dq.write(byteData);

JTOpenLite

JTOpen also ships a much smaller package called JTOpenLite (jtopenlite.jar). It offers a lighter set of APIs for programs, service programs, IFS, commands, a lightweight JDBC driver and record level access.

Reasons you might choose it:

  • Smaller JAR and smaller memory footprint
  • Some operations run faster
  • It works well for native Android applications

Command call example with JTOpenLite:

CommandConnection cc =
    CommandConnection.getConnection("mySystem", "myUID", "myPWD");
CommandResult result = cc.execute("CRTLIB FRED");
boolean isSuccessful = result.succeeded();

for (Message msg : result.getMessages()) {
    // handle messages
}

Java Native Interface (JNI)

JNI is the most powerful (and most complex) integration path. You write native methods in ILE RPG or C that can be called directly from Java, and from the ILE side you can reach back into the running JVM, create Java objects, call Java methods and manipulate arrays. It is true two way integration, but it requires more care than the Toolbox approaches.

Runtime.exec()

Finally, plain Java gives you Runtime.exec(). Because Java on IBM i runs in PASE you can use the PASE system utility to fire CL commands or CALL a program:

Process p = Runtime.getRuntime().exec(
    "system \"CALL PGM(MYLIB/MYPROGRAM)\"");

OutputStream stdin  = p.getOutputStream();
InputStream  stdout = p.getInputStream();
InputStream  stderr = p.getErrorStream();

This is the quickest method when you only need to launch something and do not need rich parameter handling. It only works when the Java code itself is running on IBM i.

Those are the main practical routes from Java into ILE. Most shops start with the IBM Toolbox for Java because it is mature, well documented and covers almost every common requirement.

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>