Creating Native Java Classes in COBOL
By Stephen Gennard (stephen@gennard.net)


This article assumes you're familiar with Java and Micro Focus COBOL


Document History


Introduction

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.

Contents

Why COBOL and Java?
A Simple Example
Accessing Fields
Calling Java Methods
Creating Java Strings
Generating Java Exceptions
Garbage Collection
What are the COBOL datatype mappings?
Generic COBOL DataTypes
Known restrictsion
Hints and tips
References

Why COBOL and Java?

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.


Java and COBOL compared?
Object Orientation? COBOL Java
Robust? Yes Yes
Secure?   Yes
Interpreted? Yes Yes
Portable? Yes Yes
Threads? Yes Yes
Garbage collection?   Yes
Exception handling? Sort of.. Yes
Business orientated? Yes  
Dynamic? Sort of.. Yes
Overall Application Performance High High
 
Key
YesFeature exists
Sort of..Feature half exists
 Feature does not exists

Given these points... why not use COBOL and Java together!

Now let's create our first Java/COBOL application...


A Simple Example

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!

Calling Java Methods


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!


Accessing Fields

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

Creating Java Strings


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.

Generating Java Exceptions


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


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.

What are the COBOL datatype mappings?

Java and COBOL Datatypes comparision table
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

The java type long currently has no COBOL datatype. The 'C' datatype is int64_t

Generic COBOL Datatypes table
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.

Hints and tips


Known restrictions


References

Java in a Nutshell


A desktop quick reference for Java Programmers)
by David Flanagan

Visual J++


Learn hot web programming techniques with this java traing and reference guide
BY Charles A. Wood

1001 JAVA Programmer's Tips


The most complete programmer's guide to JAVA and Visual J++
By Mark C. Chan, Steven W. Griffith, and Anthony F. Iasi


W3C Wilbur Checked!