もうちょっとマシなブリッジプログラムを作る

 つつましい COBOLer 、いや、COBOList の方々に COBOL プログラム作ったらブリッジの C プログラムも作っておいてなんて言ってもたぶん作りたがらないでしょう。なので、動的に COBOL 製モジュールを呼び出すブリッジプログラムを作りましょう。

 Java 側の仕様としては、まず最初に初期化処理を呼び出し、以降、モジュール名とパラメータで COBOL 製モジュールを呼び出すというものです。C のブリッジプログラムは、libj2cob.so というダイナミックリンク・ライブラリとします。

package bridge;

public class CobolBridge {
    static {
        // ライブラリのロード
        System.loadLibrary("j2cob");
    }

    /**
     * COBOL モジュールの初期化を行います。
     */
    public native void init();

    /**
     * COBOL モジュールを呼び出します。
     * 
     * @param moduleName COBOL モジュール名
     * @param parameter COBOL モジュールへのパラメータ
     */
    public native void callCobol(String moduleName, byte[] parameter);

    public static void main(String[] args) {
        CobolBridge cobolBridge = new CobolBridge();

        byte[] name = "Hoge      ".getBytes();

        cobolBridge.init();
        cobolBridge.callCobol("hello", name);
    }
}

 例のごとく javah でヘッダファイルを生成して、次は C のプログラムです。

#include <libcob.h>;
#include "bridge_CobolBridge.h"

/* 動的 COBOL モジュールのプロトタイプ宣言 */
static int (*cobMod)(char *);

JNIEXPORT void JNICALL Java_bridge_CobolBridge_init
  (JNIEnv *env, jobject obj)
{
    /* COBOL プログラムの初期化 */
    cob_init(0, NULL);
}

JNIEXPORT void JNICALL Java_bridge_CobolBridge_callCobol
  (JNIEnv *env, jobject obj, jstring modName, jbyteArray param)
{
    /* モジュール名の取得 */
    const jbyte *mn = (*env)->GetStringUTFChars(env, modName, NULL);

    /* モジュールの取得 */
    cobMod = cob_resolve((char *)mn);

    /* モジュール名資源のリリース */
    (*env)->ReleaseStringUTFChars(env, modName, mn);

    if (cobMod == NULL) {
        fprintf(stderr, "err %s\n", cob_resolve_error());
    } else {
        /* 引数の配列の参照を取得 */
        jbyte *p = (*env)->GetByteArrayElements(env, param, NULL);
        /* COBOL プログラムの実行 */
        cobMod((char*)p);
        /* 資源のリリース */
        (*env)->ReleaseByteArrayElements(env, param, p, 0);
    }
}

 これを機に Makefile も作ってしまいましょう。

TARGET=libj2cob.so
OBJS=bridge_CobolBridge.o

# JDK のありかは適宜修正してください
JAVA_HOME=/usr/local/java/latest
CC=/usr/bin/gcc
CFLAGS=-fPIC -g -I$(JAVA_HOME)/include/ -I$(JAVA_HOME)/include/linux/ `cob-config --cflags`
LIBS=`cob-config --libs`

all: $(TARGET)

clean:
    rm -f *.o $(TARGET)

$(TARGET): $(OBJS)
    $(CC) --shared -o $@ $^ $(LIBS)

.c.o:
    $(CC) $(CFLAGS) -c $<

 これで、make コマンドを一発たたけば libj2cob.so ができあがります。

 最後に COBOL です。今度はダイナミックリンク・ライブラリとしてビルドしなければなりませんので、前回の hello.cob を使い回しますが以下のように -m オプションをつけてビルドします。これで、hello.so ができあがります。libhello.so じゃありません。

$ cobc -m hello.cob

 実行時の注意としては、libj2cob.so は Java が呼びますので、Javaシステムプロパティ java.library.path 上になければなりませんが、hello.cob はそれとは関係なく、一般の C のライブラリパスに置いておく必要があります。とりあえずカレントディレクトリに置いておけば動きます。