Example: invoking Java from a batch COBOL program

You can invoke Java™ from a batch COBOL program by using the Java Batch Launcher and Toolkit for z/OS® (JZOS). The following example contains JCL and source for a COBOL program that invokes a Java program in a batch job step. Numbers in parentheses refer to notes that follow the example.

In this environment, it is often desirable to direct the standard Java System.out and System.err files to z/OS data sets or spool files. You can do this by calling the redirectStandardStreams method in the com.ibm.jzos.ZUtil class after starting the Java virtual machine (JVM). For details about the ZUtil class, see ZUtil in the z/OS security and legacy services API Reference.

In this example COBOL program, the main() method from the com.ibm.jzos.sample.HelloWorld class is invoked, but you can change this to invoke other Java class methods.

//COB2JAV JOB (),'Dovetail',
// MSGCLASS=H,REGION=128M,
// NOTIFY=&SYSUID
//*
//* Tested on z/OS V2R2 with Ent Cobol V5R1 and Java V7.0
// SET COBPRFX='SYSPROG.MNT.COBOL51'                                            (1)
// SET LIBPRFX='CEE'
// SET SYSLIB1='G1JAVA1.PRIVATE.JZOS.DEVEL.JCL'  Has JNI cpybook                (2)
//*  See also CLASSPATH below
//*
//COMPILE EXEC PGM=IGYCRCTL,
// PARM='SIZE(5000K)'
//SYSLIB DD DISP=SHR,DSN=&SYSLIB1  (JNI) CPY
//SYSLIN DD DSNAME=&&OBJECT(TSTHELLO),UNIT=3390,DISP=(NEW,PASS),
// SPACE=(CYL,(1,1,1)),DCB=(LRECL=80,RECFM=FB)
//SYSPRINT DD SYSOUT=*
//STEPLIB DD DSN=&COBPRFX..SIGYCOMP,DISP=SHR
// DD DSN=&LIBPRFX..SCEERUN,DISP=SHR 
// DD DSN=&LIBPRFX..SCEERUN2,DISP=SHR
//SYSUT1 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT2 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT3 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT4 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT5 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT6 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT7 DD UNIT=VIO,SPACE=(CYL,(1,1))
//SYSUT8 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT9 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT10 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT11 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT12 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT13 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT14 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSUT15 DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSMDECK DD UNIT=SYSALLDA,SPACE=(CYL,(1,1))
//SYSIN DD *
       cbl dll,thread
       Identification division.
       Program-id. "TSTHELLO" recursive.
       Environment division.
       Configuration section.
       Repository.
           Class ZUtil         is "com.ibm.jzos.ZUtil"                          (3)
           Class HelloWorld    is "com.ibm.jzos.sample.HelloWorld"              (4)
           Class JavaException is "java.lang.Exception"
           Class JavaObject    is "java.lang.Object"
           Class JavaString    is "java.lang.String"
           Class JavaClass     is "java.lang.Class"
           Class stringArray is "jobjectArray:java.lang.String".

       Data Division.
       Working-storage section.
       01 args           object reference stringArray.
       01 argsLen        pic s9(9) binary value 0.
       01 jstring1       object reference JavaString.
       01 stringClass    object reference JavaClass.
       01 ex             object reference JavaException.
       01 stringBuf      pic X(256) usage display.
       Linkage section.
       COPY "JNI" SUPPRESS.

       Procedure division.
           Display "COBOL program TSTHELLO entered"
           Set address of JNIEnv to JNIEnvPtr
           Set address of JNINativeInterface to JNIENV
      *
      * This static JZOS method will redirect Java stdout/stderr
      * to DD:STDOUT and DD:STDERR, which may be spool files or data sets
      *
           Invoke ZUtil "redirectStandardStreams"                               (3)
           Perform ErrorCheck
           Display "Returned from ZUtil.redirectStandardStreams"

      *
      * We invoke com.ibm.jzos.sample.HelloWorld,
      * but this could be any arbitrary Java code
      *
           Perform BuildEmptyArgsArray.
           Invoke HelloWorld "main"                                             (4)
               using by value args
           Perform ErrorCheck
           Display "Returned from HelloWorld.main"

           Goback.

        ErrorCheck.
            Call ExceptionOccurred
                using by value JNIEnvPtr
                returning ex
            If ex not = null then
                Call ExceptionClear using by value JNIEnvPtr
                Display "Caught a Java exception"
                Invoke ex "printStackTrace"
                Stop run
            End-if.

        BuildEmptyArgsArray.
      *  Create a new empty string
           Call NewString
                using by value JNIEnvPtr
                      address of stringBuf
                      0
                returning jstring1
           If jstring1 not = null then
               Display "NewString returned OK"
           Else
               Display "NewString returned null!"
               Stop run
           End-if

      *  Get a reference to the String class object
           Call GetObjectClass
                using by value JNIEnvPtr jstring1
                returning stringClass
           If stringClass not = null then
               Display "GetObjectClass returned OK"
           Else
               Display "GetObjectClass returned null!"
               Stop run
           End-if

      *  Create a zero-length String[] array
           move 0 to argsLen
           Call NewObjectArray
                using by value JNIEnvPtr
                argsLen stringClass jstring1
                returning args
           If args not = null then
               Display "NewObjectArray returned OK"
           Else
               Display "NewObjectArray returned null!"
               Stop run
           End-if.

       End program "TSTHELLO".
