メニューボタン
サポートチーム便り2012.01.16

RPGプログラム内にCLASSPATHを設定しないこと!

Question

Mr. Klement、私はあなたの JDBC コードを使用してスプレッドシートを作成しています。ただし、この質問は HSSF/POI、JFreeChart、また Java が RPG から呼び出される他のシナリオにも当てはまります。putenv() API を使用して自分のプログラムに CLASSPATH を設定したいと考えています。あなたのメッセージを見ると、これは非常に良くないとおっしゃっていますね。なぜそうなのでしょうか。RPG プログラムがその自分の依存関係にリンクしているのは理想的とも思えるのですが。

Answer

回答者
Penton Media,Inc.
Scott Klement

ちょっと思い付いたんですが、私がボックスのアップグレードをした後、問題が発生し、あるネットワーク接続に影響がでました。IBM サポートにアドレスを読んで聞かせるまで、アドレスのうち 1 つが本来あるべき姿とは逆の数値を2 つ持っていたことに気が付きませんでした。2 つチェックを行うことをお勧めします。まず、別の人があなたの設定シートを見ながら情報を確認しつつ、設定を読み上げること。次に、設定計画中のアドレス指定のレプリケーションを確認することです。実際、3 つ目のチェックとして、システムの回線速度と二重設定が、新しい DMZ スイッチ設定と互換性があることも確認します。

私がそう言ったのは、CLASSPATH 変数はアプリケーションの一部ではなく、環境設定でなければならず、その値はジョブごとに一度だけチェックされるためです。「環境」の意味するところと、なぜそれが重要なのかをご説明します。

CLASSPATH はライブラリー・リストのようなものです。ただし、それは IFS オブジェクトのリストであり、Java クラスを見つけるときだけ使用される点が異なります。ライブラリー・リストを RPG プログラムの中に設定したりはしないでしょう? もちろん、しないですよね。中に設定すると、プログラムのテストが難しくなります。異なるライブラリーからオブジェクトを取得するためにコードを変更する必要があり、それは頭が痛い話です。ですから、RPG プログラム中にライブラリー・リストをハードコーディングすることは絶対にありませんね。

CLASSPATH にも同じことが言えます。他の Java JAR ファイルをテストしたいときはどうしますか? CLASSPATH をプログラム中にハードコーディングしていると、テストできません。プログラム中にそれをハードコーディングすることはないと思います。

CLASSPATH をハードコーディングすることは、ライブラリー・リストをハードコーディングすることだと言ったのです。しかし実際、ハードコーディングされた CLASSPATH の方が性質 (たち) が悪いです。CLASSPATH は Java 仮想マシン (JVM) により一度だけ読み取られます。これは JVM メモリーに読み込まれたときに行われます。RPG が Java コードを呼び出すと、ジョブの残り時間中 JVM はメモリーに保持されます。ジョブを終了して、新しいジョブを開始する以外、JVM をアンロードまたは再ロードする方法はありません (つまり対話式ジョブの場合、サインオフしてから、再度サインオンする必要があるということです。)

仮に次の内容を実行するジョブ・ストリームを実行しているとしましょう。

  • JDBC を使用して SQL サーバーからデータを取得し、QTEMP 内のファイルに保存する
  • JFreeChart を使用して QTEMP 内のファイルからグラフを作成する
  • HSSF を使用して QTEMP 内のファイルからスプレッドシートを作成し、グラフに組み込む

JDBC プログラムがまず実行され、CLASSPATH が、それが必要とする JAR ファイルにのみ設定されます。ジョブ・ストリームの他のプログラムは意識していません。最初に Java を使用するのがこのプログラムであるため、メモリーに読み込まれた (CLASSPATH を読み取る) JVM の役割を果たし、動作します。すべてはうまくいっています。

次に JFreeChart プログラムが実行され、CLASSPATH が、今度はそれが必要とする JAR ファイルを使用して設定されます。グラフを作成しようとしますが、失敗します。なぜでしょうか? JVM はすでにメモリーにあるからです。JVM は JDBC プログラムにより読み込まれました。したがって CLASSPATH は再度読み取られることはありません。JVM が読み込まれたときに JFreeChart JAR ファイルが CLASSPATH になかったため、JVM はそれらのファイルを見つけることができません。CLASSPATH がプログラム中にハードコーディングされていても、依存関係は見つかりません。まずいですね。それで、もしなんとかその回避方法を見つけたとしても (私には思いつきませんが)、HSSF プログラムが実行された後で問題が再現するでしょう。

では、解決方法は何でしょうか。そうですね、すべての JAR ファイルを組み込むよう JDBC プログラムの CLASSPATH コードを変更できます。しかし、ジョブの実行中にあなたが行うことすべてをJDBC プログラムに意識するよう期待するのは妥当でしょうか。

