Hi,
we have done something similar with a customer. The difference was, that they
have called WebSphere ILOG as business rules engine.
The COBOL Java approach worked very well. But you need to make sure that you
code JNI calls and do not use the INVOKE syntax of the COBOL compiler. I'll
attach some code.
COBOL and Java run in the same address space so in terms of performance you
save the cross address space calls. The JVM is reusable for the lifetime of the
batch region, with the latest enhancements of JDK 6.0.1 it is great performance.
There was one difference, we also executed the rules engine (ILOG) which is
implemented in Java on z/OS. So we did not do calls to outside z/OS, which are
most likely the biggest performance eaters. But there is still the option to
run multithreaded.
[Environment]
As for development, there are plenty of tools on the market, which generate
Java code from WSDL (Eclipse, Rational Application Developer, etc.), so there
is almost no coding to be done apart from Data conversion. It is recommended to
pass copybooks by reference and then make a byte array out of it which is
passed to java. Then use the JZOS record generator to create a Java class with
matching offsets getter and setter methods to be used in Java. Since all our
data was fixed length strings, in the Java part we just did String.substring to
get the data as Java String.
You need a JDK on z/OS to do that. Thats it. If you want DB2 calls from Java
and COBOL transactional, you need RRSAF linked with COBOL and the JDBC Driver
for Java.
[Development Process]
The development process would be like this, that the z/OS people create the
cobol code as samples are below:
Plus use the JZOS record generator to generate Java classes from any used input
and output copybooks.
Send the generated Java classes to the Java devlopers with the WSDL.
The Java developers would generated a Java proxy for the web service from the
WSDL.
The Java developers have to code a method with an input and output byte array
for the data to be passed from and to COBOL, plus they have to implement the
getter and setter methods to fill the input to the web service from the byte
array and to retrieve the output from the web service and pass it to the output
byte array. This is manual work, but could be simple depending on the data
types, offsets, etc.
The Java developers test the web service from Java with some sample data and
create the Jar file with all dependencys or get you a bunch of Jar files.
The jar files are uploaded to z/OS.
You can run and test the batch.
[Sample Scenario]
Our scenario was as follows, this is simplified:
Main Program CJ01MAIN (NODLL) reads records from sequential file, calls
subroutine and writes output to sequential file. (needs to be linked with
CEEUOPT to set XPLINK(ON) and POSIX(ON) LE runtime options). This allows to
simply code a MOVE 'CJ01KAPS' TO MODULE plus CALL MODULE to invoke the
subroutine dynamically.
Wrapper subroutine CJ01KAPS , because Java runs as DLL compiled, dynamic calls
are only possible from DLL to DLL and from NODLL to NODLL.
COBOL subroutine CJ01JAVA which implements the JNI calls, preparing the byte
array objects, caching the objects and some ids to save most of the JNI
overhead during repeated processing, passing the copybook data to the bytearray
object, find the java class and method to be called, call the java method and
pass the result byte array object into an output copybook.
This is a sample of CEEUOPT to be linked with the main program:
//SYSIN DD *
TITLE 'CEEUOPT'
CEEUOPT CSECT
CEEUOPT AMODE ANY
CEEUOPT RMODE ANY
CEEXOPT XPLINK=(ON), X
POSIX=(ON), X
ENVAR=('_CEE_ENVFILE=/u/gaebler/hello/ENV')
END
//*
The File /u/gaebler/hello/ENV contains the environment variables for Java:
PATH=/bin:/usr/lpp/java/J6.0/bin:.
LIBPATH=/lib:/usr/lib:/usr/lpp/java/J6.0/bin:>
/usr/lpp/java/J6.0/bin/j9vm:/usr/lpp/db2/db2910/db2910_jdbc/lib
CLASSPATH=/u/gaebler/hello.jar
The classpath can be one or multiple jar files or directorys and should contain
the Java classes and all dependent jar files.
[Sample compile]
CJ01COMP
[Sample wrapper source]
CJ01KAPS
[Sample JNI calls in cobol sub source]
CJ01JAVA
If you need assistence please feel free to contact me directly.
mfg / best regards
Denis Gäbler
IMS Senior Technical Sales Professional
Kst.: B471, Geb.: 10, Am Keltenwald 1, Ehningen, 71139, Germany
Chat with me through AIM (AOL Instant Messenger):
For people outside IBM, use AOL and add the IBMers: [email protected]
Fax: +49-(0)30-484986506
Funk: +49-(0)172-6286935
IBM Deutschland GmbH / Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Martina Koederitz (Vorsitzende), Reinhard Reschke,
Dieter Scholz, Michael Diemer, Gregor Pillen, Joachim Heel
Sitz der Gesellschaft: Ehningen / Registergericht: Amtsgericht Stuttgart, HRB
14562 / WEEE-Reg.-Nr. DE 99369940
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html
//CJ01COMP JOB ,
// MSGCLASS=A,TIME=1440,USER=&SYSUID,
// MSGLEVEL=(1),REGION=0M
//*
//* Definitions
//*
// SET IMSHLQ=IMS.IMSD
// SET DSNHLQ=DB2.V9R1
// SET DB2SSID=DSNA
// SET CEEHLQ=CEE
// SET SYS1HLQ=SYS1
// SET SRCHLQ=DDS1479.CJLAB
//*
//* Change the following occurences of paths and qualifiers in SYSIN
//* In the CEEUOPT Assembly change /u/itso12/hello to the path that
//* will contain the files uploaded from Eclipse
//* In the CJ01JAVA Assembly change /usr/lpp/java/J5.0 to the path
//* that contains the JAVA 5 JDK on your system
//* In the CJ01JAVA Aseembly change /usr/lpp/cobol to the path
//* that contains the Enterprise COBOL compilers HFS installation
//* In the DB2GRANT and BINDJDBC jobsteps change the DB2 SSID DB9H
//* to the DB2 SSID of your system and the DB9H9 DB2 High Level
//* Qualifier to the one of your DB2 system
//*
//* Lib containing the COBOL compiler procedures
//*
//PROC04 JCLLIB ORDER=(&SRCHLQ..PROCLIB)
//*
//* Create CEEUOPT
//*
//CEEUOPT EXEC PGM=ASMA90,PARM='LINECOUNT(0)'
//SYSPRINT DD SYSOUT=*
//SYSUT1 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT2 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT3 DD UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSLIN DD DSNAME=&&OPTIONS(CEEUOPT),UNIT=SYSALLDA,
// DISP=(MOD,PASS),SPACE=(TRK,(3,3,5)),
// DCB=(BLKSIZE=3200)
//SYSLIB DD DSN=&CEEHLQ..SCEEMAC,DISP=SHR
// DD DSN=&SYS1HLQ..MACLIB,DISP=SHR
//SYSIN DD *
TITLE 'CEEUOPT'
CEEUOPT CSECT
CEEUOPT AMODE ANY
CEEUOPT RMODE ANY
CEEXOPT XPLINK=(ON), X
POSIX=(ON), X
ANYHEAP=(3M,128K,ANY,FREE), X
HEAP=(80M,10M,ANY,KEEP,16K,8K), X
HEAPPOOLS=(ON,8,10,32,10,128,10,256,10,1024,10,2048,10, X
0,1,0,10,0,10,0,10,0,10,0,10), X
STACK=(64K,16K,ANY,KEEP,128K,128K), X
STORAGE=(NONE,NONE,NONE,0K), X
THREADSTACK=(OFF,64K,16K,ANY,KEEP,128K,128K), X
TERMTHDACT=(UADUMP), X
ENVAR=('_CEE_ENVFILE=/u/dds1479/CJ01ENVIMSDB2')
END
//*
//*
//* Compile and Link of Main IMS Transaction
//*
//CJ01MAIN EXEC DSNHICOB,MEM=CJ01MAIN,USER=&SYSUID,
// PARM.COB=RENT,REGION=1400K,
// PARM.LKED='RENT,LIST,XREF,LET,MAP'
//PC.SYSIN DD DSN=&SRCHLQ..SOURCE(CJ01MAIN),DISP=SHR
//PC.SYSLIB DD DUMMY
//LKED.SYSLMOD DD DSN=&IMSHLQ..PGMLIB(CJ01TRAN),DISP=SHR
//LKED.SYSLIB DD DSN=&IMSHLQ..SDFSRESL,DISP=SHR
// DD DSN=&DSNHLQ..SDSNLOAD,DISP=SHR
// DD DSN=&CEEHLQ..SCEELKED,DISP=SHR
// DD DSN=&CEEHLQ..SCEELKEX,DISP=SHR
// DD DSN=&SYS1HLQ..CSSLIB,DISP=SHR
// DD DSNAME=&&OPTIONS,DISP=(OLD,DELETE)
//LKED.SYSIN DD *
INCLUDE SYSLIB(CEEUOPT)
ORDER CEEUOPT
INCLUDE SYSLIB(DSNTIAR)
INCLUDE SYSLIB(DFSLI000)
ENTRY CJ01MAIN
NAME CJ01TRAN(R)
/*
//*
//* Compile and Link of COBOL Subroutine Executing Java Class
//*
//*
//CJ01JAVA EXEC IGYWCPL,PARM.COBOL='RENT',REGION=1400K,
// PARM.LKED='RENT,LIST,XREF,LET,MAP,DYNAM(DLL),CASE(MIXED)'
//COBOL.SYSIN DD DSN=&SRCHLQ..SOURCE(CJ01JAVA),
// DISP=SHR
//* Dataset containing JNI.cpy
//COBOL.SYSLIB DD DISP=SHR,DSN=&SRCHLQ..SOURCE
//LKED.SYSLMOD DD DSNAME=&&MODULES(CJ01JAVA),UNIT=SYSALLDA,
// DISP=(MOD,PASS),SPACE=(TRK,(3,3,5)),
// DCB=(BLKSIZE=3200)
//LKED.SYSLIB DD DSN=&IMSHLQ..SDFSRESL,DISP=SHR
// DD DSN=&CEEHLQ..SCEELKED,DISP=SHR
//PLKED.SYSIN DD
// DD PATH='/usr/lpp/java/J6.0/bin/j9vm/libjvm.x'
// DD PATH='/usr/lpp/cobol/lib/igzcjava.x'
//LKED.SYSIN DD *
INCLUDE '/usr/lpp/java/J6.0/bin/j9vm/libjvm.x'
INCLUDE '/usr/lpp/cobol/lib/igzcjava.x'
ENTRY CJ01JAVA
NAME CJ01JAVA(R)
/*
//*
//* Compile and Link of COBOL DLL,LIB Wrapper for previous Step
//*
//*
//CJ01KAPS EXEC IGYWCL,PARM.COBOL='RENT,NODLL,NODYNAM',REGION=1400K,
// PARM.LKED='RENT,LIST,XREF,LET,MAP'
//COBOL.SYSIN DD DSN=&SRCHLQ..SOURCE(CJ01KAPS),
// DISP=SHR
//LKED.SYSLMOD DD DSN=&IMSHLQ..PGMLIB(CJ01KAPS),DISP=SHR
//LKED.SYSLIB DD DSN=&IMSHLQ..SDFSRESL,DISP=SHR
// DD DSN=&CEEHLQ..SCEELKED,DISP=SHR
// DD DSNAME=&&MODULES,DISP=(OLD,DELETE)
//LKED.SYSIN DD *
NAME CJ01KAPS(R)
/*
//BINDJDBC EXEC PGM=IKJEFT01,DYNAMNBR=20
//DBRMLIB DD DISP=SHR,DSN=&DSNHLQ..SDSNDBRM
// DD DISP=SHR,DSN=&SYSUID..DBRMLIB.DATA
//STEPLIB DD DISP=SHR,DSN=&DSNHLQ..SDSNLOAD
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(DSNA)
BIND PACKAGE(DDS1479) MEMBER(CJ01MAIN) -
ISOLATION(UR) QUALIFIER(SYSIBM)
BIND PLAN(CJ01TRAN) -
PKLIST(DDS1479.CJ01MAIN, -
NULLID.SYSLH200, -
NULLID.SYSSTAT)
END
/*
//DB2GRANT EXEC PGM=IKJEFT01,DYNAMNBR=20
//STEPLIB DD DISP=SHR,DSN=&DSNHLQ..SDSNLOAD
//SYSTSPRT DD SYSOUT=*
//SYSTSIN DD *
DSN SYSTEM(DSNA)
RUN PROGRAM(DSNTIAD) PLAN(DSNTIA91) -
LIB('DB2.V9R1.DSNA.RUNLIB.LOAD')
END
//SYSPRINT DD SYSOUT=*
//SYSUDUMP DD SYSOUT=*
//SYSIN DD *
GRANT EXECUTE ON PLAN CJ01TRAN TO PUBLIC;
COMMIT;
//*
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html
CBL APOST,NODLL,NODYNAM,RENT 00010000
* DUMMY MODULE WITH NO LOGIC TO PROVIDE A WRAPPER FOR
* LIB,DLL COMPILED MODULES, WHICH JAVA IS USING
IDENTIFICATION DIVISION. 00020000
PROGRAM-ID. 'CJ01KAPS'. 0003000
* 00390000
ENVIRONMENT DIVISION. 00400000
CONFIGURATION SECTION. 00410000
SOURCE-COMPUTER. IBM-370. 00420000
OBJECT-COMPUTER. IBM-370. 00430000
* 00440000
DATA DIVISION. 00450000
WORKING-STORAGE SECTION. 00460000
* 00470000
LINKAGE SECTION. 01900000
* 01910000
* COMMENT TO REMIND WHAT DATATYPES THE CALLING VARIABLES ARE
*
01 JAVARC USAGE IS POINTER.
01 JAVAIN USAGE IS POINTER. 01920000
01 JAVAOUT USAGE IS POINTER. 01920000
* 02020000
PROCEDURE DIVISION USING JAVARC, JAVAIN, JAVAOUT. 02030000
* 02040000
* ON ENTRY CALLER PASSES ADDRESSES FOR JAVA INPUT AND OUTPUT 02050000
* 02060000
* MAIN PROGRAM JUST OUTPUTS TRACING INFORMATION
* AND CALLS THE CJ01JAVA MODULE STATICALLY
*
MAIN-RTN. 02070000
* Static call to get around DLL/NODDL restriction
CALL 'CJ01JAVA' USING JAVARC, JAVAIN, JAVAOUT. 0208000
MAIN-RTN-END.
GOBACK.
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html
cbl lib,dll,pgmname(longmixed),noexp 00000108
* 00000207
* Sample program to call a Java Class 00000307
* 00000407
* Compile options, lib, thread and dll to be java compatible 00000507
* 00000607
Identification Division. 00002000
* recursive required for Java interaction 00002107
Program-id. "CJ01JAVA" recursive. 0000300
Environment Division. 00004000
Configuration section. 00005000
* Repository requires Java Class Definitions and mapping 00005107
* to Java package and class name 00005207
Repository. 00006000
Class Base is "java.lang.Object" 00007000
Class Hello is "com.ibm.cjlab.CJ0xHello" 00008000
Class JavaException is "java.lang.Throwable" 00008100
Class jbytearray is "jbytearray" 00008200
Class jclass is "jclass".
Data division. 00009300
Working-storage section. 00009400
* This is the place for storing the Global References
* that they can be reused for further invokations of the same
* module as long as the module is loaded
* This saves lots of CPU for saved JNI calls
01 cached-class-reference object reference Hello value null.
01 STATIC-METHOD-ID PIC S9(9) BINARY VALUE 0.
01 cachedDataByteArray object reference jbyteArray value null.
Local-storage section. 00009400
* Now declaring the local instance variables for the objects 00009507
* that contain a class when it was instanciated 00009607
01 ex object reference JavaException. 00009907
01 exObject object reference jclass.
01 DataByteArray object reference jbyteArray.
01 OutputByteArray object reference jbyteArray.
01 class-reference object reference Hello.
* Simple cobol variables 00010007
01 rc pic s9(9) comp-5. 00010200
01 laenge pic s9(9) comp-5 value 50.
01 offset pic s9(9) comp-5 value 0.
01 len pic 9(9) binary.
01 method-name pic x(50).
01 class-name pic x(50).
01 method-parm-description pic x(50).
01 input-string pic x(50).
01 JMETHOD-ID PIC S9(9) BINARY VALUE 0.
* Shows how to pass variables to the subroutine 00010307
Linkage section. 00010400
01 JAVARC PICTURE S9(3) COMP. 00010500
01 JAVAIN PIC X(50). 00010600
01 JAVAOUT PIC X(50). 00010700
* Copybook for JNI copybooks and function pointer definitions 00010807
Copy JNI. 00010900
Procedure Division USING JAVARC, JAVAIN, JAVAOUT. 00011000
* Required JNI setup 00011107
Set address of JNIenv to JNIEnvPtr 00011200
Set address of JNINativeInterface to JNIenv 00011300
* When Global Instance of Input ByteArray exists
If cachedDataByteArray = null
* Create a new Input Byte Array (Local Reference)
Call NewByteArray
using by value JNIEnvPtr
by value laenge
returning DataByteArray
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
* And make this ByteArray a Global Reference
Display 'newglobalref start.'
Call NewGlobalRef
using by value JNIEnvPtr
by value DataByteArray
returning cachedDataByteArray
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
Display 'newglobalref ended.'
Else
* Create a local reference of Input Byte Array
* From the Global Reference which is saved in
* Working Storage
Display 'newlocalref start.'
Call NewLocalRef
using by value JNIEnvPtr
by value cachedDataByteArray
returning DataByteArray
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
Display 'newlocalref ended.'
End-if
* Populate the Input Byte Array from the Input String 00011507
* passed to the routine
Move javain to input-string
Display 'SetByteArrayRegion start.'
Call SetByteArrayRegion
using by value JNIEnvPtr, DataByteArray, offset,
laenge, address of input-string
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
* Create a local class reference by using Findclass
* If there is no cached class in working storage
If cached-class-reference = null
* Make sure the global version of static method id is also
* null
Move 0 to STATIC-METHOD-ID
* Set Class Name
Move z"com/ibm/cjlab/CJ0xHello" to class-name
* Convert Class Name to ascii
Call "__etoa" using by value address of class-name
returning len
* Do the FindClass call with the ascii class name
Display 'FindClass start.'
Call FindClass using by value JNIEnvPtr
address of class-name returning class-reference
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
* If there is no class reference after Findclass
* either the class is not in the classpath, the class has
* the wrong class version (e.g. invoking a Java 6 compiled
* class with a JDK 5 JVM) or something else went wrong
If class-reference = null
Display "Error occurred locating TestClass class"
* Call ExceptionClear using by value JNIEnvPtr
Goback
End-if
* After successful Findclass create a global reference
* and store it in working storage for reuse
Display 'Findclass NewGlobalRef'
Call NewGlobalRef
using by value JNIEnvPtr
by value class-reference
returning cached-class-reference
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
Display 'findclass ended.'
Else
* When the cached Class Reference in Working Storage is
* already there, create a Locally useable reference from it
Call NewLocalRef
using by value JNIEnvPtr
by value cached-class-reference
returning class-reference
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
Display 'newlocalref instead of findclass ended.'
End-if
* Static Method Id from working storage is 0 when getstatic
* methodid was not executed or findclass was executed the
* first time
* The static method id remains the same as long as the same
* instance of the JVM remains active
If STATIC-METHOD-ID = 0
* Move static method name to variable
Move z"executeWithByteArray" to method-name
* And convert to ascii
Call "__etoa" using by value address of method-name
returning len
* Move method signature (accept and return byte array)
* to variable
Move z"(B)B" to method-parm-description
* And convert to ascii
Call "__etoa" using by value address of
method-parm-description
returning len
* Call GetStaticMethodID with method name and signature
* returning static-method-id
call GetStaticMethodID using
by value JNIEnvPtr
by value class-reference
address of method-name
address of method-parm-description
returning STATIC-METHOD-ID
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
* If static-method-id is 0 something went wrong
If STATIC-METHOD-ID = 0
Display "Error occurred while getting STATIC-METHOD-ID"
Goback
End-if
Display 'getstaticmethodid ended.'
End-if
* Check for Error 00011707
Perform JavaExceptionCheck 00011800
* Finally invoke the static method with DataByteArray as
* Input and OutputByteArray as Output
call CallStaticObjectMethod using
by value JNIEnvPtr
by value class-reference
by value STATIC-METHOD-ID
by value DataByteArray
returning OutputByteArray
* Check for Error
Perform JavaExceptionCheck
* Retrieve the OutputByteArray from the Java Method
Display 'GetByteArrayRegion started.'
Call GetByteArrayRegion
using by value JNIEnvPtr, OutputByteArray, offset,
laenge, address of javaout
* Check for Error 00014307
Perform JavaExceptionCheck 00014405
Display Javaout
* Delete Local Object Reference OutputByteArray because it is
* no longer needed
Call DeleteLocalRef
using by value JNIEnvPtr
by value OutputByteArray
* We're done and return to caller 00014507
Goback 00014600
. 00014700
* Check for an Exception occured in Java 00014807
JavaExceptionCheck. 00014900
* ExceptionOccured JNI function returns Exception object 00015007
Call ExceptionOccurred using by value JNIEnvPtr 00015100
returning ex 00015200
* If its not null then Exception was not caught in Java 00015307
* and needs to be analyzed with JNI calls
* If you don't catch the Exceptions in the Java code you will 00015407
* land here and to go back to Java you need to call another 00015507
* method, so better handle all Exceptions in Java try catch 00015607
* blocks 00015707
If ex not = null then 00016000
* Display a message to the Job output 00017107
Display "Caught an unexpected exception" 00018000
* Get the actual Java Object Reference for the Exception object
call GetObjectClass using
by value JNIEnvPtr
by value ex
returning exObject
* Print the Exception Stack Trace to get a clue what went wrong 00018107
Call ExceptionDescribe using by value JNIEnvPtr 00017000
* Move static method name to variable
Move z"printStackTrace" to method-name
* And convert to ascii
Call "__etoa" using by value address of method-name
returning len
* Move method signature (accept and return byte array)
* to variable
Move z"(V)V" to method-parm-description
* And convert to ascii
Call "__etoa" using by value address of
method-parm-description
returning len
* Call GetMethodID with method name and signature
* returning jmethod-id
Display 'GetMethodID in Exception'
call GetMethodID using
by value JNIEnvPtr
by value exObject
address of method-name
address of method-parm-description
returning JMETHOD-ID
if not JMETHOD-ID = 0 then
Display 'CallVoidMethod in Exception'
call CallVoidMethod using
by value JNIEnvPtr
by value exObject
by value JMETHOD-ID
by value 0
End-If
* Clear the Exception 00016107
Call ExceptionClear using by value JNIEnvPtr 00017000
* Set error code to 100 00019109
MOVE 100 TO JAVARC 00019209
* Return to caller 00019809
Goback 00020009
End-if 00030000
. 00040000
End program "CJ01JAVA". 0005000
----------------------------------------------------------------------
For IBM-MAIN subscribe / signoff / archive access instructions,
send email to [email protected] with the message: GET IBM-MAIN INFO
Search the archives at http://bama.ua.edu/archives/ibm-main.html