Category Archives: Java

Scripting Languages and COBOL

The use of scripting languages with other languages has increased over the last couple of years, from a simple case of interoperability, reuse of scripting code to allowing your code to customised via the user of external scripts. All of which are real world examples I have seen customers use.

Interoperability between languages is very important to COBOL environments just as much as other languages. Some platforms such as Microsoft’s .Net with their CLR makes life much easier by allowing all languages to share a common infrastructure ie: the instruction set and the VM (MSIL and CLR) along with a base class library to get you started.

Environments such as Sun’s VM (JVM) provide two different approaches to interoperability with Java, the first is via JNI/JNA and the second is producing bytecode that runs as is on the VM.

Although the Micro Focus COBOL compiler does not support JVM bytecode or Java source generation it does have support for invoking classes/methods via the OO invoke verb.

This mechanism is very simple to use, you just need to let our object COBOL runtime know the class is a Java class, which can be done by placing $JAVA$ before the name of the class and ensuring the class itself can be found by the JVM itself usually by adding an extra directories or .jar files to the CLASSPATH environment variable.

With Java 6.0 and JSR 223 support for Java based scripting languages were provided via the package javax.script.

Java has a wealth of scripting languages from awk to xlst. My favourites being jpython, jruby and javascript.

The java.net website has a comprehensive list of scripting languages -
https://scripting.dev.java.net/.

To use the scripting packages, you first need to create a ScriptEngineManager, then use this to create a specific ScriptEngine object for your chosen scripting language and use it.

