[Seasar-user:20947] [S2Struts+S2Mai] メール送信完了画面からの画面遷移で例外発生

宮崎俊郎 [E-MAIL ADDRESS DELETED]
2011年 8月 4日 (木) 18:03:07 JST


お世話になります、宮崎と申します。

◆現在、以下のような現象が発生しております。
 解決方法等ご教授頂きたく。

 以下、長文になりますが、ご容赦下さい。

【動作環境】
・JDK 1.6.0_23
・apache-tomcat 6.0.32
・s2-framework-2.4.44.jar
・s2-extension-2.4.44.jar
・s2-tiger-2.4.44.jar
・sa-struts-1.0.4-sp8.jar
・s2mai-0.9.6.jar

【現象】
tomcatへデプロイしたWebアプリケーション(S2Strutsベース)をHOT deployにて動作させています。その際、
・「メール送信画面」にて『確定』ボタンを押し、サーバへリクエストします。
 呼び出されたActionの実行メソッドの中で、S2Maiによるメール送信を行います。
 メール送信処理を含め、実行メソッドが正常終了し、「メール送信完了画面」へ遷移します。
・「メール送信完了画面」から、別のAction実行メソッドを呼び出すようなリクエストを発生させます。
 すると、以下のような例外が発生します。
--
致命的: サーブレット default のServlet.service()が例外を投げました
java.lang.NullPointerException
       at org.seasar.struts.util.S2ExecuteConfigUtil.findExecuteConfig(S2ExecuteConfigUtil.java:70)
       at org.seasar.struts.filter.RoutingFilter.doFilter(RoutingFilter.java:127)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.seasar.framework.container.filter.S2ContainerFilter.doFilter(S2ContainerFilter.java:79)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at xx.xx.xx.xx.xx.filter.DataSourceSwitchFilter.doFilter(DataSourceSwitchFilter.java:74)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.seasar.framework.container.hotdeploy.HotdeployFilter.doHotdeployFilter(HotdeployFilter.java:99)
       at org.seasar.framework.container.hotdeploy.HotdeployFilter.doFilter(HotdeployFilter.java:67)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.seasar.extension.filter.EncodingFilter.doFilter(EncodingFilter.java:69)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
       at java.lang.Thread.run(Thread.java:662)
--

【調査結果】
○COOL deployでは例外は発生せず、HOT deployで発生します。
○メール送信コードをコメントアウトすると、例外は発生しません。
○メール送信コードがある場合とない場合で処理を比べると、以下のような違いがありました。
 ①メール送信コードがある場合、
  S2MaiInterceptor#sendMail()から、
  S2MaiInterceptor.java 69行目→
  MaiMetaDataFactoryImpl.java 52行目→
  MaiMetaDataImpl.java 47行目で
  S2ContainerFactory.create(path);
  が呼び出される。
 ②S2ContainerFactory.create()の中ではs2container.diconを読み込み、
  HotdeployBehaviorのインスタンス(B)が生成され、
  S2ContainerBehavior#providerに設定される。
  その際、もともと設定されていたHotdeployBehaviorのインスタンス(A)
  (=S2ServletContainerにより生成されたもの)
  が置き換わってしまう。
 ③HotdeployBehaviorは、リクエスト処理中に生成したComponent定義をキャッシュし(HotdeployBehavior#componentDefCache)、
  リクエスト処理の最後でこのキャッシュをクリアする(HotdeployBehavior#stop())。
  リクエスト処理の途中でHotdeployBehaviorのインスタンスが(A)から(B)に入れ替わってしまうと、
  入れ替わった後に生成されたComponent定義は新しいインスタンス(B)が保持するが、
  リクエスト処理の最後で(B)のキャッシュはクリアされず、次のリクエスト処理へ持ち越されてしまう。
  (HotdeployFilterの中でインスタンス(A)のstart()とstop()は呼び出されるが、(B)の後処理は呼び出されない。)
 ④次のリクエスト処理で、キャッシュに残っていた情報のつじつまが合わずに、例外が発生。

【質問】
「メール送信完了画面」からの画面遷移で例外が発生しないようにするための方法をご教授いただきたいのですが、
それと合わせ
(1)Hotdeploy中(HotdeployBehavior#start()の後)に、S2ContainerFactory.create()を呼び出しても良いものなのでしょうか?
(2)HotdeployBehaviorのライフサイクルはデフォルトのsingletonですが、2つ目のインスタンス(B)が生成されてしまうのは、
 S2Containerが別だからなのでしょうか?
(3)作り込みが進んでおり、Component定義読み込みのつじつまを合わせることは難しいため、
 持ち越されたキャッシュをクリアする方向で対応したいと考えています。
 暫定対応として、以下のようなコードをメール送信コードの後に入れてみましたが、ご意見を頂けたらと思います。
 (DisposableUtil#dispose()が入れ子で呼ばれてしまいますが、disposables.removeLast()で処理が回っているのでうまくいくように見えます。)
--
       if (HotdeployUtil.isHotdeploy()) {
           DisposableUtil.add(new Disposable() {
               public void dispose() {
                   //HotdeployUtil.stop();
                   ((HotdeployBehavior)
S2ContainerBehavior.getProvider()).finish();
               }
           });
       }
--

以上、長くなりましたが何卒よろしくお願い致します。


Seasar-user メーリングリストの案内