Oracle JRE (1.8u40) を使用して Tomcat (8.0.21) 内で OpenSplice DDS (6.1.0p5、PrismTech ディストリビューション) を使用する Web アプリケーションを実行するのに問題があります。
バックグラウンド
私たちのコードは OpenSplice ライブラリ dcpscj.jar、dcpssaj.jar、dlrlsaj.jar を使用しています。ライセンスとメンテナンスの理由から、これらは通常の WEB-INF/lib の WAR ファイルに組み込まれるのではなく、外部ディレクトリ /opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar にホストされます。
- Tomcat ClassPath に外部 jar を含めるに従って、オプションの bin/setenv.sh ファイル内で CLASSPATH 変数を設定することにより、Web アプリケーションでこれらを正常に使用できるようになりました。
- また、Tomcat にネイティブ ライブラリを追加する方法に従って、JNI パーツが機能するように java.library.path を設定しました。.
setenv.sh
export CLASSPATH=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpscj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dcpssaj.jar:/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/jar/dlrlsaj.jar
export CATALINA_OPTS=-Djava.library.path=/opt/OpenSpliceDDS/V6.1.0p6/HDE/x86.linux2.6/lib
export LD_PRELOAD=/usr/java/jre/lib/i386/libjsig.so
tomcat classloading documentationに従って、conf/catalina.properties の common.loader プロパティを介してライブラリを利用できるようにすることにも成功しました。
問題
CLASSPATH と common.loader の両方のアプローチで、WAR がデプロイされると、Tomcat は一貫して SIG_SEGV でクラッシュします。
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x0142043a, pid=17613, tid=2004876144
#
# JRE version: Java(TM) SE Runtime Environment (8.0_40-b25) (build 1.8.0_40-b25)
# Java VM: Java HotSpot(TM) Server VM (25.40-b25 mixed mode linux-x86 )
# Problematic frame:
# V [libjvm.so+0x53543a] get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
#
# Core dump written. Default location: //core or core.17613
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
スタックの上部
V [libjvm.so+0x53543a] get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*)+0x7a
V [libjvm.so+0x5467ad] jni_GetMethodID+0xbd
C [libdcpssaj.so+0x1569e] saj_cacheStructBuild+0x10e
C [libdcpssaj.so+0x148ae] saj_metaObject+0x9e
C [libdcpssaj.so+0x14b76] saj_copyCacheBuild+0x56
C [libdcpssaj.so+0x14c34] saj_copyCacheNew+0x94
C [libdcpssaj.so+0x29dcf] Java_org_opensplice_dds_dcps_FooTypeSupportImpl_jniRegisterType+0x21f
j org.opensplice.dds.dcps.FooTypeSupportImpl.jniRegisterType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I+0
j org.opensplice.dds.dcps.FooTypeSupportImpl.registerType(Ljava/lang/Object;LDDS/DomainParticipant;Ljava/lang/String;)I+17
j org.example.dds.example_topic_typeTypeSupport.register_type(LDDS/DomainParticipant;Ljava/lang/String;)I+3
分析
この問題は、JAR が WEB-INF/lib の外部にある場合にのみ発生します。JAR が WEB-INF/lib に「埋め込まれている」場合、Tomcat はクラッシュしません。
org.example.dds.example_topic_typeTypeSupport (anonymised) は、OpenSplice によって生成されたコードであり、WEB-INF/lib に個別の JAR としてパッケージ化されています。
example_topic_typeTypeSupport
FooTypeSupportImpl.registerType()を呼び出し、クラス名を IDL 形式 "org::example::dds:example_topic_type" の文字列として JNI 部分saj_fooTypeSupport.cに渡します。
理解するのは難しいですが、最終的に env->FindClass は Java バリアント、つまり org.example.dds.example_topic_type で呼び出されると思います。これは、segfault を引き起こす jni_GetMethodID に渡される NULL を返しているようです。
javaClass = (*(ctx->javaEnv))->FindClass (ctx->javaEnv, classDescriptor);
FindClass のドキュメントによると、使用されるクラスローダーはネイティブ メソッドをホストするものです。
FindClass は、現在のネイティブ メソッドに関連付けられているクラス ローダーを見つけます。つまり、ネイティブ メソッドを宣言したクラスのクラス ローダーです。ネイティブ メソッドがシステム クラスに属している場合、クラス ローダーは関与しません。
これは、クラスローダが dcpssaj.jar にある FooTypeSupportImpl をロードするために使用されるものであることを意味します。このクラスローダーは、WEB-INF/lib/topics.jar にあるトピック定義を認識できません。
Tomcatクラスローディングのドキュメントでは、各モジュールのプライベート クラスローダーについて説明しています。
Bootstrap | System <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar | Common <=== if dcpssaj.jar is loaded here then it can't see example_topic_type in topics.jar / Webapp1 <=== WEB-INF/lib/topics.jar containing example_topic_type
質問
- Tomcat に追加の JAR ファイルを含め、 WEB-INF/lib で他の JAR をロードするために使用される同じクラスローダーによってそれらをロードする方法はありますか? クリーンな構成ベースのソリューションを探しています。シンボリックリンクを含む回避策や、展開時にスクリプトを介して DDS JAR を WAR ファイルに移植することを既に検討しています。
- この問題を回避するために OpenSplice DDS を構成する方法はありますか?