前へJava から手続き型 COBOL を呼び出す Java から Object COBOL を呼び出す次へ

第 3 章 COBOL から Java を呼び出す

この章では、COBOL プログラムから Java オブジェクトにアクセスする方法について説明します。

3.1 概要

Micro Focus Java サポートでは、Object COBOL プログラムや Object COBOL クラスから Java オブジェクトへメッセージを送ることができます。Java は、Object COBOL の Java ドメインを経由してサポートされます。Java ドメインでは、COBOL プログラム内で Java クラスを宣言することができます。これにより、Java クラスへメッセージを送信できます。また、Java クラスから COBOL へメッセージを送信することもできます。詳細は、「Java から COBOL を呼び出す例」 の章を参照してください。

Java ドメイン サポートは、次の図に示すように、それぞれの Java オブジェクトに対して COBOL プロキシ オブジェクトを作成することで実現されます。宣言するクラス自身は、Java クラスの静的メソッドに対するプロキシです。

プロキシを経由する COBOL から Java へのメッセージ

図 3-1: Java プロキシ

COBOL ランタイム システムは、メッセージとともに送られるパラメータを COBOL データ型から Java データ型に変換します。メソッドがパラメータを戻す場合は、Java データ型から COBOL データ型へ変換されます。

この技術を効果的に使用するには、少なくとも Java 言語の基本知識が必要です。Java については、Sun Microsystems の Java サイトを参照することをお勧めします。

3.2 Java/COBOL サポートの設定

この項では、Java と COBOL を組み合わせて使用する前に行う必要がある設定について説明します。説明する項目には、Java から COBOL を呼び出す場合のみに適用される項目と、COBOL から Java を呼び出す場合のみに適用される項目があります。

3.2.1 COBOL と Java の環境設定

Java アプリケーションを実行するマシンには、Java ランタイム システムが必要です。Java と COBOL の混合アプリケーションを開発する場合は、Java 開発環境も必要です。Sun Microsystems から入手可能な Java Software Development Kit を使用するか、または、次にあげる Sun または Microsoft のランタイム環境に基づく Java IDE を使用することができます。

Net Express が現在、Windows 環境でサポートしている Java ランタイム システムは次のとおりです。

相互に動作する COBOL プログラム と Java プログラムを作成する前に、COBOL および Java のランタイム システムに対して環境変数をいくつか設定する必要があります。

Java を呼び出す COBOL プログラムがある場合は、どの Java ランタイム システムを使用するかを COBOL ランタイム システムに伝える必要があります。このためには、環境変数 COBJVM を次のいずれかに設定します。

たとえば次のとおりです。

set cobjvm=SUN

さらに、Sun Java ランタイム システムを使用している場合は、システム パスに Sun の jre\bin\classic サブディレクトリを追加します。たとえば次のとおりです。

set path=%path%;c:\jdk1.2.2\jre\bin\classic

これにより、このディレクトリにある jvm.dll ファイル を COBOL ランタイム システムが見つけることができます。jvm.dll は他の場所に移動させないでください。このファイルは、Sun Java ランタイム システムのほかのファイルに依存しているので、jre\bin\classic ディレクトリにある必要があります。

COBOL を呼び出す Java プログラムがある場合は、COBOL ランタイム システムへのインターフェイスとなる Java クラスをいくつか使用する必要があります。このためには、Java ランタイムの CLASSPATH 環境変数に mfcobol.jar を追加します。たとえば次のとおりです。

set classpath=%classpath%;c:\program files\merant\net express\base\bin\mfcobol.jar 

注記 : -classpath スイッチを使用して、Java プログラムの実行時に Java クラス パスを設定することもできます。たとえば次のとおりです。

java -classpath ".;c:\program files\merant\net express\base\bin\mfcobol.jar;%CLASSPATH%" MyClass

3.2.2 COBOL プログラムのコンパイラ指令

Java を呼び出す COBOL プログラムは、すべて次の指令でコンパイルする必要があります。

ooctrl(+p-f) 

このコンパイラ指令により、次の 2 つの操作が行われます。

3.2.3 Java プログラムのコンパイルにおける Net Express サポート

Net Express プロジェクトに追加された Java クラスは、プロジェクトをリビルドする際に IDE によってコンパイルされます。このサポートを設定するには、net express\base\bin ディレクトリの mfj.cfg を編集して、Java コンパイラへの完全パスとファイル名を含めてください。 また、NetExpressのメニュー[プロジェクト]-[ビルド設定]でJavaコンパイラに渡すパラメータを以下の手順で指定してください。

選択したビルドのフォルダにクラスファイルを作成する場合

-d %TARGETDIR %FILENAME

