COBOL with JDBC and GraalVM
By: Roberto Ferrari
Tags: Postgresql, Graalvm, Native, Cobol, Jdbc

COBOL has always been and continues to be a huge part of our lives. Yet, most of us have never heard of it. About 95 percent of ATM swipes use COBOL code — Reuters reported in April 2017 — and the 58-year-old language even powers 80 percent of in-person transactions. In fact, Reuters calculates that there is still 220 billion lines of COBOL code currently being used in production, and that COBOL systems handle $3 trillions in commerce every day.

Since approximately two decades, many big companies have been looking for downsizing their legacy applications from mainframe to other platforms with the aim of reducing costs. The problem is that it results not to be a forward-looking choice. They were simply creating a “new” COBOL solution, which would have required new skills, more resources in addition to existing ones and greater complexity. As result it would have become outdated quite quickly.

The solution has to be gradual and safe by extrapolating individual application modules from current legacy applications, and rewriting them using a modern language, thus exploiting the technological features that such language makes available. Only in this way it will be possible to reduce the number of lines of code, and consequently reduce the number of COBOL developers required for software maintenance.

GraalVM, an Oracle Labs initiative in collaboration with open source community supported by VMWare, Red Hat, Microsoft, Twitter, Amazon and more, may help in order to achieve this goal. It is a new universal virtual machine that supports both a polyglot runtime environment and the ability to compile Java applications down to native machine code. GraalVM removes the isolation between programming languages and enables interoperability in a shared runtime.

Scope

The purpose of this article is to demonstrate the interoperability between COBOL and Java code using GraalVM Native Image. It will be built a simple COBOL program that will use JDBC to access an SQL database, in this case PostgreSQL.

Prerequisites

The instructions of this post have been tested on Linux. To reproduce the following code, these tools are required:

A GraalVM Community Edition based on JDK11 (or JDK8) for Linux with the additional component Native Image.

Available here: https://www.graalvm.org/downloads/.

Community Edition based on JDK11 (or JDK8) for Linux with the additional component Native Image. Available here: https://www.graalvm.org/downloads/. The C standard library headers . On Linux it depends on the distribution adopted.

. On Linux it depends on the distribution adopted. A C compiler . It will be used to build a native shared library. In order to do that as well, install gcc or clang .

. It will be used to build a native shared library. In order to do that as well, install or . A PostgreSQL database instance. It can be downloaded from PostgreSQL: Downloads.

database instance. It can be downloaded from PostgreSQL: Downloads. Maven , a build automation tool.

, a build automation tool. nm utility tool (optional) for inspecting the results. It is usually installed by default.

The system should look like this:

$ lsb_release -a

No LSB modules are available.

Distributor ID: Ubuntu

Description: Ubuntu 20.04.1 LTS

Release: 20.04

Codename: focal $ gcc --version

gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

Copyright (C) 2019 Free Software Foundation, Inc. $ gu list

ComponentId Version Component name Origin

--------------------------------------------------------------------

js 20.3.1 Graal.js

graalvm 20.3.1 GraalVM Core

native-image 20.3.1 Native Image



$ psql --version

psql (PostgreSQL) 13.1 (Ubuntu 13.1-1.pgdg20.04+1)

Setup

The project folder is created under $HOME with cobol-pg as name, but any label is valid.

$ cd $HOME

$ mkdir cobol-pg

$ export TMP_DIR=~/cobol-pg

$ cd $TMP_DIR

$ mkdir native

The first thing that needs to be done is to set up some environment variables so that all GraalVM tools can run. The commands can be found in the script setup.sh , which looks like this:

# set workdir - You can use the folder that you want

export TMP_DIR=~/cobol-pg # set graalvm home directory

export GRAALVM_PATH=~/graalvm-ce-java11-20.3.1 # set javalvm home directory

export JAVA_HOME=${GRAALVM_PATH} # set the PATH variable

export PATH=$GRAALVM_PATH/bin:$PATH # set the path for graalvm libraries

export GRAALVM_LIBRARIES_PATH=$GRAALVM_PATH/languages/llvm/native/lib # export the path for gnucobol

export NATIVE_LIBRARIES_PATH=$TMP_DIR/native # include cobc in search path

export PATH=$NATIVE_LIBRARIES_PATH/bin:$PATH # export the variable where libraries should be searched for first