/*
//LKED EXEC PGM=IEWL,COND=(4,LT,COMPILE),
//             PARM='RENT,LIST,LET,DYNAM(DLL),CASE(MIXED)'
//SYSLIB DD DSN=&LIBPRFX..SCEELKED,DISP=SHR
// DD DSN=&LIBPRFX..SCEELKEX,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSTERM DD SYSOUT=*
//SYSLMOD DD DSN=&&GOSET(TSTHELLO),DISP=(MOD,PASS),UNIT=3390,
// SPACE=(CYL,(1,1,1)),DSNTYPE=LIBRARY
//SYSDEFSD DD DUMMY
//OBJMOD DD DSN=&&OBJECT,DISP=(OLD,DELETE)
//SYSLIN DD *
 INCLUDE OBJMOD(TSTHELLO)
 INCLUDE '/usr/lpp/java/J7.0/bin/j9vm/libjvm.x'                                 (5)
 INCLUDE '/usr/lpp/cobol/V5R1/lib/igzcjava.x'                                   (5)
//*
//* Note: we expect RC=32 since we should Stop run for exception
//*
//GO EXEC PGM=TSTHELLO,COND=(4,LT,LKED)
//CEEOPTS DD *
* Be careful when editing: quoted ENVARS wrap at col 72
ENVAR(                                                                          (6)
"PATH=bin:/usr/lpp/java/J7.0/bin",                                              
"LIBPATH=lib:/usr/lib:/usr/lpp/java/J7.0/bin:/usr/lpp/java/J7.0/lib/s390        
:/usr/lpp/java/J7.0/lib/s390/j9vm",                                             
"CLASSPATH=/home/g1java1/jzostest/jzos_test.jar")
POSIX(ON) XPLINK(ON)
*
* Add this ENVAR to send stdout/stderr to DD:SYSOUT
*  "COBJVMINITOPTIONS=-Djzos.merge.sysout=true",                                (7)
* Debugging options:
*  "COBJVMINITOPTIONS=-Xdump:ceedump -Xcheck:jni:trace -Xjit:verbose")
//STEPLIB DD DSN=*.LKED.SYSLMOD,DISP=(OLD,PASS)
// DD DSN=&LIBPRFX..SCEERUN2,DISP=SHR
// DD DSN=&LIBPRFX..SCEERUN,DISP=SHR
//SYSOUT DD SYSOUT=*
//CEEDUMP DD SYSOUT=*
//SYSUDUMP DD DUMMY
//*
//* ZUtil.redirectStandardStreams will point to these for sdtout/stderr
//*  Unless you add the -Djzos.merge.sysout=true option above.
//*  Using that option, both Java stdout/stderr with go to DD:SYSOUT
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//*
//* JAVAOUT/JAVAERR should not be used unless redirectStandardStreams fails
//* so you may choose to point these to DUMMY
//JAVAOUT DD PATH='/tmp/cob2jav.javaout',                                       (8)
// PATHOPTS=(OWRONLY,OCREAT,OTRUNC),
// PATHMODE=(SIRUSR,SIWUSR,SIRGRP)
//JAVAERR DD PATH='/tmp/cob2jav.javaerr',                                       (8)
// PATHOPTS=(OWRONLY,OCREAT,OTRUNC),
// PATHMODE=(SIRUSR,SIWUSR,SIRGRP)
(1)
Set the JCL symbols to match your environment.
(2)
You must first copy the JNI.cpy file from your COBOL installation directory (typically /usr/lpp/cobol/include) as member JNI in this source PDS.
(3)
The ZUtil redirectStandardStreams method will redirect Java System.out and System.err to DD:STDOUT and DD:STDERR respectively.
(4)
The com.ibm.jzos.sample.HelloWorld class prints “Hello World! (stdout)” to System.out and “Hello World! (stderr)” to System.err. You can download the com.ibm.jzos.sample.HelloWorld class with the JZOS samples.
(5)
Set the INCLUDEs to point to the locations where your Java and COBOL are installed.
(6)
Set the Language Environment® ENVARs to point to your Java home directories. Note that individual environment variable settings wrap at column 72.
(7)
You can add the COBJVMINITOPTIONS environment variable as shown to set Java system properties for the JVM. The jzos.merge.sysout=true property can be used to merge both System.out and System.err to go to DD:SYSOUT.
(8)
The JAVAOUT DD and JAVAERR DD statements are not used if ZUtil.redirectStandardStreams() works properly, so you can point these to DD DUMMY.

About JZOS

Java Batch Launcher and Toolkit for z/OS (JZOS) is a set of tools that helps you develop z/OS Java applications that run in a traditional batch environment, and that access z/OS system services. For details, see the JZOS Installation and User's Guide.