Troubleshooting
Problem
This document explains how to get a Java trace into a file for Java exceptions from ILE RPG calling Java.
Resolving The Problem
This document explains how to get a Java trace for Java exceptions that are thrown by a Java method called by ILE RPG. It also explains the necessary environment variables, Java properties, and some additional setup needed before RPG calls any Java methods.
A simple example is included.
Step 1: Do the following before the JVM is started (before any Java methods are called by RPG programs):
Step 2: Set the QIBM_RPG_JAVA_EXCP_TRACE environment variable to a value of 'Y'. This does not have to be done before the JVM is started, but it must be done before the Java method is called that gets the exception.
Step 3: Do the following to get the Java exception trace into a file:
Source for CLP Program SETUPENV
The following is the source for the CLP program SETUPENV to set up the environment variables. This program can be compiled with PDM Option 14 or the CRTCLPGM command.
Note: If using a cut-and-paste method into the CLP source, ensure that the value of the QIBM_RPG_JAVA_PROPERTIES environment variable is in mixed case in the CLP source.
ADDENVVAR ENVVAR(QIBM_USE_DESCRIPTOR_STDIO) VALUE('Y')
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) VALUE('-Dos400.stderr=file:/home/mydir/mystderr.txt;')
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_EXCP_TRACE) VALUE('Y')
Note: If you would also like to get the stdout along with the stderr, add on to the ADDENVVAR value:
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) + VALUE('-Dos400.stderr=file:/home/mydir/mystderr.txt;-Dos400.stdout=file:/home/mydir/mystdout.txt;')
Source for RPGLE Program ERRORTEST
The following is the source for the RPGLE program ERRORTEST, which gets an exception from a called Java method. This program can be compiled with PDM Option 14 or the CRTBNDRPG command.
H thread(*serialize)
H CCSID (*CHAR:*JOBRUN)
H DFTACTGRP(*NO)
/TITLE ERRORTEST - Call a Java method that throws an exception
D parseInt pr 10i 0 extproc(*java:'java.lang.Integer'
D : 'parseInt')
D static
D string o class(*java:'java.lang.String')
D const
D num s 10i 0
/free
num = parseInt(*null); // get pointer-not-set error from Java
*inlr = '1';
Source for RPG Program OPENSTDIO
The following is the source for RPG program OPENSTDIO to open the three standard I/O file descriptors stdin (0), stdout (1), and stderr (2).
You should call this program as the first step in your job. If any other activity in the job opens one of these file descriptors incorrectly, this program will fail and your Java or QSHELL call might not work correctly.
Create the ILE RPG program called OPENSTDIO. The following is the ILE RPG source code, source member type RPGLE. You can compile it using Option 14 in PDM or by using the CRTBNDRPG command.
The main procedure of the program ends with some rudimentary code to report the error; it uses a DSPLY operation and then it calls the *PSSR subroutine with ENDSR *CANCL which causes an exception to be sent to the program's caller. You may want to replace this code with a better mechanism for reporting the error.
h thread(*serialize) bnddir('QC2LE') dftactgrp(*no)
D O_CREAT C x'00000008'
D O_TRUNC C x'00000040'
D O_RDONLY C x'00000001'
D O_WRONLY C x'00000002'
D O_RDWR C x'00000004'
D O_ACCMODE c %BITOR(O_RDONLY
D : %BITOR(O_WRONLY
D : O_RDWR))
D S_IRUSR C x'0100'
D S_IROTH C x'0004'
D S_IWUSR C x'0080'
D S_IWOTH C x'0002'
D chk pr n
D descriptor 10i 0 value
D mode 10i 0 value
D aut 10i 0 value
D other_valid_mode...
D 10i 0 value
D ok s n
/free
// Validate or open descriptors 0, 1 and 2
ok = chk (0
: 0 + O_CREAT + O_TRUNC + O_RDWR
: 0 + S_IRUSR + S_IROTH
: 0 + O_RDONLY)
and chk (1
: 0 + O_CREAT + O_TRUNC + O_WRONLY
: 0 + S_IWUSR + S_IWOTH
: 0 + O_RDWR)
and chk (2
: 0 + O_CREAT + O_TRUNC + O_WRONLY
: 0 + S_IWUSR + S_IWOTH
: 0 + O_RDWR);
// If the descriptors were not all correct,
// signal an exception to our caller
if not ok;
// !!! Additional coding required:
// !!! At this point, the code should signal an error condition,
// !!! or a parameter could be added to return the fact that
// !!! this program did not open the descriptors correctly
// !!! For now, it will use DSPLY and then call the *PSSR ending with
// !!! *CANCL to signal an exception
dsply ('Descriptors 0, 1 and 2 not opened successfully.');
exsr *pssr;
endif;
*inlr = '1';
begsr *pssr;
// endsr *cancl will signal an exception to the caller
endsr '*CANCL';
/end-free
P chk b
D chk pi n
D descriptor 10i 0 value
D mode 10i 0 value
D aut 10i 0 value
D other_valid_mode...
D 10i 0 value
D open pr 10i 0 extproc('open')
D filename * value options(*string)
D mode 10i 0 value
D aut 10i 0 value
D unused 10i 0 value options(*nopass)
D closeFile pr 10i 0 extproc('close')
D handle 10i 0 value
D fcntl pr 10I 0 extproc('fcntl')
D descriptor 10I 0 value
D action 10I 0 value
D arg 10I 0 value options(*nopass)
D F_GETFL c x'06'
D flags s 10i 0
D new_desc s 10i 0
D actual_acc s 10i 0
D required_acc s 10i 0
D allowed_acc s 10i 0
/free
flags = fcntl (descriptor : F_GETFL);
if flags < 0;
// no flags returned, attempt to open this descriptor
new_desc = open ('/dev/null' : mode : aut);
if new_desc <> descriptor;
// we didn't get the right descriptor number, so
// close the one we got and return '0'
if new_desc >= 0;
closeFile (new_desc);
endif;
return '0';
endif;
else;
// check if the file was opened with the correct
// access mode
actual_acc = %bitand (flags : O_ACCMODE);
required_acc = %bitand (mode : O_ACCMODE);
allowed_acc = %bitand (other_valid_mode : O_ACCMODE);
if actual_acc <> required_acc
and actual_acc <> allowed_acc;
return '0';
endif;
endif;
return '1';
/end-free
P chk e
Note: If the OPENSTDIO program is not run before you run your program, you will receive message CPFB9C8 in the joblog.
A simple example is included.
Step 1: Do the following before the JVM is started (before any Java methods are called by RPG programs):
a | Set the QIBM_USE_DESCRIPTOR_STDIO environment variable to a value of 'Y'. |
b | Set the Java property os400.stderr to point to a file in the Integrated File System. One way to do this is to use the QIBM_RPG_JAVA_PROPERTIES environment variable; refer to the following Source for CLP Program SETUPENV section. |
c | Ensure that three file descriptors are open. Refer to the source for program OPENSTDIO in the following Source for RPG Program OPENSTDIO section. |
Step 2: Set the QIBM_RPG_JAVA_EXCP_TRACE environment variable to a value of 'Y'. This does not have to be done before the JVM is started, but it must be done before the Java method is called that gets the exception.
Step 3: Do the following to get the Java exception trace into a file:
a. | Create the programs SETUPENV, ERRORTEST, OPENSTDIO from the source in the following sections. |
b. | Create the directory for the stderr file in the Integrated File System by using the MKDIR command on the operating system command line: MKDIR '/home/mydir' Press the Enter key. |
c. | On the operating system command line type the following: CALL SETUPENV Press the Enter key. |
d. | On the operating system command line type the following: CALL OPENSTDIO Press the Enter key. |
e. | On the operating system command line type the following: CALL ERRORTEST Press the Enter key. |
f. | To see the results, use the WRKLNK command on the operating system command line, and select Option 5 to view the file: WRKLNK '/home/mydir/mystderr.txt' Press the Enter key. The file mystderr.txt should contain output similar to the following: java.lang.NumberFormatException: null java/lang/Throwable.<init>(Ljava/lang/String;)V+4 (Throwable.java:85) java/lang/Exception.<init>(Ljava/lang/String;)V+1 (Exception.java:33) java/lang/RuntimeException.<init>(Ljava/lang/String;)V+1 (RuntimeExc java/lang/IllegalArgumentException.<init>(Ljava/lang/String;)V+1 (Ill java/lang/Integer.parseInt(Ljava/lang/String;I)I+4 (Integer.java:377) java/lang/Integer.parseInt(Ljava/lang/String;)I+1 (Integer.java:458) |
Source for CLP Program SETUPENV
The following is the source for the CLP program SETUPENV to set up the environment variables. This program can be compiled with PDM Option 14 or the CRTCLPGM command.
Note: If using a cut-and-paste method into the CLP source, ensure that the value of the QIBM_RPG_JAVA_PROPERTIES environment variable is in mixed case in the CLP source.
ADDENVVAR ENVVAR(QIBM_USE_DESCRIPTOR_STDIO) VALUE('Y')
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) VALUE('-Dos400.stderr=file:/home/mydir/mystderr.txt;')
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_EXCP_TRACE) VALUE('Y')
Note: If you would also like to get the stdout along with the stderr, add on to the ADDENVVAR value:
ADDENVVAR ENVVAR(QIBM_RPG_JAVA_PROPERTIES) + VALUE('-Dos400.stderr=file:/home/mydir/mystderr.txt;-Dos400.stdout=file:/home/mydir/mystdout.txt;')
Source for RPGLE Program ERRORTEST
The following is the source for the RPGLE program ERRORTEST, which gets an exception from a called Java method. This program can be compiled with PDM Option 14 or the CRTBNDRPG command.
H thread(*serialize)
H CCSID (*CHAR:*JOBRUN)
H DFTACTGRP(*NO)
/TITLE ERRORTEST - Call a Java method that throws an exception
D parseInt pr 10i 0 extproc(*java:'java.lang.Integer'
D : 'parseInt')
D static
D string o class(*java:'java.lang.String')
D const
D num s 10i 0
/free
num = parseInt(*null); // get pointer-not-set error from Java
*inlr = '1';
Source for RPG Program OPENSTDIO
The following is the source for RPG program OPENSTDIO to open the three standard I/O file descriptors stdin (0), stdout (1), and stderr (2).
You should call this program as the first step in your job. If any other activity in the job opens one of these file descriptors incorrectly, this program will fail and your Java or QSHELL call might not work correctly.
Create the ILE RPG program called OPENSTDIO. The following is the ILE RPG source code, source member type RPGLE. You can compile it using Option 14 in PDM or by using the CRTBNDRPG command.
The main procedure of the program ends with some rudimentary code to report the error; it uses a DSPLY operation and then it calls the *PSSR subroutine with ENDSR *CANCL which causes an exception to be sent to the program's caller. You may want to replace this code with a better mechanism for reporting the error.
h thread(*serialize) bnddir('QC2LE') dftactgrp(*no)
D O_CREAT C x'00000008'
D O_TRUNC C x'00000040'
D O_RDONLY C x'00000001'
D O_WRONLY C x'00000002'
D O_RDWR C x'00000004'
D O_ACCMODE c %BITOR(O_RDONLY
D : %BITOR(O_WRONLY
D : O_RDWR))
D S_IRUSR C x'0100'
D S_IROTH C x'0004'
D S_IWUSR C x'0080'
D S_IWOTH C x'0002'
D chk pr n
D descriptor 10i 0 value
D mode 10i 0 value
D aut 10i 0 value
D other_valid_mode...
D 10i 0 value
D ok s n
/free
// Validate or open descriptors 0, 1 and 2
ok = chk (0
: 0 + O_CREAT + O_TRUNC + O_RDWR
: 0 + S_IRUSR + S_IROTH
: 0 + O_RDONLY)
and chk (1
: 0 + O_CREAT + O_TRUNC + O_WRONLY
: 0 + S_IWUSR + S_IWOTH
: 0 + O_RDWR)
and chk (2
: 0 + O_CREAT + O_TRUNC + O_WRONLY
: 0 + S_IWUSR + S_IWOTH
: 0 + O_RDWR);
// If the descriptors were not all correct,
// signal an exception to our caller
if not ok;
// !!! Additional coding required:
// !!! At this point, the code should signal an error condition,
// !!! or a parameter could be added to return the fact that
// !!! this program did not open the descriptors correctly
// !!! For now, it will use DSPLY and then call the *PSSR ending with
// !!! *CANCL to signal an exception
dsply ('Descriptors 0, 1 and 2 not opened successfully.');
exsr *pssr;
endif;
*inlr = '1';
begsr *pssr;
// endsr *cancl will signal an exception to the caller
endsr '*CANCL';
/end-free
P chk b
D chk pi n
D descriptor 10i 0 value
D mode 10i 0 value
D aut 10i 0 value
D other_valid_mode...
D 10i 0 value
D open pr 10i 0 extproc('open')
D filename * value options(*string)
D mode 10i 0 value
D aut 10i 0 value
D unused 10i 0 value options(*nopass)
D closeFile pr 10i 0 extproc('close')
D handle 10i 0 value
D fcntl pr 10I 0 extproc('fcntl')
D descriptor 10I 0 value
D action 10I 0 value
D arg 10I 0 value options(*nopass)
D F_GETFL c x'06'
D flags s 10i 0
D new_desc s 10i 0
D actual_acc s 10i 0
D required_acc s 10i 0
D allowed_acc s 10i 0
/free
flags = fcntl (descriptor : F_GETFL);
if flags < 0;
// no flags returned, attempt to open this descriptor
new_desc = open ('/dev/null' : mode : aut);
if new_desc <> descriptor;
// we didn't get the right descriptor number, so
// close the one we got and return '0'
if new_desc >= 0;
closeFile (new_desc);
endif;
return '0';
endif;
else;
// check if the file was opened with the correct
// access mode
actual_acc = %bitand (flags : O_ACCMODE);
required_acc = %bitand (mode : O_ACCMODE);
allowed_acc = %bitand (other_valid_mode : O_ACCMODE);
if actual_acc <> required_acc
and actual_acc <> allowed_acc;
return '0';
endif;
endif;
return '1';
/end-free
P chk e
Note: If the OPENSTDIO program is not run before you run your program, you will receive message CPFB9C8 in the joblog.
Related Information
[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"Programming (Languages- compilers- tools)","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"All Versions","Edition":"","Line of Business":{"code":"LOB57","label":"Power"}}]
Historical Number
454756802
Was this topic helpful?
Document Information
More support for:
IBM i
Software version:
All Versions
Operating system(s):
IBM i
Document number:
636571
Modified date:
18 December 2019
UID
nas8N1014290
Manage My Notification Subscriptions