The EasyLinkage feature
The isCOBOL Compiler can generate bridge classes that a Java program can use to easily call your COBOL programs. These bridge classes include an object for each Linkage Section data item; such object allows to set and inquire the data item value. The bridge class provides a method named run() that allows to call the COBOL program.
Note that only standard COBOL programs identified by a PROGRAM-ID can be called through EasyLinkage. It’s not possible to call COBOL objects that are identified by a CLASS-ID.
In order to make the Compiler generate bridge classes, the EasyLinkage feature must be activated through the following configuration setting:
iscobol.compiler.easylinkage=1
See Properties for the EasyLinkage feature for all the configuration settings that affect the EasyLinkage feature.
EasyLinkage and its settings can also be set directly in the source code through the SET Directive.
The generated bridge class is produced according to the current compiler options. For example, if the -jj option is used on the command line, then the Java source of the bridge program is left on disc. The only option ignored is -od; the bridge class is always generated in the "easylinkage" subfolder in the directory indicated by the setting of iscobol.compiler.generate.root_dir whose default is the same directory as the COBOL source file.
Let’s analyze a small practical example.
Consider the following COBOL program:
       program-id. prog1.
       linkage section.
       77 p1 pic 9.
       procedure division using p1.
       main.
           add 1 to p1.
           goback.