新規作成でプロジェクトに追加されるJavaのコンポーネントは、表示上、拡張子がclassではなく、clasになります (図 3-2 参照) が、実際にビルドする時には正しいクラスファイルが作成されます。

NetExpressプロジェクト内のJavaコポーネント

図 3-2: NetExpressプロジェクト内のJavaコポーネント

3.3 COBOL プログラムの作成

3.2.4 マルチスレッド COBOL プログラム

Java で使用する COBOL プログラムは、すべてマルチスレッド ランタイム システムにリンクさせる必要があります。

Net Express で、「プロジェクトのビルド設定」ダイアログ ボックスの [リンク] タブから [マルチスレッド] をクリックします。プログラムのデバッグを行っている場合は、[アニメート] メニューの [設定] をクリックして、「マルチスレッドの実行を使用」をチェックします。

この項では、Object COBOL Java ドメインを使用して、Java メソッドを呼び出す COBOL プログラムをコーディングする方法を説明します。作成するプログラムには、Class-Control 節を使用し、Java メソッドを呼び出すたびに INVOKE 動詞を使用する必要がありますが、Object COBOL クラスとして書く必要はありません。

Object COBOL Java ドメインを使用しないで Java プログラムを呼び出すこともできます。詳細は、「Java から手続き型 COBOL を呼び出す」 の章を参照してください。

3.3.1 Java クラスの宣言

COBOL プログラムで使用する Java クラスは、それぞれ Class-Control 節で宣言する必要があります。クラスが存在するパッケージは、パッケージの完全名の前に $java$ をつけて指定する必要があります。このプリフィックスは、COBOL ランタイム システムが Java ドメインからクラスをロードするように指示します。

たとえば次のとおりです。

 class-control. 
     jRectangle is class "$java$java.awt.Rectangle" 
     .

この例では、java.awt パッケージ中の Rectangle クラス の COBOL プロキシ オブジェクトとして jRectangle を宣言しています。このパッケージは、Java クラスパス上に存在している必要があります。存在していない場合は、プログラムが実行時に失敗します。

3.3.2 Java オブジェクトのインスタンス化

それぞれの Java クラスには、オブジェクトをインスタンス化するコンストラクタ メソッドがあります。Java では、コンストラクタ メソッドの名前はクラスの名前と同じです。COBOL からこれらのメソッドを呼び出せるように、これらのメソッドは COBOL プロキシ オブジェクトの "new" メソッド名にマップされます。

Java クラスのさまざまなコンストラクタは、それぞれ異なる数と組み合わせのパラメータを使用して、作成中のインスタンスをインスタンス化します。たとえば、Java Rectangle クラスは、次に示す 2 つの Java コード例を始めとして、さまざまな方法でインスタンス化することができます。

 Rectangle r1 = new Rectangle () //  長方形 (x,y) = 0,0, 幅=0, 高さ=0
 Rectangle r2 = new Rectangle(4, 5, 10, 20) // 長方形 (x,y) = (4,5), 幅=10, 高さ=20

これに相当する COBOL コードを次に示します。

 working-storage section. 
 01 r1                  object reference. 
 01 r2                  object reference. 
 ...

 procedure division. 
 ...
     invoke jRectangle "new" returning r1 *> 長方形 (x,y) = 0,0, 幅=0, 高さ=0
     invoke jRectangle "new" using 4, 5, 10, 20 
                         returning r2 *> 長方形 (x,y) = (4,5), 幅=10, 高さ=20

COBOL ランタイム システムは、パラメータの数と型を使用して Java クラスの適切なコンストラクタを呼び出します。Java は型付けが強い言語なので、Java クラスが予期する型のパラメータを指定することが大切です。「Java データ型」の章では、COBOL データ型が Java データ型にマップされる方法について説明しています。コピーファイル javatypes.cpy でも、Java データ型に直接対応する、COBOL で使用可能なデータ型のセットが定義されています。Java と COBOL の間でデータを転送する場合は、これらを使用することをお勧めします。

3.3.3 Java メソッドの呼び出し

Java オブジェクト上のメソッドはどれでも、メソッドと同じ名前でメッセージを送ることで呼び出すことができます。また、プログラムの Class-Control 段落で宣言したクラス名にメッセージを送ると、Java クラスの静的メソッドを呼び出すこともできます。Java の メソッド名は大文字と小文字を区別するので、COBOL でのメッセージ名は Java のメソッドの大文字と小文字と一致している必要があります。

Java には、メソッドのオーバーロードという機能があり、渡されるパラメータの数と型に応じて、1 つのメソッド名で異なる実体を定義することができます。COBOL では、この処理を透過的に行うので、常に正しい Java メソッドが呼び出されます。

