The TABLEMANAGER object provided by aXes allows you to call RPG or CL programs directly from eXtension JavaScript. The programs that you call need to be thread safe. See the end of this section for more details. Typically the calls are made when a button or hyperlink is clicked.

Example 1 – Call with no parameters

Server CL program

This small CL program named LOTST009 sends a message to the system history log:

PGM

SNDPGMMSG MSG('Hello from LOTST009') TOMSGQ(QHST)

ENDPGM

Button onClick JavaScript coding in Axes

TABLEMANAGER.callProgram("LOTST009","QGPL");

Result

Display the system history log (DSPLOG command) and locate message "Hello from LOTST009".

Example 2 – Call with one parameter

Server CL program

This small CL program named LOTST011 sends a message to the system history log. The message text is passed into the program as a parameter.

PGM (&MSG)

DCL &MSG *CHAR 132

SNDPGMMSG MSG(&MSG) TOMSGQ(QHST)

ENDPGM

Button onClick JavaScript coding in Axes

TABLEMANAGER.callProgram("LOTST011","QGPL",{type:"alpha",len:132,value:"This is a test message"} );

Result

Display the system history log (DSPLOG command) and locate message "This is a test message".

Example 3 – Call with a returned value

Server CL program

This small CL program named LOTST001 concatenates two alpha parameters and returns the result.

PGM (&P1 &P2 &P3)

DCL &P1 *CHAR 10

DCL &P2 *CHAR 10

DCL &P3 *CHAR 20

CHGVAR &P3 (&P1 *CAT &P2)

ENDPGM

Button onClick JavaScript coding in Axes

var result = TABLEMANAGER.callProgram("LOTST001","QGPL",

{type:"alpha",len:10,value:"Hello"},

{type:"alpha",len:10,value:"World"},

{type:"alpha",len:20,pass:false,ret:true} );

if (result.error) alert("Call Failed");

else alert(result.returnParms[3]);

Result

Image

Example 4 – Numeric Parameters passed and returned

Server CL program

This small CL program named LOTST002 adds up 3 packed decimal parameters and returns the result.

PGM (&P1 &P2 &P3 &P4)

DCL &P1 *DEC (7 0)

DCL &P2 *DEC (9 2)

DCL &P3 *DEC (12 5)

DCL &P4 *DEC (15 5)

CHGVAR &P4 (&P1 + &P2 + &P3)

ENDPGM

Button onClick JavaScript coding in Axes

var result = TABLEMANAGER.callProgram("LOTST002","QGPL",

{ type:"packed",len:7,dec:0,value: 4 },

{ type:"packed",len:9,dec:2,value: 7.7 },

{ type:"packed",len:12,dec:5,value: 820.12345 },

{ type:"packed",len:15,dec:5,pass:false,ret:true } );

if (result.error) alert("Call Failed");

else

{

var strp4 = result.returnParms[4]; /* Should be 831.82345 as string */

var intp4 = parseInt(strp4,10) + 42; /* Should be 831 + 42 = 873 */

var floatp4 = parseFloat(strp4) + 123.75868; /* Should be 955.58213 as float */

alert("strp4=" + strp4 + ", intp4=" + intp4.toString() + ", floatp4=" + floatp4.toString());

}

Result

Image

Note that the returned parameter (strP4) is a always a string. By using the standard JavaScript functions parseInt() and parseFloat() it can easily be converted to a number for further manipulation by JavaScript code.

Example 5 – Value Passed and Returned in same Parm

Server CL program

This small CL program named LOTST005 sends a message to the system operator and returns "OKAY":

PGM (&P1)

DCL &P1 *CHAR 20

SNDMSG MSG(&P1) TOMSGQ(QSYSOPR)

CHGVAR &P1 'OKAY'

ENDPGM

Button onClick JavaScript coding in Axes

var message = "Hello from LOTST005";

var result = TABLEMANAGER.callProgram("LOTST005","QGPL",

{type:"alpha",len:20,pass:true,ret:true,value:message} );

if (result.error) alert("Call Failed");

else alert(result.returnParms[1]);

Result

Image

Example 6 – Multiple Values Passed and Returned

Server CL program

This small CL program named LOTST007 receives and returns multiple parameters:

PGM (&P1 &P2 &P3 &P4)

DCL &P1 *CHAR 10

DCL &P2 *CHAR 10

DCL &P3 *CHAR 20

DCL &P4 *CHAR 10

CHGVAR &P3 (&P1 *CAT &P2)

CHGVAR &P4 'OKAY'

ENDPGM

Button onClick JavaScript coding in Axes

var p1 = "JavaScript";

var p2 = "is Good";

var result = TABLEMANAGER.callProgram("LOTST007","QGPL",

{ type:"alpha",len:10,pass:true,value:p1 },

{ type:"alpha",len:10,pass:true,value:p2 },

{ type:"alpha",len:20,pass:false,ret:true },

{ type:"alpha",len:10,pass:false,ret:true } );

if (result.error) alert("Call Failed");

else

{

var p3 = result.returnParms[3];

var p4 = result.returnParms[4];

alert("p3=" + p3 + ", p4=" + p4);

}

Result

Image

Example 7 – Multiple Values Returned in One Parameter

Server CL program

This small CL program named LOTST010 returns a 2000 byte string containing the aXes server's job name, user profile, job number and current output queue. The returned information is formatted as a JSON string. This program is the tip of a very large iceberg of possibility.

PGM (&JSON)

DCL &JSON *CHAR 2000

DCL &JOB *CHAR 10