export LD_LIBRARY_PATH=${NATIVE_LIBRARIES_PATH}/lib:${GRAALVM_LIBRARIES_PATH}:${TMP_DIR}/target

Execute the script with the command:

$ source setup.sh

Building GNUCOBOL in Native

GnuCOBOL is a free, modern COBOL compiler. It translates COBOL into intermediate C and compiles the code using a native C compiler (preferably gcc , but not limited to it).

Now that all environment variables are set, we can compile GnuCOBOL for GraalVM in native mode. GnuCOBOL for mathematical functions requires either GMP or MPIR and for file management Berkeley DB (libdb), VBISAM or DISAM. Here GMP and VBISAM are adopted.

Now download GNUCOBOL source and its dependencies:

wget https://sourceforge.net/projects/gnucobol/files/gnucobol/3.1/gnucobol-3.1.2.tar.gz

$ tar -xf gnucobol-3.1.2.tar.gz -xf gnucobol-3.1.2.tar.gz wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.lz

$ tar --lzip -xvf gmp-6.2.1.tar.lz $ tar --lzip -xvf gmp-6.2.1.tar.lz wget http://rjnorman74.users.sourceforge.net/vbisam-2.1.1.tar.Z

$ tar -xf vbisam-2.1.1.tar.Z -xf vbisam-2.1.1.tar.Z

First of all compile the two dependencies, executing the following instructions for VBISAM:

$ cd $TMP_DIR/gnucobol/vbisam-2.1.1

$ ./configure --prefix=${NATIVE_LIBRARIES_PATH}

$ make

$ make install

and the following for GMP:

$ cd $TMP_DIR/gnucobol/gmp-6.2.1

$ ./configure --prefix=$NATIVE_LIBRARIES_PATH

$ make

$ make install

Now compile GNUCOBOL:

$ cd $TMP_DIR/gnucobol/gnucobol-3.1.2

$ ./configure CFLAGS="-I${NATIVE_LIBRARIES_PATH}/include" LDFLAGS="-L${NATIVE_LIBRARIES_PATH}/lib" --disable-nls --with-vbisam --with-curses=no --prefix=${NATIVE_LIBRARIES_PATH}

$ make

$ make install

Create database and datatable

The library in this project uses the JDBC Driver for PostgreSQL, which can be installed executing the following commands:

sudo apt-get update -y

sudo apt-get install -y libpostgresql-jdbc-java

Then create a database called testdb with the following instruction:

CREATE DATABASE testdb

WITH

OWNER = postgres

ENCODING = 'UTF8'

LC_COLLATE = 'C.UTF-8'

LC_CTYPE = 'C.UTF-8'

TABLESPACE = pg_default

CONNECTION LIMIT = -1;

and the table CUS with:

CREATE TABLE public.cus

(

cus_id numeric(4,0) NOT NULL,

cus_name character(20) COLLATE pg_catalog."default",

cus_age numeric(3,0),

CONSTRAINT cus_pkey PRIMARY KEY (cus_id)

) TABLESPACE pg_default; ALTER TABLE public.cus

OWNER to postgres;

Create a shared library from Java

GraalVM allows ahead of time compilation of Java code to a standalone executable called “native image”. It includes the application classes, classes from its dependencies, runtime library, classes from JDK, and statically linked native code from JDK by using AoT (ahead-of-time compiler) directly for a specific operating system and architecture. It does not run on the Java VM, but includes necessary components like memory management and thread scheduling from a different virtual machine called “Substrate VM”.

GraalVM’s native-image command is capable of creating a shared library from Java code and thus combining the polyglot approach with native-image.

A native image can be built either as a standalone executable, which is the default, or as a shared library with the command line switch --shared. The tool is able to create shared C libraries which open up a whole new world of polyglot interaction. Take anything that runs on GraalVM native image — either Java or one of the supported target languages — and build a library that can be applied in COBOL, C and C# programs or anything that allows foreign-function-interfaces (FFI).

In this example it will be called a function that takes authentication details to a PostgreSQL, executed a simple query and returned data to COBOL caller program via a shared C library using Isolate, a virtualization feature supported by GraalVM. A Isolate is a disjoint heap that allows multiple tasks in the same VM instance to run independently in the same process, so each isolate can be garbage-collected independently (or just destroyed before any GC is needed).