The EasyLinkage feature, run with default settings, generates a bridge class named linkPROG1 that includes an object named p1.
The following Java program calls PROG1 through the bridge class by passing the p1 parameter set to 1 and expecting it set to 2 when PROG1 returns.
public class test {
   public static void main (String[] args) throws Exception {
      //create an instance of linkPROG1
      linkPROG1 prog1 = new linkPROG1();
      //set the p1 parameter to 1
      prog1.p1.set(1);
      //do the call
      prog1.run();
      //check if p1 was incremented by 1
      if (prog1.p1.toint() == 2) System.out.print("OK");
   }
}
Note that the COBOL program uses the GOBACK statement in order to return to the calling Java program. If STOP RUN is used instead the whole JVM terminates.
If the COBOL program includes entry points, the Java program can call each entry point as a separate function. However, it’s important to call the main program first, like you would do with a caller COBOL program, otherwise the entry points are not available.
Additional usage (Java replacement for called functions)
The EasyLinkage feature is able to generate a stub class for every CALL statement found in the compiled program. This alternative usage is useful if you plan to provide a Java replacement or a Java implementation for some called functions. Two scenarios where this feature may be useful are:
replacement of C functions with equivalent Java functions in order to have a pure Java application,
implementation of a library routine that is currently missing in isCOBOL.
In order to make the Compiler generate stub classes, the EasyLinkage feature must be activated through the following configuration setting:
iscobol.compiler.easylinkage=2
See Properties for the EasyLinkage feature for all the configuration settings that affect the EasyLinkage feature.
EasyLinkage and its settings can also be set directly in the source code through the SET Directive.
The -od compiler option is ignored; the bridge class is always generated in the "easylinkage" subfolder in the directory pointed by iscobol.compiler.generate.root_dir whose default is the same directory as the COBOL source file.
Let’s analyze a small practical example.
Consider the following COBOL program:
       program-id. showtempdir.
 
       working-storage section.
       77 buflen   pic s9(4comp-5.
       77 pathname pic x(128).
 
       procedure division.
       main.          
           set buflen to size of pathname.
           call "GetTempPathA" using by value     buflen 
                                     by reference pathname.
           display pathname.
           goback.  
The program calls the GetTempPathA Windows API in order to retrieve the path of the system’s temporary directory. This program will work only on Windows systems and requires the isCOBOL interface to C (the dyncall library) in order to work.
By compiling the program with EasyLinkage enabled, you obtain the following Java source named GETTEMPPATHA.java, with the following content:
import com.iscobol.java.IsCobol;
import com.iscobol.java.StopRunAsException;
import com.iscobol.rts.IscobolRuntimeException;
import com.iscobol.rts.Factory;
import com.iscobol.rts.IscobolCall;
import com.iscobol.types.*;
 
public class GETTEMPPATHA implements IscobolCall {
 
   // Linkage variable declarations
 
   public byte returnCode$0[];
   public    com.iscobol.types.NumericVar returnCode;
   public    com.iscobol.types.NumericVar returnUnsigned;
   public byte transactionStatus$0[];
   public    com.iscobol.types.PicX transactionStatus;
   public java.lang.Throwable exceptionObject;
 
   //  variable declaration BUFLEN
   public byte buflen$0[];
   public    com.iscobol.types.NumericVar buflen;
   //  variable declaration PATHNAME
   public byte pathname$0[];
   public    com.iscobol.types.PicX pathname;
 
    {
      returnCode$0=Factory.getMem(8);
      returnCode=Factory.getVarBinary(returnCode$0,0,8,false,nullnull,null,"RETURN-CODE",false,18,0,true,false,false);
    }
    {
            returnUnsigned=Factory.getVarBinary(returnCode,0,8,false,nullnull,null,"RETURN-UNSIGNED",false,18,0,false,false,false);
    }
    {
      transactionStatus$0=Factory.getMem(2);
      transactionStatus=Factory.getVarAlphanumPrv(transactionStatus$0,0,2,false,nullnull,null,"TRANSACTION-STATUS",false,false);
    }
    {
          }
    {
      buflen$0=Factory.getMem(2);
      buflen=Factory.getVarNativeBinary(buflen$0,0,2,false,nullnull,null,"BUFLEN",false,4,0,true,false,false,false);
    }
    {
      pathname$0=Factory.getMem(128);
      pathname=Factory.getVarAlphanum(pathname$0,0,128,false,nullnull,null,"PATHNAME",false,false);
    }
 
  @Override
   public void perform(int arg0, int arg1) {
   }
   @Override
 
   public Object call(Object[] argv) {
      final int argl=(argv==null)?0:argv.length;
 
      switch (argl) {
      default:
      case 2: pathname.link((CobolVar)argv[1]);
      case 1: buflen.link((CobolVar)argv[0]);
      case 0: break;
      }
 
/*  Write here the routine logic
 *        This is the call prototype:
*
 *   try {
 *      returnCode.set(Factory.call("_new_GETTEMPPATHA", null,
 *                                  new CobolVar[] {pathname.byRef(),
 *                                               buflen.byVal()}));
 *   }
 *   catch (CallOverflowException ex) {
 *      throw new WrapperException(ex);
 *   }
 *
/
      return returnCode;
   }
 
   @Override
   @SuppressWarnings("deprecation")
   public void finalize() {
   }
 
}
You can add the necessary Java code to retrieve the temporary directory, e.g. replace the comment
/*  Write here the routine logic
 *        This is the call prototype:
*
 *   try {
 *      returnCode.set(Factory.call("_new_GETTEMPPATHA", null,
 *                                  new CobolVar[] {pathname.byRef(),
 *                                               buflen.byVal()}));
 *   }
 *   catch (CallOverflowException ex) {
 *      throw new WrapperException(ex);
 *   }
 *
/
with
pathname.set(System.getProperty("java.io.tmpdir"));
After compiling GETTEMPPATHA.java, you have a replacement for the GetTempPathA function.
From now on, the COBOL program will use the Java replacement instead of the original Windows API. In this way the program can work on every operating system and doesn’t require C libraries anymore.
EasyLikage uses the following rules to generate stub classes:
1. The name of the generated class will be the upper-case conversion of the name of the called function.
2. If the name is a data item rather than a constant string, then the data item name is used.
3. If the same function is called multiple times with different parameters, a separate stub for each different call is generated, along with a main stub that takes care of invoking the correct class depending on the parameters.
4. If the stub class already exists, it’s not generated again, in order to avoid accidental overwriting of code added by the user.
Generating both kinds of class
In order to generate both bridge classes and stub classes described above, use the following configuration setting
iscobol.compiler.easylinkage=3