たとえば、Rectangle クラスには異なる add() メソッドが 3 つあり、それぞれ異なるパラメータを受け取ります。次の Java コードは、長方形の add() メソッドを呼び出すことができる方法を 3 つ示しています。

 Rectangle r1 = new Rectangle(0,0,0,0) ;
 Point pt = new Point(6,6) ; 
 Rectangle r2 = new Rectangle(3,4,9,9) ;  
 r1.add(4,5) ; // r1 を、r1 とポイント 4,5 を含む最小の長方形に変更する
 r1.add(pt) ;  // r1 を、r1 と ポイント pt を含む最小の長方形に変更する 
 r1.add(r2) ;  // r1 を r1 と r2 の共用体

これに相当する COBOL は次のようになります。

 class-control.
     jRectangle is class "$java$java.awt.Rectangle"
     jPoint is class "$java$java.awt.Point"
     .
 working-storage section. 
 01 r1                 object reference. 
 01 r2                 object reference. 
 01 pt                 object reference. 

 procedure division. 
     invoke jRectangle "new" returning r1
     invoke jPoint "new" using 4 5 returning pt
     invoke jRectangle "new" using 3 4 9 9 returning r2
     invoke r1 "add" using 4 5  
     invoke r1 "add" using pt 
     invoke r1 "add" using r2 

r2pt はどちらもオブジェクト リファレンス型のデータ項目ですが、COBOL ランタイム システムは示された Java オブジェクトの型を判断して正しい Java メソッドを呼び出します。

3.3.4 Java 変数へのアクセス

Object COBOL プロキシで invoke "setname" および "getname" メソッドを使用すると、Java クラスのパブリック メンバーと静的変数にアクセスすることができます。Java では、変数名が大文字と小文字を区別するので、COBOL コードの name は Java コードで宣言した大文字小文字と一致している必要があります。

たとえば、次の Java クラスにはパブリック変数 classVal と instVal があります。

public class x {
    static int classVal;
    int instVal;
};

次の COBOL コードのサンプルでは、静的変数 classVal を設定して、次にメンバー instVal を取り込みます。

 $set ooctrl(-f+p)
 class-control.
     x is class "$Java$x"
     .

 working-storage section.
 copy "javatypes.cpy".
 01 anX                  object reference.
 01 anInt                jint.
 procedure division.
     invoke x "setclassVal" using by value 4
     invoke x "new" returning anX
     invoke anX "getinstVal" returning anInt

3.3.5 Java 例外の処理

Java が発生させた例外は、javexpt クラスに対して挙げられた Object COBOL 例外として COBOL に戻されます。デフォルトの例外の動作は、COBOL ランタイム システムが例外の警告メッセージを表示して、終了します。代わりに、COBOL プログラムに例外ハンドラを追加して、例外をトラップすることもできます。

次の手順は、最初にオンライン ヘルプで例外処理に関する情報を読むことを前提としています。Net Express の [ヘルプ] メニューで [ヘルプ トピック] をクリックして、[プログラミング][オブジェクト指向プログラミング][クラス ライブラリ フレームワーク][例外処理] を選択してください。

次の手順で Java 例外をトラップします。

  1. Class-Control 段落で、Exceptionmanager クラス、JavaExceptionManager クラス、および Callback クラスまたは EntryCallback クラスを宣言します。
    class-control. 
        ...
        JavaExceptionManager is class "javaexpt"
        ExceptionManager is class "exptnmgr"
        Callback is class "callback"
        EntryCallback is class "entrycll"
        ...
  2. 例外ハンドラ (クラス中のメソッド、またはエントリポイント) を書いて、それに対して Callback または EntryCallback を作成します。たとえば、 Callback は次のようになります。
    invoke Callback "new" using anObject z"methodName"
                      returning aHandler

    EntryCallback は次のようになります。

    invoke EntryCallback "new" using  z"entryPointname"
                      returning aHandler
  3. コールバックを JavaExceptionManger クラスに対して登録します。たとえば次のとおりです。
    invoke ExceptionManager "register"
             using OLEExceptionManager aHandler

これで、Object COBOL Java ドメインを経由して呼び出しているクラスから発生した Java 例外はすべてこの例外ハンドラに送られます。

次は、Java プログラムが発生させた例外をキャッチする COBOL プログラムの例です。

$set ooctrl (+p-f)
 program-id. ExceptionCatcher.

 class-control.
     SimpleClass is class "$JAVA$SimpleClass"
     EntryCallback is class "entrycll"
     JavaExceptionManager is class "javaexpt"
     ExceptionManager is class "exptnmgr"
     .

 working-storage section.
 01 theInstance                  object reference.
 01 wsCallback                   object reference.
 local-storage section.
 01 filler pic x.   *> ローカル エントリ ポイントをコールバックに
                    *> 使用させるためのダミー記憶域
 linkage section.
 01 lnkException                 object reference.

 procedure division.
