Creating Native Java Classes in COBOL | |
---|---|
By Stephen Gennard | (stephen@gennard.net) |
This article assumes you're familiar with Java and Micro Focus COBOL |
- 02/24/1997 - First draft.
- 03/03/1997 - I forgot Object COBOL has software exceptions.
- 03/06/1997 - Hints/tips section added.
- 03/22/1997 - Made document HTML 3.2 compliant
- 04/02/1997 - Updated documented on AOL
- 04/15/1997 - Checked HTML document with WebTechs HTML Validation Service
This document outlines how a legacy COBOL application can be converted into a "Native Java Class" by using Microsoft's "Raw Native Interface".
For the purpose of this article, I am using the Microsoft's Java SDK and Micro Focus Visual Object COBOL.
If you have questions about this whitepaper, please email at the above address.
COBOL is a very mature business language. It is well proven in the business world, because of this your company may have invested a great deal of time and effort in producing your application only to find you have no direct avenue for progression.
One possible solution is to re-use your legacy application with Java.
Having stated all this let us compare come of the features of the two languages.
|
|
If we have a simple Java class called ourFirstClass that has one method called ourFirstCOBOLmethod. The native class would be:
class ourFirstClass { native static int ourFirstCOBOLmethod(); static { System.loadLibrary("NatCBL"); } }
Now compile the class eg: jvc ourFirstClass.java
Microsoft (R) Visual J++ Compiler Version 1.01.XXXX Copyright (C) Microsoft Corp 1996. All rights reserved.The next step is to generate the a 'C' header file, this then can be used to generate a COBOL copybook.
msjavah ourFirstClass h2cpy -S -a float=1 -a dfloat=1 -Id:\msjavasdk\include -D__int64=long -Dva_list=void ourFirstClass.h
This will generate a copybook called ourFirstClass.cpy. From the copybook you will that a COBOL prototype for a the method. This is:
.... program-id. "c_typedefs" is external. special-names. call-convention cdecl-convention-val is cdecl-conv. $set constant ourFirstClass-ourFirstCOBOLmet "ourFirstClass_COBOLmethod" entry ourFirstClass-ourFirstCOBOLmet cdecl-conv using by value data-pointer returning long . end program "c_typedefs".
Next we need to declare a COBOL entry-point that matches the prototype above....
$set case linkage section. 01 HourFirstClass pointer. procedure division. entry "ourFirstClass_COBOLmethod" using by value HourFirstClass. display "Hello World from ourFirstCOBOLmethod" exit program returning 0.
Now let us create a DLL.... | |
---|---|
cobol NatCbl; cbllink -K -V -D NatCbl.obj gdi32.lib user32.lib msjava.lib Okay... now we are ready to try out the demo... so do it jview main You should now be look at.... | |
Hint: Where does msjava.lib, jview, mshavah come from? The library comes with the Microsoft SDK! |
Three API exists for calling Java Methods, these are: execute_java_dynamic_method, execute_java_static_method and FindClass.
Before a method can be called, you first need to locate the class itself. This can be done by calling the "FindClass" API.
The FindClass API takes three parameters, the first parameter is ALWAYS set to NULL. The second is a zero terminated string, which is the name of the class and the last is set to FALSE.
For example:
call MSJAVAsupAPI "FindClass" using by value 0 size 4, by reference z"Main", by value 0 size 4 returning HHelloWorldClass end-call
Once we have a pointer to the class, we can now execute a method inside the class. For example, if we have a static method inside the class "Main" called "HelloWorld". We would use:
call MSJAVAsupAPI "execute_java_static_method" using by value 0 size 4, by value HHelloWorldClass, by reference z"HelloWorld", by reference z"()V" end-call
What do the parameters mean? The First parameter is always set to NULL, the second is a handle the class (from FindClass), the third is the method name and the last is parameters type (or method signature).
A method signature is a two part string that describes the parameters pass into the java method and its return type. The parameter types are placed between the ( ... ). A table of signatures can be found in the reference section of this document.
For example, a signature for method with three parameters, passing into the method a boolean, byte and a short with a returning type of float would be: (ZBS)F.
call MSJAVAsupAPI "execute_java_static_method" using by value 0 size 4, by value HHelloWorldClass, by reference z"HelloWorld", by reference z"(ZBS)F)", by value ourBoolean, by value ourByte, by value ourShort, returning ourFloat end-call
Now that we can call Java methods from COBOL, we now have a wealth of functionality at our finger tips!
In the above example one parameter is passed into each and every native method. This data-pointer is a pointer to a native structure. For example:
class FieldDemo { int x; int y; int z; public native void SetFields(); static { System.loadLibrary("FldDemo"); } }
Assuming you have created a copybook, you should now have a copybook with a typedef, as follows:
01 ClassFieldDemo is typedef. 02 msreserved usage long. 02 x usage long. 02 y usage long. 02 z usage long.Now how does a COBOL application set these variables? Here is a little demo...
$set case mf ans85 copy "FieldDemo.cpy". identification division. working-storage section. 78 JavaClassName value "FieldDemo_". 78 JavaMethod value "SetFields". linkage section. 01 pClassFieldDemo ClassFieldDemo. procedure division. exit program. entry JavaClassName & JavaMethod using by reference pClassFieldDemo. move 10 to x move 20 to y move 30 to z exit program returning 0.
NB: Java strings are objects and also use the Unicode encoding method because of this we need to convert the string into a COBOL string. This can be done via a support API called 'javaString2CString'. For example:
call MSJAVAsupAPI "javaString2CString" using by reference lnk-string, by reference CobolString, by value 255 size 4 end-call
Java strings are real java objects because of this you need to create them via a API. This API can be found the Microsoft support module (msjava.lib).
For example to create a Java string with the contents 'Hello From COBOL' you would use:
$set ans85 mf defaultbyte"00" case identification division. special-names. call-convention 8 is MSJAVAsupAPI. working-storage section. 01 m-stringfromcbl Java-String. .... .... call MSJAVAsupAPI "makeJavaString" using by reference 'Hello From COBOL' by value 16 size 4 returning m-stringfromcbl end-call exit program returning 0.
To throw a Java exception from native code you need to call the support API called SignalError. For example:
call MSJAVAsupAPI "SignalError" using by value 0 size 4, by reference z"java/lang/OutOfMemoryError", by reference z"Failed to create string" end-call
The first parameter is the environment which should always be zero, the second is the class name of the Java exception you want to throw. The third is the "detail string" which can be zero if you wish.
Garbage collection is the most important issues for anyone who creates a "Native Java" method. Why is garbage collection important? By default the Java VM, disable the garbage collector before ANY call to a "Native Method" is performed. Anyone who uses Java everyday of the week, will understand the benefits of a good garbage collector. Therefore imagine disabling it!
With this in-mind the VM allows you enable to "garbage" collector, but before you enable it, you must protect "any" java objects you have created.
In-order to protect a Java object you must create a two areas in the COBOL local-storage section. These being: 1) a garbage area and the 2) being the garbage frame. For example:
local-storage section. 01 gc. 03 safe-object1 pointer. 01 gcf GCframe.
Once you have done this, you must populate the gc, with the objects you wish to protect. Then create a garbage collection stack frame, enable garbage collection.... go off any do you wicked "code"... then remove the stack frame etc...
Below is worked example:
import callback; class Main { public static void main(String args[]) { callback ourNativeObject; ourNativeObject = new callback(); ourNativeObject.COBOLmethod(); } static void HelloWorld(java.lang.String guess) { System.out.println("Hello World COBOL is " + guess); } } class callback { native static int COBOLmethod(); static { System.loadLibrary("NatCBL"); } }
$set ans85 mf defaultbyte"00" case copy "callback.cpy". identification division. special-names. call-convention 8 is MSJAVAsupAPI. working-storage section. 01 HHelloWorldClass ClassClass. 01 phString pointer. 01 our-Len int. 01 our-String pic x(10). local-storage section. 01 gc. 03 safe-object1 pointer. 01 gcf GCframe. linkage section. 01 Hcallback pointer. procedure division. entry "callback_COBOLmethod" using by value Hcallback. call MSJAVAsupAPI "makeJavaString" using by reference "Wicked!", by value 7 size 4, returning phString end-call set safe-object1 to address of phString call MSJAVAsupAPI "GCEnable" end-call call MSJAVAsupAPI "GCFramePush" using by reference gcf, by reference gc, by value length of gc end-call call MSJAVAsupAPI "javaString2CString" using by value phString by reference our-String by value length of our-String end-call call MSJAVAsupAPI "FindClass" using by value 0 size 4, by reference z"Main", by value 0 size 4 returning HHelloWorldClass end-call if HHelloWorldClass equal null call MSJAVAsupAPI "SignalError" using by value 0 size 4, by reference z"java/lang/OutOfMemoryError", by reference z"Class NOT Found!" end-call else call MSJAVAsupAPI "execute_java_static_method" using by value 0 size 4, by value HHelloWorldClass, by reference z"HelloWorld", by reference z"(Ljava/lang/String;)V", by value phString end-call end-if call MSJAVAsupAPI "GCDisable" end-call call MSJAVAsupAPI "GCFramePop" using by reference gcf end-call exit program returning 0.
Java Type | COBOL Type | Signature Type |
---|---|---|
CHAR | pic 9(4) comp-5 | C |
BYTE | pic s99 comp-5 | B |
SHORT | pic s9(4) comp-5 | S |
INT | pic s9(9) comp-5 | I |
Integer | pointer | Ljava/lang/Integer; |
FLOAT | comp-1 | F |
DOUBLE | comp-2 | D |
String |
01 Java-STRING is typedef. 02 msreserved usage Java-INT. 02 value usage data-pointer. 02 offset usage Java-INT. 02 count usage Java-INT. |
Ljava/lang/String; |
VOID | V |
01 Java-CHAR is typedef pic 9(4) comp-5. |
01 Java-BYTE is typedef pic s99 comp-5. |
01 Java-SHORT is typedef pic s9(4) comp-5. |
01 Java-INT is typedef pic s9(9) comp-5. |
01 Java-FLOAT is typedef comp-1. |
01 Java-DOUBLE is typedef comp-2. |
01 Java-STRING is typedef. 02 msreserved usage Java-INT. 02 value usage data-pointer. 02 offset usage Java-INT. 02 count usage Java-INT. |
References |
---|
Java in a NutshellA desktop quick reference for Java Programmers) |
Visual J++Learn hot web programming techniques with this java traing and
reference guide |
1001 JAVA Programmer's TipsThe most complete programmer's guide to JAVA and Visual J++ |