axis2でのログ設定

axis2でコンテナとサービスのログ設定を完全に切り離そうとしてハマった。
log4jに起因するものなので他のログ実装ではあてはまらないかもしれない。


最初は単にEnableChildFirstClassLoadingパラメータを有効にして必要なjarをアーカイブに入れればできると思ったんだが、これだけではダメだった。


ポイントは2つ。


log4jが設定ファイルの探索にスレッドコンテキストクラスローダを優先して使用している。


axis2はサービスごとにクラスローダを作ってはいるものの、スレッドコンテキストクラスローダは置き換えていないのでコンテナのWebappClassLoaderが使われてしまう。
これはサービスをロードする時にスレッドコンテキストクラスローダをサービスのクラスローダに置き換えるようにして対処。
変更箇所は2ヶ所。
スレッドコンテキストクラスローダを変更しているコードが追加した部分。
まずorg.apache.axis2.deployment.ServiceGriuoBuilder#populateServiceGroup()内の下記の部分。

ClassLoader oldTCCL = Threada.currentThread().getContextClassLoader();
try {
  Thread.currentThread().setContextClassLoader(axisServiceGroup.getServiceGroupClassLoader())
  AxisService as = serviceBuilder.populateService(service);
  serviceList.add(as);
} finally {
  Thread.currentThread().setContextClassLoader(oldTCCL);
}

次にorg.apache.axis2.engine.DependencyManager#initService()内の下記の部分

ClassLoader oldTCCL = Threada.currentThread().getContextClassLoader();
try {
  Thread.currentThread().setContextClassLoader(classLoader)
  Class implClass = Loader.loadClass(classLoader, ((String) implInfoParam.getValue()).trim());
  Object serviceImpl = implClass.newInstance();
  serviceContext.setProperty(ServiceContext.SERVICE_OBJECT, serviceImpl);
  initServiceObject(serviceImpl, serviceContext);
} catch (Exception e) {
  AxisFault.makeFault(e);
} finally {
  Thread.currentThread().setContextClassLoader(oldTCCL);
}

もう1点、サービスのメソッドが実行される時にもスレッドコンテキストクラスローダを変更するべきだと思う。
そうしないともしこれを使用しているクラスを実行時にロードすると誤動作しかねない。
これはwsdl2javaコマンドで自動生成されるXXXXMessageReceiverInOutクラスのinvokeBusinessLogic()の最初と最後でやるようにした。
このクラスのテンプレートはaxis2-codegen-xxxx.jar内のorg/apache/axis2/wsdl/template/java/MessageReceiverTemplate.xslなので、これを修正して自動生成する。


・DeploymentClassLoaderがgetResourceメソッドをオーバーライドしていない。


そのためリソースに関してはEnableChildFirstClassLoadingパラメータの設定に関わらず親優先の探索になってしまう。
これはパラメータの値を見て子優先で探索するようにオーバーライドして対処。
コードは簡単なので割愛。


また今回は先日の記事にある通り、サービス関連のファイルをアーカイブせずservicesディレクトリの下に直接置くことにしたのだが、このやり方だとwindows環境ではDeploymentClassLoaderではなくJarFileClassLoaderが使われてしまう。
JarFileClassLoaderはEnableChildFirstClassLoadingパラメータの設定に関わらず常に親優先なので使えない。
DeploymentClassLoaderと同じようにオーバーライドしようと思ったが、何やらややこしい処理をしてるようなのでやめておく。
DeploymentClassLoaderを使わない理由は良くわからないが、org.apache.axis2.classloader.JarFileClassLoader=falseというシステム変数を設定するとwindows環境でもDeploymentClassLoaderが使われるようになる。


これでとりあえずコンテナとサービスで別々のlog4j.propertiesファイルを参照して動作している。
面倒なこと・・・