For example:

  • Create a ScriptEngineManager object.
  • Retrieve a ScriptEngine object from the manager.
  • Evaluate a script using the ScriptEngine object.
  • In COBOL this is quite simply:

          *> ooctrl(+p) required for COM and Java classes
          *> ooctrl(-f) used to preserve case of method names for Java
          $set ooctrl(+p) ooctrl(-f)

           class-control.
               cls-Script-EngineManager is
                   class "$JAVA$javax.script.ScriptEngineManager"
               cls-Script-Engine is
                   class "$JAVA$javax.script.ScriptEngine"
               cls-object is
                   class "$JAVA$java.lang.Object"
               cls-System is
                   class "$JAVA$java.lang.System"    
               cls-PrintStream is
                   class "$JAVA$java.io.PrintStream"
              .

           working-storage section.
           01 ws-obj-sem     object reference cls-Script-EngineManager.
           01 ws-javascript  object reference cls-Script-Engine.
           01 ws-obj         object reference cls-object.

           01 ws-pout        object reference cls-PrintStream.
           procedure division.
             invoke cls-Script-EngineManager "new"
                 returning ws-obj-sem
             end-invoke

             invoke ws-obj-sem "getEngineByName" using
                 "JavaScript" returning ws-javascript
             end-invoke

             invoke ws-javascript "eval" using
                 z"print('Hello, world!')"
                 returning ws-obj
             end-invoke

             if ws-obj not equal null
              invoke cls-System "getout" returning ws-pout
              invoke ws-pout "println"   using ws-obj
              invoke ws-pout "finalize"  returning ws-pout
              invoke ws-obj "finalize"   returning ws-obj
             end-if

          $if NO-FINALIZE not defined
             invoke ws-obj-sem "finalize"    returning ws-obj-sem
             invoke ws-javascript "finalize" returning ws-javascript
          $end
            stop run.

    The actual Javascript being execute is contained in the invoke statement, which is simply:

    print('Hello, world!')

    To use the above example, we first need to compile the code and run it.. which is done as follows:

    C:\jscripting\HelloWorld>cobol cbljscript.cbl int();
    Micro Focus Net Express V5
    Version 6.0.00059  Copyright (C) 1984-2009 Micro Focus (IP) Limited.
    URN AXCGG/AA0/00000
    * Checking complete with no errors - starting code generation
    * Generating cbljscript
    * Data:         848     Code:        1992     Literals:         904

    C:\jscripting\HelloWorld>runm cbljscript
    Micro Focus Net Express V6.0.00059                          
    RUN TIME ENVIRONMENT Copyright (C) 1984-2009 Micro Focus (IP) Limited.        
    URN AXCGG/AA0/00000                                                            
    Hello, world!

    This is just the start, the next thing piece that is required with interoperability to another language is the ability to pass parameters to in and out of the script. Luckily for us the clever chaps on the jsr group have provided ‘put’ and ‘get’ methods that allows us to simply put a name parameter and get the resulting updated or new parameter.

    So consider the example, where we need to setup a parameter called ‘message’ for the script and then read a parameter called ‘replyMessage’ after the script has been executed. The javascript to do this is:

    /* Do some insanity checking! */
    if (typeof(message) == 'undefined')
    {
        message = "ERROR - 'message' has not been setup"
    }

    println(message)

    replyMessage = "Hello from javascript"

    To setup the message parameter, we just need todo.

           *> Put a variable in engine, so the javascript
           *> can use it.
              invoke ws-javascript "put" using
                 z"message"
                 z"Hello World from COBOL!"
              end-invoke

    The after the script has executed, we just need to use the ‘get’ method..

           *> get a variable in engine
              invoke ws-javascript "get" using
                 z"replyMessage"
                 returning ws-message
              end-invoke
     
           *> now display the replyMessage if it is available
              if ws-message not equal null
                invoke ws-pout "println"   using ws-message
              else
                display "Javascript did not set a replyMessage var"

    The completed COBOL example below, uses a side file for the javascript too, the code is as follows:

          *> ooctrl(+p) required for COM and Java classes
          *> ooctrl(-f) used to preserve case of method names for Java
          $set ooctrl(+p) ooctrl(-f)

           class-control.
               cls-Script-EngineManager is
                   class "$JAVA$javax.script.ScriptEngineManager"
               cls-Script-Engine is
                   class "$JAVA$javax.script.ScriptEngine"
               cls-object is
                   class "$JAVA$java.lang.Object"
               cls-System is
                   class "$JAVA$java.lang.System"    
               cls-PrintStream is
                   class "$JAVA$java.io.PrintStream"
               cls-FileReader is
                   class "$JAVA$java.io.FileReader"
              .

           working-storage section.
           01 ws-file        object reference cls-FileReader.
           01 ws-obj-sem     object reference cls-Script-EngineManager.
           01 ws-javascript  object reference cls-Script-Engine.
           01 ws-obj         object reference cls-object.
           01 ws-message     object reference cls-object.

           01 ws-pout        object reference cls-PrintStream.
           procedure division.
          *> setup ws-pout to be System.out object
             invoke cls-System "getout" returning ws-pout

          *> Setup a FileReader object for the external helloworld.js file
             invoke cls-FileReader "new" using
                  z"helloworld.js"
                  returning ws-file
             end-invoke

          *> Create a new script manager
             invoke cls-Script-EngineManager "new"
                 returning ws-obj-sem
             end-invoke

          *> Find the javascript engine
             invoke ws-obj-sem "getEngineByName" using
                 "JavaScript" returning ws-javascript
             end-invoke

          *> Put a variable in engine, so the javascript
          *> can use it.
             invoke ws-javascript "put" using
                z"message"
                z"Hello World from COBOL!"
             end-invoke

          *> do some javascript stuff!
             invoke ws-javascript "eval" using
                ws-file
                returning ws-obj-sem
             end-invoke

          *> get a variable in engine
             invoke ws-javascript "get" using
                z"replyMessage"
                returning ws-message
             end-invoke

          *> now display the replyMessage if it is available
             if ws-message not equal null
               invoke ws-pout "println"   using ws-message
             else
               display "Javascript did not set a replyMessage var"
             end-if
       
           
          *> cleanup code, not strickly needed for the example but
          *> its good practice, to do it.
          $if NO-FINALIZE not defined
             if ws-message not equal null
                invoke ws-message "finalize" returning ws-message
             end-if
             if ws-pout not equal null
                invoke ws-pout "finalize"    returning ws-pout
             end-if
             invoke ws-obj-sem "finalize"    returning ws-obj-sem
             invoke ws-javascript "finalize" returning ws-javascript
          $end

             stop run.
    C:\jscripting\HelloWorld3>cobol cbljscript.cbl int();
    Micro Focus Net Express V5
    Version 6.0.00059  Copyright (C) 1984-2009 Micro Focus (IP) Limited.
    URN AXCGG/AA0/00000
    * Checking complete with no errors - starting code generation
    * Generating cbljscript
    * Data:         888     Code:        2528     Literals:        1296

    C:\jscripting\HelloWorld3>runm cbljscript
    Micro Focus Net Express V6.0.00059                          
    RUN TIME ENVIRONMENT Copyright (C) 1984-2009 Micro Focus (IP) Limited.        
    URN AXCGG/AA0/00000                                                            
    Hello World from COBOL!
    Hello from javascript

    As you can see from the code above, setting up parameter is pretty easy todo but sometimes we just want to execute a function in the scripting language such as:

    function testMessage(msg)
    {
        print("testMessage : " + msg);
    }

    The ScriptEngine object that we have created to use the scripting engine may implement an optional interface called javax.script.Invocable, if the scripting engine we are using does provide this interface then a method called invokeFunction(..) can be used.

    In order to reduce the size of the COBOL code, I have coded a simple utils class in java as a simple proxy layer, the code is pretty simple but does make it easier for the COBOL to use the invokeFunction() method.

    Then from the COBOL side, we can just use the invokeFunction above.</p>

    <p>For example:</p>
    <code lang="cobol" width="800" lines="-1" nowrap="0">
           *> invoke a function with one parameter
              invoke cls-utils "invokeFunction" using
                 ws-javascript
                 z"testMessage"
                 z"Hello to function testMessage from COBOL"

    Which gives us the following output when executed.

    C:\jscripting\InvokeFunction>runm cbljscript
    Micro Focus Net Express V6.0.00059
    RUN TIME ENVIRONMENT Copyright (C) 1984-2009 Micro Focus (IP) Limited.
    URN AXCGG/AA0/00000

    testMessage : Hello to function testMessage from COBOL

    The completed example is as follows:

          *> ooctrl(+p) required for COM and Java classes
          *> ooctrl(-f) used to preserve case of method names for Java
          $set ooctrl(+p) ooctrl(-f)

           class-control.
               cls-Script-EngineManager is
                   class "$JAVA$javax.script.ScriptEngineManager"
               cls-Script-Engine is
                   class "$JAVA$javax.script.ScriptEngine"
               cls-object is
                   class "$JAVA$java.lang.Object"
               cls-System is
                   class "$JAVA$java.lang.System"    
               cls-PrintStream is
                   class "$JAVA$java.io.PrintStream"
               cls-FileReader is
                   class "$JAVA$java.io.FileReader"
               cls-Utils is
                   class "$JAVA$utils"
              .

           working-storage section.
           01 ws-file        object reference cls-FileReader.
           01 ws-obj-sem     object reference cls-Script-EngineManager.
           01 ws-javascript  object reference cls-Script-Engine.
           01 ws-message     object reference cls-object.

           01 ws-pout        object reference cls-PrintStream.
           procedure division.
          *> setup ws-pout to be System.out object
             invoke cls-System "getout" returning ws-pout

          *> Setup a FileReader object for the external helloworld.js file
             invoke cls-FileReader "new" using
                  z"helloworld.js"
                  returning ws-file
             end-invoke

          *> Create a new script manager
             invoke cls-Script-EngineManager "new"
                 returning ws-obj-sem
             end-invoke

          *> Find the javascript engine
             invoke ws-obj-sem "getEngineByName" using
                 "JavaScript" returning ws-javascript
             end-invoke

          *> do some javascript function
             invoke ws-javascript "eval" using
                ws-file
                returning ws-obj-sem
             end-invoke

          *> invoke a function with one parameter
             invoke cls-utils "invokeFunction" using
                ws-javascript
                z"testMessage"
                z"Hello to function testMessage from COBOL"
                returning ws-message
             end-invoke

          *> cleanup code, not strickly needed for the example but
          *> its good practice, to do it.
          $if NO-FINALIZE not defined
             if ws-file not equal null
                invoke ws-file "finalize" returning ws-file
             end-if
             if ws-message not equal null
                invoke ws-message "finalize" returning ws-message
              end-if
             if ws-pout not equal null
                invoke ws-pout "finalize"    returning ws-pout
             end-if
             if ws-obj-sem not equal null
                invoke ws-obj-sem "finalize"    returning ws-obj-sem
             end-if
             if ws-javascript not equal null
                invoke ws-javascript "finalize" returning ws-javascript
             end-if
          $end

             stop run.

    Conclusions: Using a Java based scripting language from COBOL is quite easy, so feel free to use it. Now which scripting language should I use…?

    Using sun.jvmstat.monitor to see active Java processes

    Monitor’ing Java processes can be achieved using the jvmstat monitor classes provided in the JVM. The documentation is a bit sketchy but with a little experimenting it can be done.

    Below is a little example that shows you how to get a list of active Java processes.. which of course can then be used for other things :-)

    Here’s the code…

    import java.net.URISyntaxException;
    import java.util.Set;

    import sun.jvmstat.monitor.*;

    public class sjps
    {
       public static void main(String[] args)
              throws MonitorException, URISyntaxException
       {
          MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost("localhost");
          Set<Integer> activeVms = monitoredHost.activeVms();
          for (int psId : activeVms)
          {
             MonitoredVm monitoredVm = monitoredHost.getMonitoredVm
                       (new VmIdentifier(String.valueOf(psId)));
             String mainClass = MonitoredVmUtil.mainClass(monitoredVm, false);
             String vmVersion = MonitoredVmUtil.vmVersion(monitoredVm);
             String commandLine = MonitoredVmUtil.commandLine(monitoredVm);
             System.out.println(mainClass + " [" + psId + "]" +
                                           " using : "+vmVersion);
         System.out.println(" -> "+commandLine);
          }
       }

    }

    And to see the code running..

    $ java sjps
    sjps [865] using : 14.1-b02-90
     -> sjps
    JConsole [863] using : 14.1-b02-90
     -> sun.tools.jconsole.JConsole

    Java process id via java.lang.management

    While working on a project recently I need to find out the current process of the active running Java process (for tracing/auditing), however I never found a 100% perfect solution but did come across an acceptable solution to use the management classes to query its name, which happens to have encoding in it, so here is the quick solution:

    import java.lang.management.ManagementFactory;

    public class getpid
    {
      public static void main(String args[]) throws Exception
      {
          System.out.println("Process id : "+getProcessId());
      }

      public static long getProcessId()
      {
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String[] nameBits = name.split("@");
       
        return nameBits == null ? -1 :  Long.valueOf(nameBits[0]);
      }
    }
    $ java getpid
    Process id : 377

    Fiddling with the JVM

    Java is a very safe language if used in a normal way, however just like the CLR it can be used in an unsafe manor.

    The main reason for using Java in a unsafe manor is performance, some unsafe operations are optimised by the JVM itself.

    The boot class loader grants enough permissions to access a key undocumented class sun.misc.Unsafe. As I will state, this is an undocumented class and as the name implies it’s unsafe.

    This class provides methods that allows you to manipulate objects and the memory of the objects directly.

    For example, you could use it to access the object itself, lets look at an example to manipulate a String object.. not nice I hear you say…. and boy are you are so right. The purpose of this example is to demonstrate the power of the JVM if used to the extreme but not to demonstrate how to destroy the JVM.

    import sun.misc.Unsafe;
    import java.lang.reflect.Field;

    //  To Compile: javac BadBoy.java
    //  To Run:        java -Xbootclasspath/p:. BadBoy

    public class BadBoy
    {
      private final static  Unsafe  unsafe  = Unsafe.getUnsafe();
     
      public static void main(String args[]) throws Exception
      {
       // Find the field "count" inside java.lang.String
       Field field = String.class.getDeclaredField("count");

       // Find the memory offset within the field...
       long countOffset = unsafe.objectFieldOffset(field);

       field = String.class.getDeclaredField("offset");
       long offset4Offset  = unsafe.objectFieldOffset(field);

       // Lets read the memory directory...
       Object  object = "Hello World from Java, the ultra safe language... or is it..";

       int length = unsafe.getInt(object, countOffset);
       System.out.println("The original Length is length: " + length);

       System.out.println("1- The 'object' contains : ");
       System.out.println(" -> "+object);
       System.out.println("  hashCode is : " + object.hashCode());

       unsafe.putInt(object, offset4Offset, 17);
       unsafe.putInt(object, countOffset, 32);
       System.out.println("2- The 'object' contains : ");
       System.out.println(" -> "+object);
       System.out.println("  hashCode is : " + object.hashCode());
     }
    }

    Then, the output of the example on my little macbook is:

    stephen-gennards-macbook:blob spg$ java -Xbootclasspath/p:. BadBoy
    The original Length is length: 60
    1- The 'object' contains :
     -> Hello World from Java, the ultra safe language... or is it..
      hashCode is : 573430574
    2- The 'object' contains :
     -> Java, the ultra safe language...
      hashCode is : 573430574

    As you can see the String object is changed but the hashCode remains the same. :-)

    Even if the above example seems weird to the extreme and it is, I offer you one take home from this blog…

    Be very careful what you place on your “bootclasspath!”

    Object COBOL/Java default exception handler

    While working on some support recently for our compiler (Micro Focus COBOL compiler that is), I became annoyed with the lack of a reasonable error messages/stack trace output from our Java/COBOL Object support.

    I have no idea why our default exception handler for Java exceptions just displays a such a simple message with little or no information.

    For those who have not seen it, display something similar to:

    Exception 65537 not trapped by the class javaexceptionmanager.
    Description: "Java exception"
    Test error
    Hit T to terminate program. Hit any other key to continue.
    instantiated - test

    Exception 65537 not trapped by the class javaexceptionmanager.
    Description: "Java exception"
    Test error
    Hit T to terminate program. Hit any other key to continue.

    Luckily for me and you, we do expose a mechanism for replacing the default exception handler.

    Anyway, with very little effort I created a different “default” system exception handler that display this instead:

    instantiated - test 1
    java.lang.Exception: Test error
            at SimpleClass.TestException(SimpleClass.java:10)

    WARNING: JavaException: Test error
    instantiated - test 2
    java.lang.Exception: Test error
            at SimpleClass.TestException(SimpleClass.java:10)
    WARNING: JavaException: Test error

    The key difference being that a Java stack trace is included, boy did this help me.

    The program below is the code that implements the exception handler. I am sure someone else can take this example and make it much nicer and provide more features but for this blog I will keep it simple.

          $set ooctrl (+p-f) case
           program-id. ExceptionCatcher.
           
           class-control.
                 EntryCallback is class          "entrycll"
                 JavaExceptionManager is class   "javaexpt"
                 ExceptionManager is class       "exptnmgr"
                 Javasup is class "javasup"
                 .
           
           working-storage section.
           01 wsCallback                   object reference.
           01 wsIterator                   object reference.
           01 theJavaException             object reference.
           local-storage section.
           01 filler pic x.   *> dummy storage item to allow recursion
           linkage section.
           01 lnkException                 object reference.
           01 lnkErrorObject               object reference.
           01 lnkErrorTextCollection       object reference.
           01 lnkErrorNumber               pic x(4) comp-5.
           01 anElement                    object reference.
             procedure division.
          *>---Set up system level Exception handler
                 invoke EntryCallback "new" using
                        z"JException"
                        returning wsCallback
                 end-invoke

                 invoke ExceptionManager "register" using
                        javaexceptionmanager
                        wsCallback
                 end-invoke

                 invoke EntryCallback "new" using z"DispError"
                   returning wsIterator
                 end-invoke

                 goback.
           
           
             entry "Jexception" using
                      lnkException
                      lnkErrorNumber
                      lnkErrorTextcollection
                 .

                  invoke javasup "exceptionOccurred"
                       returning theJavaException
                  end-invoke

                  if theJavaException not equal null
                    invoke theJavaException "printStackTrace"
                  end-if
               
                  invoke lnkErrorTextCollection "do" using wsIterator
                  goback.
                 .

              entry "DispError" using anElement
                display "WARNING: JavaException: " with no advancing
                invoke anElement "display"
                display " "
                goback.
                 .

    To use the above code, you just have to first cut-paste to code into a file called ExceptionCatcher.cbl and include this in your project, and then add the directive INITCALL”ExceptionCatcher”, then away you go.

    My test programs for the above example are:

         $set ooctrl (+p-f) case
           program-id. jtest.
           
           class-control.
                 SimpleClass is class            "$JAVA$SimpleClass"
                 .
           
           working-storage section.
           01 theInstance                  object reference.
           local-storage section.
           01 filler pic x.   *> dummy storage to allow the local entry
             procedure division.
          *>---Instantiate the class
                 invoke SimpleClass "new" returning theInstance
           
                 display "instantiated - test 1"
                 invoke theInstance "TestException"

                 display "instantiated - test 2"
                 invoke theInstance "TestException"
                 stop run.

    and the Java class itself:

    import java.lang.* ;

    public class SimpleClass {
      public SimpleClass() { }

      public void TestException() throws Exception {
         throw new Exception ("Test error" );
      }
    }

    References: Studio Enterprise 6.0 Document for COBOL/Java Interop