JNI に挑戦
COBOL(COBOLer)の延命治療に粉骨砕身するオープン系技術者としては、なんとか「自分=お釈迦様」、「COBOL(COBOLer)=孫悟空」にしたいものです。つまり、自分の手のひらの中で動いてほしいわけですね。
ということで、昨日 OpenCOBOL のインストール方法をご紹介しましたが、実は最終的な目標は COBOL プログラムを Java から呼び出すことなのです。
ただ、何かと融通の効かない COBOL 君です。いきなり Java から COBOL を呼び出すのは難しいので、Java - C - COBOL という構成で呼び出したいと思います。
それに先立ち、今回は Java から呼び出すプログラムを C で作ってみましょう。
まず、Java 側を作ります。
package bridge; public class HelloCobol { static { // libHello.so のロード System.loadLibrary("Hello"); } // ネイティブメソッドの宣言 public native void sayHello(); public static void main(String[] args) { HelloCobol helloCobol = new HelloCobol(); helloCobol.sayHello(); } }
このように書くと、libHello.so 内の sayHello() 関数を呼び出すことになります。パッケージ名は、なんでもいいですが、今回は bridge にしてみました。
次にこのクラスから、javah コマンドを使って C(C++)のヘッダファイルを生成します。上記のクラスをコンパイルしたものを指定します。
$ javah -jni bridge.HelloCobol
これで、以下のような bridge_HelloCobol.h というファイルができあがります。
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class bridge_HelloCobol */ #ifndef _Included_bridge_HelloCobol #define _Included_bridge_HelloCobol #ifdef __cplusplus extern "C" { #endif /* * Class: bridge_HelloCobol * Method: sayHello * Signature: ()V */ JNIEXPORT void JNICALL Java_bridge_HelloCobol_sayHello (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
この中に Java から呼ばれる関数のプロトタイプ宣言がありますので、これを参考に以下のように C プログラムを作成します。ファイル名はなんでもいいのですが、ここではヘッダファイルにあわせて bridge_HelloCobol.c とします。
#include <stdio.h> #include "bridge_HelloCobol.h" JNIEXPORT void JNICALL Java_bridge_HelloCobol_sayHello(JNIEnv *env, jobject obj) { printf("Hello, world!"); }
これをコンパイルします。Java のインストール先が環境変数 JAVA_HOME に入っているものとします。
$ gcc -shared -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ bridge_HelloCobol.c -o libHello.so
これで、libHello.so というファイルができあがります。
この libHello.so をライブラリパスに置くか、java のコマンドラインオプションで java.library.path で置き場を指定することで、実行時に動的リンクすることができます。たとえば、/home/hoge/lib の中にあるとすれば以下のようなコマンドで実行可能です。もちろん、bridge.HelloCobol クラスはクラスパス上にある必要があります。
$ java -Djava.library.path=/home/hoge/lib bridge.HelloCobol Hello, world!