私の言わんとしていることがおわかりと思います。このように CLASSPATH を設定してもうまくいきません。

私にとって *LIBL といった設定は「環境設定」です。アプリケーションにより設定されるべきものではなく、ジョブの動作方法の一部として構成すべきものなのです。これらの設定は、パワー・ユーザーが必要に応じて異なった動作にするときに、ジョブ中で変更できるものです。

もちろん *LIBL は我々全員がよく知っている (と思いますが) ものです。しかし CLASSPATH、JAVA_HOME、また QIBM_RPG_JAVA_PROPERTIES も同じカテゴリーに分類されます。個人的には、これらの変数を設定する CL プログラムがあります。これは図 1 でご覧いただけます。

この CL プログラムは一回だけ呼び出す必要があります。LEVEL(*SYS) を使用してこれらの変数を設定します。つまり、 システム全体に設定され、IPL 間でも設定されたままになるということです。

これらのコマンドは一回しか実行できないため、プログラムに組み込むより、対話式に入力したくなるでしょう。それでも大丈夫です。しかし私の場合は、例えば、新しいサーバーに移行する場合など、後で再度設定したい場合に、コマンドをプログラムに入れておく方を選びます。また、Java ソフトウェアを別のサーバーで構成したり、このサーバーに変更を行う場合に定形文面としてこのプログラムを使用したりすることもできます。

サーバー上のすべてのユーザーはこのように設定されます。あるいは、デフォルトで設定されるでしょう。設定はオーバーライドできます。

目的を問わず、環境変数をジョブ内で最初に使用する場合、LEVEL(*SYS) 変数が LEVEL(*JOB) 変数にコピーされ、アプリケーションが使用するのは LEVEL(*JOB) 変数であることがわかると思います。開発者またはパワー・ユーザーは変数をオーバーライドし、異なるバージョンの JAR ファイルをテストするか、新しい Java コードを試すと思います。これを行うには、開発者は単にジョブ・レベルの変数を変更してから、次のように JVM を読み込みます。

ADDENVVAR ENVVAR(CLASSPATH)
     VALUE('/Java400Custom/jdbc/jtds-2.0.0.jar+
        :/Java400Custom/JT400/jt400-full-6.0.jar') +
     LEVEL(*JOB)

この変更を行った後、開発者はこの例で、システムの他のユーザーがバージョン 1.2.5 を使用していても、バージョン 2.0.0 の jTDS ドライバーをテストできます。変数は LEVEL(*JOB) で変更されるため、他のユーザーには影響しません。

すでに JDBC を実行しすべてうまくいっている状態で、POI を使用しようとしていると想像してみてください。POI JAR ファイルを組み込むには、全員の CLASSPATH 変数を変更する必要があります。CLASSPATH がプログラム内でハードコーディングされている場合、実行するのは簡単ではありません。前述の LEVEL(*SYS) 技法を使用する場合、次のやり方でできます。

ADDENVVAR ENVVAR(CLASSPATH)
     VALUE('/Java400Custom/JDBCv3114/mysql-connector-+
          java-3.1.14-bin.jar+
        :/Java400Custom/jdbc/jtds-1.2.5.jar+
        :/Java400Custom/JT400/jt400-full-6.0.jar+
        :/java/poi3.6/poi-3.6-20091214.jar') +
     LEVEL(*SYS)

それだけです。これですべてのユーザーの CLASSPATH 変数に POI JAR ファイルが JDBC JAR ファイルとともに存在することになります。あるいは、サインオフして、再度サインオンした後に存在するようになります。つまり、すべてのユーザーが POI ソフトウェアを使用でき、JDBC コードの変更は必要なくなります。

putenv() を使用してコードの JAR ファイルを設定した場合、あまり幸運だとは言えません。この場合、CLASSPATH を設定しているあらゆるプログラムを見つけ、POI JAR ファイルが組み込まれるよう変更する必要があります。 たとえユーザーが POI を使用していなくても、CLASSPATH で必要です。そうでない場合、ファイルは同じジョブでうまく動作できなくなります。

同様に、コードが別のコンピューターにコピーされると、JAR ファイルは別の場所に格納される場合があります。または、そのコンピューター上のユーザーは、JDBC しかアプリケーションで使用されていなくても、POI を使用しなければならない場合があります。それらのユーザーがそのジョブの一部として Java 変数を構成する場合、これは問題ではありません。ただし、変数がプログラム内で設定されている場合は、プログラムを新しいコンピューターに適応させる必要があります。

私の言わんとしていることがわかると思います。CLASSPATH と他の RPG/Java 統合変数 (JAVA_HOME、QIBM_RPG_JAVA_PROPERTIES など) は、ジョブの構成の一部として設定される環境変数のはずです。それらをプログラムに設定するのはグッド・アイデアとは言えません。

あわせて読みたい記事

PAGE TOP