AS/400展望台

Javaのプログラムコールをもっと簡単に



シャロン・ホフマン著

PCMLのスムーズなインタフェースが、iSeriesプログラムをJavaから呼び出す際のパラメータ変換を簡素化

Javaに関心を持っているiSeriesアプリケーションの開発者のほとんどは、RPGアプリケーションをJavaで置き換えたいなどとは思っていません。彼らはJavaをアプリケーション開発ツールキットに統合したいと思っているのです。具体的に言えば、iSeriesアプリケーションの開発者はiSeriesのデータやビジネス・ロジックを使用するJavaアプリケーションを作成したいのです。Javaアプリケーションはレコード・レベルのアクセスまたはJDBCを使用してiSeriesのデータに直接アクセスすることができますが、Javaを使用してRPGやCobolプログラムを呼び出す方が良い場合がほとんどです。このため、IBMはプログラム呼び出しマークアップ言語(PCML:Program Call Markup Language)を開発しました。PCMLはXMLの特殊な方言で、これを使えば、お馴染みのiSeriesの用語でプログラム呼び出し用のパラメータを定義することができます。
PCML文書を作成して使用することにより、JavaアプリケーションからiSeriesプログラムをどのように呼び出すかについて述べますが、まずその前にそのようなアプローチを取った方が良いのはどんな場合かについて考察します。

なぜJavaからRPGプログラムを呼び出すのか

プログラム呼び出しというアプローチを検討すべきなのは、いくつかの理由があるからです。まず、アプリケーションのビジネス・ロジックを処理するプログラムが既に存在する場合です。そのようなプログラムをJavaで書き直しても何の得にもなりませんし、書き直したとしても時間がかかる上、バグを入れ込んでしまうことにもなりかねません。

また、JavaアプリケーションからRPGプログラムを呼び出すと、クライアント/サーバー環境では性能が向上します。サーバー上で実行されるプログラムを呼び出すことにより、通信オーバーヘッドを削減でき、処理負荷をクライアント側からサーバー側へシフトさせることができるからです。特に、大量のデータベース処理をするアプリケーションは、データベースが格納されているサーバー上で実行する方が性能が向上します。iSeries上のRPGの効率の良さと今日のプログラマのスキル分布を考えれば、たとえ新しいプログラムを開発していたとしても、こうしたアプリケーションをRPGで書く方が理にかなっています。

さらに、レポートの印刷などのようにJavaよりもRPGの方が得意なタスクについては、呼び出しプログラムを使用することを考慮してみてください。Javaの印刷機能も改良されてはいますが、この分野ではRPGの方が優っています。長時間稼動するレポート・プログラムには、iSeriesのToolbox for Java(Toolbox)のCommandCallオブジェクトとSBMJOB(Submit Job)コマンドを使用してレポート・プログラムを起動しますが、個々の伝票などといった小規模のレポートには、Javaアプリケーションからレポート・プログラムを直接呼び出した方が良いでしょう。

おっとそれは痛い!

さて、JavaアプリケーションからRPGプログラムを呼び出す方が理にかなっている場合もあることがおわかりいただけたと思います。最初はプログラム呼び出しは簡単なタスクに見えるかもしれません。ToolboxがiSeriesのコマンドとプログラム呼び出しをサポートしていることはご存知でしょうから、何がそんなに問題なのかと疑問をお持ちでしょう。残念ながら、Javaのデータ・タイプはiSeriesのデータ・タイプとは大きく異なっているため、JavaとiSeriesコマンドやプログラムとの間でパラメータを渡す際には厄介な変換処理が必要になります。

iSeriesのデータの多くは固定小数点フィールド(ゾーン化数値またはパック化数値)かまたは文字フィールドで、ゾーン化数値やパック化数値はJavaのBigDecimalオブジェクトへ、文字フィールドはStringオブジェクトへといったように、適切なJavaオブジェクトへマッピングしてやらなければなりません。このマッピングはそれほど難しいものではないのですが、簡単なプログラム呼び出しでもかなりのコーディング量になります。IBMは、Toolboxの一部としてデータ記述や変換クラスを提供することにより、この作業負荷を多少は軽減しましたが、処理そのものは図1のAに示す通り依然としてかなり複雑なものです。(掲載スペースの関係で、本稿で使用しているコードの例はいずれもデータがハードコードされており、エラーチェックは完全ではありません。)

PCMLが救いの手を

PCMLを使用すると、Javaのデータ・タイプとiSeriesのデータ・タイプとの間の変換をマスクすることにより、JavaからのiSeriesプログラム呼び出しが簡素化されます。PCMLを使用してiSeriesプログラムを呼び出すJavaアプリケーションを記述するのは、以下のような簡単なプロセスです。

1. PCML標準に準拠した要素を含むXML文書を作成します。この文書は、プログラム名
  とそのプログラムが使用するinput/outputパラメータを指定します。

