JBoss で JCA のプロバイダの jar が見えない!!
JBoss 上で Java Cryptgraphy Architecture (JCA) を利用したアプリケーションを書いていたのだけれど、いざデプロイして稼動確認してみるかといった段で例外を吐いて死ぬ惨状となった。 状況としては、こちらの stack overflow の記事の通りで、JBoss がプロバイダの実装が入っている jar ファイルの検証を行う際、その jar ファイルがうまく読めていないものと思われる。
解決策
これは想定を含むが、今回の問題点は、JCA がプロバイダ実装を取得する際の仕組みが、JBoss の VFS に対応していないからではないか?と思っている。
先に解決策を説明しておくと、大きく分けて 2 通り。今回は前者の方法を選択した。
- 上記の stack overflow の中で回答されているとおり、jboss-deployment-structure.xml に jar ファイルの定義を記述する
- JBoss Developer コミュニティで議論されているとおり、JBoss の静的モジュールとして、プロバイダの jar を依存関係に定義する
ちなみに、Githubを見る限り、JasperReports では後者の方法を取っているみたいなので、それなりに信頼に足る対処方法なのだと判断している。 ただ、これで解決こそしたものの、やはりもうちょっと理解を深めないと今後トラブルがあった際に対応できないので、このあたりを調べた方法を整理する。
解決策の深掘り
JBoss のクラスローディング
JBoss では、Java 界で一般的な階層型のクラスローディングではなく、「モジュール」という概念に対して行われるようになっている。
一般的な階層型クラスローダの概念図は以下。
階層型クラスローダは多くの Java 実行環境で用いられているが、jar の依存関係が開発者の意図通りにならない/開発者が管理し切れない状況が生じやすく、一般に言う Jar 地獄に陥りがちだとされる。
これに対して JSR 277 等で別のアプローチとして「モジュール」を定義し、そのモジュールに対する依存関係を記述すれば良いという方向となっており、JBoss はこの考え方を先行して実装したことになる。(なお、この実装は JSR 277 とは異なる) モジュールというのは、クラスローディング・依存関係の管理に用いるクラスの集合として定義されている。
A Module is a logical grouping of classes used for class loading and dependency management.
モジュールの種類
JBoss でいうモジュールには以下の 2 種類がある。
- 静的モジュール (Static Modules)
- アプリケーションサーバ上の設定として定義されるモジュール。フォルダの中に、モジュール定義(module.xml) と、必要な jar ファイルを保持することでモジュールとして認識されるようになる。
- 「解決策」で示した 2 つ目の方法は、JCA のプロバイダの jar を、新規静的モジュールとして定義する方法になっている。
- 動的モジュール (Dynamic Modules)
- アプリケーションサーバにデプロイする JAR や WAR が動的モジュールとして認識される。
- 「解決策」で示した 1 つ目の方法に対応。動的モジュールに対するクラスローダ設定は jboss-deployment-structure.xml に記述する
静的モジュール/動的モジュールの選択
静的モジュールとして設定するのは、結局 JBoss に対して設定を行うことを意味する。 個人的嗜好なのかもしれないが、(JavaEE 等の依存関係ではなく)アプリケーションレイヤにおける依存関係をミドルウェアである JBoss に対して行うのはあまり筋が良くないと思うし、アプリケーションレイヤの話はアプリケーションレイヤで解決すべきだと思う。 なので、今回の解決策としては、動的モジュールを用いる方を選択した。
jboss-deployment-structure.xml の内容
jboss-deployment-structure.xml の内容は以下のような形になる。
<jboss-deployment-structure> <deployment> <resources> <resource-root path="WEB-INF/lib/bcprov-jdk16-1.46.jar" use-physical-code-source="true"/> </resources> </deployment> </jboss-deployment-structure>
重要なのは、use-physical-code-source 属性で、デフォルト値は false。これを true にしてやる必要がある。 ここからは想定を含むが、false の場合は、JBoss から VFS root URL を介してアクセスされるが、これが冒頭に示した Can't load jar - “zip file is empty” の例外を発生させる一因になっている。 おそらく、JCA/JCE でプロバイダ実装を取得する際の仕組みが、VFS に対応していないのではないだろうか。 true を指定すると、VFS mount Point の物理パスを介してアクセスされるようになるので、問題が発生しないと理解している。