DCL &USER *CHAR 10

DCL &JOBNBR *CHAR 6

DCL &OUTQ *CHAR 10

RTVJOBA JOB(&JOB) USER(&USER) NBR(&JOBNBR) OUTQ(&OUTQ)

CHGVAR &JSON (' JOB:"' || &JOB |< '"')

CHGVAR &JSON (&JSON |< ',JOBNBR:"' || &JOBNBR |< '"')

CHGVAR &JSON (&JSON |< ',USER:"' || &USER |< '"')

CHGVAR &JSON (&JSON |< ',OUTQ:"' || &OUTQ |< '"')

ENDPGM

Button onClick JavaScript coding in Axes – Stage 1

var result = TABLEMANAGER.callProgram("LOTST010","QGPL",{type:"alpha",len:2000,pass:false,ret:true});

alert( result.returnParms[1] );

Result Stage 1

Image

The CL program LOTST010 is executed and it returns a long string with the job name, job number, user and output queue all imbedded in it.

In effect LOTST010 has returned 4 values, but done it using a single program parameter.

Note how the returned string is formatted in much the same way as the program arguments are specified in JavaScript - type:"alpha",len:2000,pass:false,ret:true

Button onClick JavaScript coding in Axes – Stage 2

var result = TABLEMANAGER.callProgram("LOTST010","QGPL",{type:"alpha",len:2000,pass:false,ret:true});

try

{

var Info = eval( "({" + result.returnParms[1] + "})" )

window.alert("Job=" + Info.JOB + ", Job Number=" + Info.JOBNBR + ", User=" + Info.USER + ",Output Queue=" + Info.OUTQ);

}

catch (oe)

{

window.alert( "Error " + oe.description + " detected when loading JSON data " + result.returnParms[1] );

}

Result Stage 2

Image

The CL program LOTST010 is executed and it returns a long string with the job name, job number, user and output queue all imbedded in it.

The value returned is in JSON string format.

The returned value is executed by using a JavaScript eval operation to create a JavaScript object named Info.

Now the properties Info.JOB, Info.JOBNBR, , Info.USER and Info.OUTQ are all accessible to the JavaScript code. In effect the 4 values returned by CL program LOTST010 are now individually accessible as JavaScript object properties.

The JSON interface format is a driving part of the Web 2.0 / AJAX technologies. Some of the reasons it is very useful include:

  • You can alter CL program LOTST010 to return more values at any time. This would not upset any existing JavaScript calls to LOTST010. That would not be true if you were using traditional parameters – every caller would need to change.
  • Your JavaScript can easily check whether the version of LOTST010 that it called has actually returned a property by coding, say,

var UseJobSize = 42; /* Set the default value this thing */

if (Info.JOBSIZE != null) UseJobSize = Info.JOBSIZE; /* Server value provided */

to decide whether LOTST010 returned a value named JOBSIZE.

  • The JSON string you return can be much more complex in nature and include lists, arrays, structures, etc. All of these are instantly accessible to your JavaScript code.

Usage Rules, Guidelines and Tips

The server side program calls are not performed in the same job as the 5250 session. They are initiated from within the aXes server job.

The calls are performed under the user profile that the aXes server jobs run under – not under the user profile who started the 5250 session. However, you can call a CL program that submits jobs for execution under 5250 users profile. See the IBM i SBMJOB command and the concept of job descriptions.

The calls are performed in a multi-threaded process. This means that all resources are shared with all the other active threads - which may also be executing concurrent call operations.

Some of the things that this means include:

You have only 1 QTEMP library that is shared by all threads in the process (ie: IBM i server job).

The IBM i library list concept cannot be practically used. If you change the job's library list then a millisecond later another thread may alter it to something else. You have to use library qualified reference to most IBM i objects. Implement a design such that the client USERENV object knows the library name(s) associated with the 5250 user and pass them to the server program(s) as parameters so that all object references are fully qualified.

Your CL and RPG programs need to be compiled to be thread safe. Generally programs should be compiled using the CRTBNDCL or CRTBNDRPG commands. RPG programs probably need to use the THREAD(*SERIALIZE) control specification option. You should also review all IBM supplied documentation for executing multi-threaded RPG and CL programs before using this aXes feature.

Your CL and RPG programs cannot open a 5250 display file because they are not executing in a context where they are associated with a 5250 device.

Your CL and RPG programs need to be robust. They need to trap errors and handle them gracefully releasing all open or allocated resources.

Your CL and RPG programs need to be symmetrical in resource usage. Basically this means that if something is opened, locked or allocated as the program is executing it always it needs to be symmetrically closed, unlocked or de-allocated as the program is terminating.

Your server programs need to be stateless between each call. This means they must terminate (set on LR in RPG terminology) at the end of every call and cannot remember values between calls in their variables nor leave any resource open or allocated. Where a stateful design is required, typically a unique token or some sort of session id is assigned by the server that can be used to save and restore state on each call.

Your CL and RPG programs need to execute quickly. Anything that would take more than 1 or 2 seconds to execute should be submitted to batch instead.

If your 5250 session locks up you probably have poor error handling in your program. It has failed and is waiting for the system operator to reply to a message. It is recommended that you improve such default IBM i error handling.

Your RPG or CL program must never ever change the execution characteristics of the IBM i job they are executing. Job characteristics include anything that may impact other programs executing within the same job – including things like library lists, priorities, activation groups, CCSIDs, contents of QTEMP, etc.

Administrators

Legal Mentions

aXes is brought to you by:

LANSA

Serving the IBM i community for 30 years.