2. Javaアプリケーション中にProgramCallDocumentオブジェクトを作成し、
  iSeriesプログラム用のinputパラメータ値を設定して、callProgramメソッドを
  使用してプログラムを実行します。

3. iSeriesプログラムが返したoutputパラメータをJavaアプリケーション中で
  取り出します。Javaアプリケーション中のプログラム呼び出しが生成した
  メッセージであれば、どんなものでも調べることができます。

ToolboxにはPCMLを使用するのに必要なすべてのツールが揃っています。(どのコンポーネントをインストールする必要があるかについては、後述する「PCMLの前提条件」を参照してください。)Toolboxのインフラストラクチャが整ったら、各ステップをもっと詳しく見ていきましょう。

PCML文書

PCML文書には、iSeriesプログラムとそのパラメータ(input/outputパラメータを含む)を記述したXML要素が含まれています。図2はPCML文書の例です。PCML文書はどんなテキスト・エディタで作成しても構いませんが、ファイルを保存するときはその拡張子をpcmlとしてください。
XMLを知っていればPCMLファイルの中身を理解するのは簡単です。XMLは初めてという方は、XMLの基本的な構文を勉強してからPCML文書を作成した方が良いでしょう。

PCML要素にはprogram、data、struct の3つのタイプしかありません。ここでは各要素について、それぞれ代表的な属性について説明します。(PCMLに関する完全な説明についてはhttp://publib.boulder.ibm.com/pubs/html/as400/infocenter.htmlのiSeries情報センターでロケーション、リリース、言語を選択してください。情報センターに入ったらプログラミング、Java、IBM Toolbox for Java、プログラム呼び出しマークアップ言語、を選択します。)

program要素の属性の中で一番重要なのは、name属性とpath属性です。name属性は唯一必須の属性であり、PCML文書が記述するiSeriesプログラムの名前を指定します。path属性は統合ファイルシステム(IFS)の構文でiSeriesプログラムが格納されているライブラリを指定します。PCML文書のprogram要素中にpath属性を指定しない場合、JavaアプリケーションのProgramCallDocumentオブジェクトのsetPathメソッドを使用して、実行時にパス(ライブラリ名)を指定することができます。パスがPCML文書中にもJavaアプリケーションにも指定されていない場合は、iSeriesプログラムを探すデフォルトのライブラリはQSYSになります。またPCMLプログラム要素は、iSeriesサービス・プログラムを呼び出すためのentrypoint属性とreturnvalue属性もサポートしています。

iSeriesプログラムが使用する各パラメータに対して、data要素をPCML文書中に定義します。data要素で唯一必須の属性はtype属性です。type属性が持つことのできる値はbyte、char、float、int、packed、struct (structについては後述します)、zonedです。PCMLでは、これらの良く知られたiSeriesデータ・タイプ(char、packedなど)を使用してiSeriesプログラムのパラメータを指定します。iSeriesアプリケーションはiSeriesのデータ・タイプだけを扱い、JavaアプリケーションはJavaのデータ・タイプだけを扱います。たとえば、Javaアプリケーションはtype=“packed”を指定するパラメータに対してBigDecimalオブジェクトを提供し、ProgramCallDocumentオブジェクトはデータ変換を扱います。

PCMLのdata要素のその他の主な属性は以下の通りです。
・init ―この属性は、パラメータの初期値を指定します(usageがinputまたはinputoutputのパラメータに対して有効です)。

・ length ―パラメータ値の長さを定義します。

・ name ―名前付けパラメータは、参照や操作を容易にします。

・ precision ―この属性の意味は、type属性の値に依存します。パック化パラメータとゾーン化パラメータに対して、この属性は小数点の数を指定します。

・ usage ―この属性は、パラメータがinputパラメータなのか、outputパラメータなのか、inputoutputパラメータなのかを定義します。親要素がある場合、その親要素からこの属性を継承することもできます。デフォルトはinputoutputです。

struct要素を使用して、パラメータ記述中にデータ構造を定義できます。PCMLを使用せずにデータ構造を定義するのは、大変複雑なプロセスになります。struct要素には通常複数のdata要素が含まれています。struct要素の属性で唯一必須の属性はname属性です。struct要素用のusage属性を使用して、そのデータ構造がinputパラメータなのか、outputパラメータなのか、inputoutputパラメータなのかを定義することができます。

data要素もstruct要素も(さまざまな属性の他に)count属性、maxvrm属性、minvrm属性をサポートしています。count属性を使用して、その要素が配列であることを示します。配列中の要素数を指定する際、ハードコードしても構いませんし、実行時の配列要素数を含んだ名前付きdata要素を参照しても構いません。特定のパラメータに対してOS/400のリリース・レベルを指定するには、maxvrm属性およびminvrm属性を使用します。これらの属性の値はVxRxMxという形式で指定します。

PCMLを使ったプログラムの呼び出し

PCML文書を作成したら、次のステップではJavaアプリケーションからプログラムを呼び出します。図3に示すように、PCMLを使用してiSeriesプログラムを呼び出すにはまず、JavaアプリケーションがProgramCallDocumentをインスタンス化しなければなりません。これにはAS400オブジェクトとPCML文書の名前が必要になります(PCMLファイル名を指定する際には拡張子の.pcmlを省略します)。これらの値はProgramCallDocumentコンストラクタ(オブジェクトが生成されたときに呼び出されるメソッド)へのinputパラメータとして渡すか、またはオブジェクトが生成された後にsetSystemメソッドとsetDocumentメソッドを呼び出してそれぞれの値を設定することができます。

ProgramCallDocumentオブジェクトを正常に生成でき、PCML文書へのリンクができたら、ProgramCallDocumentオブジェクトのsetValueメソッドを使用してinputパラメータに値を読み込みます。正しいJavaのデータ・タイプ(たとえば文字パラメータに対してはStringオブジェクト)を使用する必要がありますが、Toolboxのデータ変換クラスを直接呼び出すことについては気にする必要はありません。図1のAと図3のBを比較すると、PCMLによってパラメータの定義とパラメータへの値の読み込みのプロセスが簡素化されていることがわかります。

inputパラメータとinputoutputパラメータの値を設定したら、ProgramCallDocumentオブジェクトのcallProgramメソッドを使用してiSeriesプログラムを実行します。iSeriesプログラム用のライブラリ名がPCML文書に指定されていない場合は、ProgramCallDocumentオブジェクトのsetPathメソッドを使用してライブラリ名を設定してから、iSeriesプログラムを実行します。図1のBと図3のAおよびCを比較すればわかりますが、iSeriesプログラムを呼び出すのに必要なコードの量はToolbox Program Callを使用してもPCMLを使用してもそれほど変わりません。

プログラム呼び出しの結果を調べる

プログラム呼び出しプロセスの最後のステップは、結果を調べることです。iSeriesプログラムがoutputパラメータを返す場合、またはiSeriesプログラムが戻り値を持つサービス・プログラムである場合、それらの値をJavaプログラム中で使用します。また、iSeriesプログラムが正常に終了したかどうかを確認し、出力を取り出します。

一番厄介なエラーは、呼び出しが正常に完了しなかった場合です。callProgramメソッドはブール値(true/false)を返してプログラム呼び出しが正常に終了したかどうかを示します。呼び出しが正常に終了しない原因のほとんどは、プログラム名やライブラリ名が正しく指定されていなかったり、iSeriesプログラムを実行するのに必要な権限を持っていなかったりというものです。図4のgetMessageListメソッドを使用すると、プログラム呼び出しが生成するメッセージをすべて調べることができます。(このプロセスはプログラム呼び出しでもPCMLでもまったく同じです。)

最後に、プログラムが正常に呼び出されて実行された場合は、ProgramCallDocumentオブジェクトのgetValueメソッドを使用して、usageがoutputまたはinputoutputであるパラメータの値を取り出すことができます。図1のCと図3のDを比較するとPCMLがこのプロセスを簡素化していることがわかります。getValueが返すJavaのオブジェクト・データ・タイプは、PCML文書中でそのパラメータ用に定義されているiSeriesのデータ・タイプに依存します。データ・タイプの対応を図5に示します。

PCML以外の手段

以上に説明した簡単な例は、JavaアプリケーションからiSeriesプログラムを呼び出すプロセスが、PCMLを使用することによりいかに簡素化されるかを示しています。ただし、PCMLを全面的に採用する前に、その他のオプションについても考慮すべきでしょう。

PCML以外の手段として最もエレガントなのは、iSeriesプログラムを外部ストアード・プロシージャとして登録し、JDBCを使用してJavaから起動するというやり方です。これはプログラム呼び出しを扱う方法としては完全にJava標準の方法で、このやり方で書かれたコードは移植性が高く、またこのやり方で身に付けたスキルも他に応用ができます。Javaアプリケーション中でのデータ・アクセスにJDBCを使用しているのであれば、iSeriesプログラムを呼び出す必要がある場合はいつでも、ストアード・プロシージャを使用するのが自然なソリューションです。

PCML以外の手段としてもう一つ挙げられるのは、ProgramCallクラスやCommand Call Toolboxクラスを使用する方法です。これらの方法のいずれかを使用するときは、Javaのデータ・タイプとiSeriesのデータ・タイプとの間のすべてのinput/outputパラメータを変換してやらなければなりません。ただし、これらのクラスはXMLパーサを使用する際に避けることのできない性能オーバーヘッドを回避することができます(PCMLファイルをシリアライズすると、性能ペナルティを低減することができます)。

さらに、アプリケーション全体をJavaで記述し、iSeriesのデータやその他のリソースに直接アクセスするという方法もあります。完璧に動作しているアプリケーション・ロジックを書き直さなければならない可能性があるだけでなく、クライアント上で実行しているJavaアプリケーションからiSeriesのデータにアクセスする際の性能面がたいへん心配されます。IBMはJavaの性能を大幅に向上させましたが、それでも複数のトランザクションや大量のデータをネットワーク上に送らなければなりません。データ保守アプリケーションに対してはJavaアプリケーション中でデータを直接操作する以外に良い手段はないかもしれませんが、トランザクションが複数のデータベースへのアクセスを必要とする場合は(PCML、ProgramCallまたはストアード・プロシージャ経由での)プログラム呼び出しの方が良いソリューションでしょう。

ギャップを埋める

JavaアプリケーションとRPGプログラムやCobolプログラムとを統合しようとしているiSeries開発者にとって、PCMLが唯一の選択肢というわけでは決してありません。しかしPCMLはパラメータ変換用のスムーズなインタフェースを提供しているので、JavaプログラムとiSeriesプログラムとの間のギャップを埋めてくれます。さらに、PCMLはiSeries開発者にとってはストアード・プロシージャによるソリューションよりもずっと直感的にわかりやすいのです。レコード・レベルのアクセスを使用してデータベースの情報を取り出すアプリケーションにはPCMLを選択すべきですが、データベースへのアクセスや(ストアード・プロシージャ経由の)プログラムの呼び出しには、可能であれば努めてJDBCを使う、というのが一般的でしょう。PCMLを多用する場合でも、必要に応じてのみ使う場合でも、Javaプログラミングの武器としてPCMLが有用であることはおわかりいただけるでしょう。

PCMLの前提条件

プログラム呼び出しマークアップ言語(PCML)を使用するには、IBM Toolbox for Javaのコンポーネントがいくつか必要になります。PCMLアプリケーションを開発するシステム上にToolboxをすべてインストールすることをお勧めします。その上で、特定のToolboxクラスとアプリケーションを一緒にパッケージ化するか、すべてのターゲットシステム上にすべてのToolboxをインストールします。
PCMLを使用するJavaアプリケーションは、Toolbox jt400.jarのクラスとXMLパーサ・クラスを必要とします。Toolbox XMLパーサ・クラスはx4j400.jarに格納されていますので、PCMLを使用するときは通常、jt400.jarとx4j400.jarの両方をクラスパスに含めておきます。

もう1つの方法として、Toolboxの最新のオープンソース版(JTOpen 3.3)が任意のソースからXMLパーサ・クラスを使用することができます。ただし、XMLパーサ・クラスの別の版を使用するためには、適切な.jarファイルをクラスパスに含めておく必要があります。たとえば私は、ApacheのWebサイトhttp://www.apache.orgから2つの異なる版のパーサ・クラスをダウンロードしました。1つは(「最新の安定しているバイナリ」と記されている)Xerces-J-bin.2.2.1.zipで、もう1つは(「最新のV1バイナリ」と記されている)Xerces-J-bin.1.4.4.zipです。これらのファイルを解凍すると、2つの異なる.jar構造が作られます。私が使用したPCMLの例でXerces-J-bin.1.4.4パーサ・クラスを使用するために、クラスパスにxerces.jarを含めました。Xerces-J-bin.2.2.1を使用するためには、クラスパスにxercesImpl.jarとXmlParserAPIs.jarの両方を含める必要がありました。現時点で利用可能な他のパーサの実装や、今後出てくるパーサの実装では、別の.jar構造を使用することになるかもしれません。

どの版のパーサ・クラスを使用するにしても、最適な性能を得るにはPCMLファイルをシリアライズして、実行時にPCMLパーサを呼び出さずに済むようにしておきます。PCMLファイルをシリアライズするのは、PCのコマンドラインから以下の構文で行えます。ここでiSNpcmlSample.pcmlはPCMLファイル名です。

java com.ibm.as400.data.ProgramCallDocument -serialize iSNpcmlSample

または、ProgramCallDocumentオブジェクトのserializeメソッドを実行すれば、Javaアプリケーション中からPCMLファイルをシリアライズすることができます。
ToolboxクラスやXMLパーサの他にも、PCMLはOS/400の分散プログラム呼び出し機能を使用します。

シャロン・L・ホフマンは小ホームページe-BELLNET.comの業務提携先Penton Technology Mediaのシニア技術編集者です。1981年にミッドレンジ・システム部門でIBMでのキャリアをスタートし、さまざまなアプリケーション開発や技術教育の開発や実施などのバックグラウンドを持っています。COMMONカンファレンスでも毎回講演しています。



↑このページのトップへ
TOPPAGE

BELLDATA, Inc. Copyright reserved.