*>---例外ハンドラの設定
     invoke EntryCallback "new" using z"JException"
                            returning wsCallback
     invoke ExceptionManager "register" using javaexceptionmanager
                                              wsCallback
*>---クラスのインスタンス化
     invoke SimpleClass "new" returning theInstance

     display "instantiated"
     invoke theInstance "TestException"
     display "excepted"
     stop run.


 entry "Jexception" using lnkException.
     invoke lnkException "display"
     .

上のプログラムの Local-Storage 節は、再帰を許可するためだけのものです。COBOL ランタイム システムは EntryCallback の呼び出しを再帰的呼び出しとして扱います。Local-Storage 節がない場合、実行時エラーが発生します。

次は、SimpleClass の Java コードです。

import java.lang.* ;

public class SimpleClass {

  public SimpleClass() {
  }

  public void TestException() throws Exception
  {
     Exception e = new Exception ("テスト エラー" );
     throw e;
  }
}

3.3.6 ネイティブ Java オブジェクトへのアクセス

Object COBOL Java ドメインを使用すると、Java オブジェクトへは直接アクセスしていないことになります。つまり、「概要」 で説明したとおり、常にプロキシを経由しています。javasup クラスの "getJavaObject" メソッドを使用すると、実際の Java オブジェクトへのポインタを取得することができます。Object COBOL Java ドメインで提供されていない Java の機能へアクセスしたい場合は、このメソッドを JNI (Java Native Interface) と合わせて使用することができます。

JNI ポインタを取得するには、javasup クラスで "getEnv" を呼び出します。JNI ポインタは関数テーブルへのポインタです。コピーファイル javatypes.cpy にあるデータ型 JNINativeInterface は、次の例で示すとおり、JNI 関数テーブルの使用を簡単にする構造体を提供します。

 working-storage section. 
 01 JEnv                        pointer.
 01 jobject                     pointer.
 linkage section.
 01 lnk-JNINativeInterface      JNINativeInterface.

*>
 procedure division.
     invoke javasup "getEnv" returning jEnv
*>   JEnv で渡されたポインタを 
*>   JNINativeInterface 構造体にマップして、
*>   JNI関数を呼び出せるようにします。
     set address of lnk-JNINativeInterface to JEnv
*>   

これで、JNINativeInterface 型定義によって与えられた名前を使用して JNI 関数を呼び出すことができます。呼び出す例については、「Java から手続き型 COBOL を呼び出す」の章の 「例外発生の例」 を参照してください。JNI についての詳細は、Sun Microsystems の Java サイトを参照してください。

javasup クラスについての詳細は、「クラス ライブラリ リファレンス」 を参照してください。 Windowsの[スタート]メニューの[プログラム]から、Net Expressのフォルダ内の[NetExpress オンラインマニュアル] を選択して、「クラス ライブラリ リファレンス」 のショートカット ボタンをクリックします。

3.3.7 Java オブジェクトの終了

Java ランタイムには、不要なオブジェクトを自動的に破棄するガーベッジ コレクタがあります。ガーベッジ コレクタは、他のオブジェクトに参照されていないオブジェクトを削除します。COBOL プログラムで Java オブジェクトへのプロキシを保持すると、COBOL ランタイム システムが Java オブジェクトへの参照を持ち、Java ガーベッジ コレクタがオブジェクトを削除するのを防ぎます。

Java オブジェクトの使用を終えた場合は、そのオブジェクトへの参照を解放してガーベッジ コレクタがそのオブジェクトを削除できるようにする必要があります。参照を解放しないと、アプリケーションにメモリ リークが発生します。次の手順でオブジェクトを終了します。

invoke javaobject "finalize" returning javaobject

ここで、returning のパラメータは重要です。パラメータを指定しないと、COBOL ランタイム システムは、COBOL プロキシを破棄する代わりにメッセージを実際の Java オブジェクトに渡します。メッセージが Java オブジェクトに渡された場合は、次の関数が呼び出されます。

public void finalize()

この関数は、すべての Java クラスによって継承または実行され、オブジェクトを破棄する前に Java ガーベッジ コレクタに呼び出されます。

万一 Java クラスが、値を戻す finalize() メソッドを実行した場合には、代わりに次の "delete" メソッドを使用して Object COBOL プロキシを破棄してください。

invoke javaobject "delete" returning javaobject


Copyright © 2000 MERANT International Limited. All rights reserved.
本書、ならびに使用されている 固有の商標と商品名は国際法で保護されています。

前へOLE データ型 Java から Object COBOL を呼び出す次へ