ふたつの川うるおう日記
2006-08-22 (Tue)
_ [Java][Seasar] HOT deploy時のサブアプリケーションのServiceクラスのコンポーネント名setterのメソッド名 (解決)
昨日のコンポーネント名を直すと、(これはS2StrutsQualifiedの問題でした)HOT deploy時にサブアプリケーションのServiceクラスのコンポーネント名が、user_LoginServiceなどとなってしまうので、ActionImplでServiceのsetterを下記のようにしないと動作しない罠がありました。
public void setUser_LoginService(LoginService user_LoginService)
なんとなく不恰好なので下記ので動いて欲しい。
public void setUserLoginService(LoginService userLoginService) public void setLoginService(LoginService loginService)
前者はServiceCreatorで登録するコンポーネント名を _ なしにするか、コンポーネント名を登録しないようにすればどちらでも動きそう。
[13:14追記] S2Strutsのorg.seasar.struts.pojo.util.BindingUtilに次のパッチを当てればとりあえず下記のsetterで動きました。
public void setLoginService(LoginService loginService)
- propertyTypeで探してから、propertyNameでクラスを探すパッチ
Index: E:/Java/Eclipse/Workspace/Seasar/s2struts/src/main/java/org/seasar/struts/pojo/util/BindingUtil.java
===================================================================
--- E:/Java/Eclipse/Workspace/Seasar/s2struts/src/main/java/org/seasar/struts/pojo/util/BindingUtil.java (revision 556)
+++ E:/Java/Eclipse/Workspace/Seasar/s2struts/src/main/java/org/seasar/struts/pojo/util/BindingUtil.java (working copy)
@@ -63,13 +63,15 @@
return (Class) primitiveMap.get(primitiveClass);
}
- private static Object getValue(S2Container container, String name) {
+ private static Object getValue(S2Container container, Class clazz, String name) {
Object var = RequestUtil.getValue(S2StrutsContextUtil.getRequest(container), name);
if (var != null) {
return var;
}
- if (container.hasComponentDef(name)) {
+ if (container.hasComponentDef(clazz)) {
+ return container.getComponent(clazz);
+ } else if (container.hasComponentDef(name)) {
return container.getComponent(name);
}
return null;
@@ -89,8 +91,9 @@
return;
}
+ Class propertyType = propertyDesc.getPropertyType();
String propertyName = propertyDesc.getPropertyName();
- Object value = BindingUtil.getValue(container, propertyName);
+ Object value = BindingUtil.getValue(container, propertyType, propertyName);
if (BindingUtil.isActionFormProperty(propertyDesc, mapping)) {
value = ActionFormUtil.getActualForm(S2StrutsContextUtil.getRequest(container), mapping);
} else {
@@ -100,7 +103,6 @@
return;
}
- Class propertyType = propertyDesc.getPropertyType();
if (propertyType.isPrimitive()) {
propertyType = getPrimitiveWrappedClass(propertyType);
}
[15:12追記] トラッキングにHOT deploy時のサブアプリケーションのServiceクラスのsetterのメソッド名で登録しておきました。リリースされてないバージョンなので投げるか迷ってましたが一応投げておきました。見当違いでしたらゴメンナサイ(;´ー`)。
[15:54追記] 右往左往した結果、S2Containerのリビジョン1208の修正で、S2Container#hasComponentDef()で例外を出なくするようにしていただいたところ、この問題は発生しなくなりました。S2StrutsのBindingUtilの修正も不要です。ひがさん修正ありがとうございました。
_ [Java][Seasar] S2StrutsでHOT deploy時にThrowsInterceptorが呼ばれない (解決)
[追記] 解決しました。
COOL deploy時に動作するThrowsInterceptorがHOT deploy時で動作しなかったり。
END org.example.web.user.impl.LoginActionImpl#login() Throwable:org.example.exception.UserNotFoundRuntimeException: ユーザ[ aaa ]は存在しないか、パスワードが正しくありません。 2006-08-22 03:23:29,296 [http-8080-Processor23] WARN org.apache.struts.action.RequestProcessor - 処理できない例外がスローされました: class org.example.exception.UserNotFoundRuntimeException 2006-08-22 03:23:29,296 [http-8080-Processor23] ERROR org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/members].[action] - サーブレット action のServlet.service()が例外を投げました org.example.exception.UserNotFoundRuntimeException: ユーザ[ aaa ]は存在しないか、パスワードが正しくありません。 at org.example.web.user.impl.LoginServiceImpl.login(LoginServiceImpl.java:60) ...
ThrowsInterceptorは、rokugenさんのS2Strutsで元の画面に帰りましょう処理のThrowsInterceptor。
デバックしてみるとCOOL deploy時には呼ばれているThrowsInterceptorが呼ばれてないみたい。何だろな〜。
[21:08追記] methodMapに登録されたhandleThrowableのMethodインスタンスと実行時に取得されたMethodインスタンスが異なるのが原因のようです。
_ [Java][Seasar] いろいろと
ここのところ自分好みのURIでS2StrutsとHOT deployを動かそうと右往左往していろいろコード見てるわけですがどれも勉強になります。今更ながらやっとほんのちょっぴりSeasar2コンテナの仕組みが判ってきた気がしてたり。。。というか僕にプログラム書くのが向いてない疑惑が以前より・・・。そんなわけで問題があっても小手先の回避先で右往左往し続けてる(;´ー`)ダメダメ。
19歳ぐらいからサーバ漬けで小手先に慣れすぎたかなー。
_ [Java][Seasar] COOL deploy時のサブアプリケーションのコンポーネント名はちっともまずくない
ちっともまずくありませんでしたー。お騒がせしました。
_ [Java][Ashikunep] Ikushipeわくわく
Seasar2対応のコードが入ったようです。S2Strutsに慣れ親しんでるところで何ですが、リリースされたら移行でしょうか(;´ー`)。コミットログにいろいろ書かれてるのでわくわくしながら見てたりしますw。
_ [Java][Seasar] HOT deploy + JoSQLが上手くいかないが解決しました
原因はJoSQLがクラスインスタンスを操作するのに使っているgentlyWEB-utils-1.1.jarのクラスローダがHOT deploy時に対応できないためでした。で、Queryクラスを確認したらちゃんとsetClassLoader(ClassLoader classLoader)がありました。
Query query = new Query(); query.setClassLoader(Thread.currentThread().getContextClassLoader());
これで後は普段通り使えば動きました。解決!
このクラスはユーティリティクラスなんですが、HOT deploy時は良いとして、COOL deploy時は毎回Thread.currentThread().getContextClassLoader()するんじゃなくて、HOT/COOL deployでDIするのを変えた方が良いのかな。その辺のコスト感覚がさっぱり判らなかったり。
ところで、gentlyWEB-utils-1.1.jarは3rd-party-jarsと書いてあるだけあって、ソースがどこにも見つからない・・・。
とりあえず、ClassLoaderを使って何かするライブラリを使う際は同様の注意が必要そうです。



public void setLoginService(LoginService loginService)<br>で動かないでしょうか。<br>org.seasar.framewowrk.container.assembler.AbstractBindingTypeDef#bindAuto()の152から159行目のif文がその辺のロジックです。
ありがとうございます。もう一度よく確認してみたところ、COOL deploy時は<br>public void setLoginService(LoginService loginService)<br>で正常に動作しました。しかし、HOT deploy時は、クラスの生成をMultiPackageOndemandCreator#getTargetClass()でされるので、ここにコンポーネント名としてloginServiceが渡されるとクラスが見つからず失敗します。<br>public void setUser_LoginService(LoginService user_LoginService)<br>ですと、コンポーネント名がuser_LoginServiceになるため上手く見つかって動くようです。
よく見たらS2ContainerよりS2Strutsに手を入れれば良さそうでしたので、S2Strutsのorg.seasar.struts.pojo.util.BindingUtilに追記したパッチを当てればとりあえず動きました。ただ、HOT deploy時にcontainer.hasComponentDef(name)でコンポーネントが見つからない例外が出てしまうのがあまり良くないかもしれません。以下は、パッチ前の動かなかった時の例外です(一番最初にこれを書いておくべきでした・・・)。 <br>org.seasar.framework.container.ComponentNotFoundRuntimeException: [ESSR0046]コンポーネント(loginService)が見つかりません<br> at org.seasar.framework.container.hotdeploy.creator.MultiPackageOndemandCreator.getTargetClass(MultiPackageOndemandCreator.java:85)<br> at org.seasar.framework.container.hotdeploy.creator.AbstractOndemandCreator.getComponentDef(AbstractOndemandCreator.java:152)<br> at org.seasar.framework.container.hotdeploy.impl.OndemandProjectImpl.getComponentDef(OndemandProjectImpl.java:67)<br> at org.seasar.framework.container.hotdeploy.OndemandBehavior.getComponentDef(OndemandBehavior.java:134)<br> at org.seasar.framework.container.hotdeploy.OndemandBehavior.getComponentDef(OndemandBehavior.java:99)<br> at org.seasar.framework.container.impl.S2ContainerBehavior$DefaultProvider.acquireFromHasComponentDef(S2ContainerBehavior.java:101)<br> at org.seasar.framework.container.impl.S2ContainerBehavior.acquireFromHasComponentDef(S2ContainerBehavior.java:53)<br> at org.seasar.framework.container.impl.S2ContainerImpl.hasComponentDef(S2ContainerImpl.java:409)<br> at org.seasar.struts.pojo.util.BindingUtil.getValue(BindingUtil.java:72)<br> at org.seasar.struts.pojo.util.BindingUtil.importProperty(BindingUtil.java:93)<br> at org.seasar.struts.pojo.util.BindingUtil.importProperties(BindingUtil.java:82)<br> at org.seasar.struts.pojo.MethodBinding.invoke(MethodBinding.java:65)<br> at org.seasar.struts.pojo.MethodBindingAction.execute(MethodBindingAction.java:41)<br> at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)<br> ...
最新版では、S2Container#hasComponentDef()で例外が出ないように修正しました(つもりですけどS2Strutsの環境でうまくいくかは自信がなかったり(笑))。
修正ありがとうございます。確認したところ例外出なくなりました。トラッキングに登録しちゃったんですが、BindingUtilの修正も必要無くなりました(汗。取り下げておきます。
ThrowsInterceptorの件ですが、お使いのThrowsInterceptorのクラス名と例外のクラス名とrootPackageNameを教えていただけるでしょうか。<br>よろしくお願いします。
クラス名: org.seasar.server.members.interceptor.ActionThrowsInterceptor<br>rootPackageName: org.seasar.server.members<br>です。org.seasar.framework.container.hotdeploy.creator.InterceptorOndemandCreatorもhotdeploy用のdiconファイルに定義してあります。例外は出ておらずそのまま無視されている感じです。<br><br>もう少し調べてみたところ、org.seasar.framework.aop.interceptors.ThrowsInterceptorのコンストラクタで、methodMapにActionThrowsInterceptor#handleThrowable(AppRuntimeException ex, MethodInvocation invocation) throws ThrowableのMethodが登録されるものの、HOT deploy時はThrowsInterceptor#getMethod()でのclazzと登録時のclazzが異なるためか見つからずnullが返却されてしまい、ActionThrowsInterceptor#handleThrowableが実行されないようです。<br><br>試しにmethodMapへの登録キーをmethodMap.put(m.getParameterTypes()[0].getName(), m);とクラス名にして、ThrowsInterceptor#getMethod()でmethodMapからの検索キーをclazz.getName()にしたところ、Methodは取得できたものの今度はThrowsInterceptor#invoke()のmethod.invoke(this, new Object[] { t, invocation });でjava.lang.IllegalArgumentException: argument type mismatchが発生し、実行できませんでした。<br>その時の例外は下記の通りです。<br>java.lang.IllegalArgumentException: argument type mismatch<br> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br> at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)<br> at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)<br> at java.lang.reflect.Method.invoke(Unknown Source)<br> at org.seasar.server.members.interceptor.ActionThrowsInterceptor.invoke(ActionThrowsInterceptor.java:108)<br> at org.seasar.server.members.web.user.impl.LoginActionImpl$$EnhancedByS2AOP$$18a8ae7$$MethodInvocation$$login0.proceed(MethodInvocationClassGenerator.java)<br>再現しないようでしたらサンプルアプリを用意したいと思います。よろしくお願いします。
お、コミットログ読みはっけん。
はい、コミットログでどんな変更なのか把握できるようになったので変更点を追いやすくなりました。RSS連携が良い感じです(゜ー゜)。
原因が(たぶん)わかりました。<br>ThrowsInterceptorの登録時には、オンデマンド以外で登録されていますね。<br>でも、実行時にはオンデマンドモードになっているので、クラスローダが違って見つかってないんだと思います。<br>オンデマンド以外でロードされたクラスは、常にオンデマンドではロードしないように修正したので、最新版で試していただけるでしょうか。<br>それでも、もしだめならThrowsInterceptorの定義をdiconファイルから取り除いて、AspectCustomizerで名前(actionThrowsInterceptor)だけ指定してください。それで大丈夫だと思います。こちらのサンプルでは大丈夫でした。
修正ありがとうございます。試してみましたが、修正版ですとActionなどのコンポーネントが見つからなくなってしまいました。S2Strutsのtrunk/s2struts-exampleで修正版に入れ換えてEmployee Managementを動かすと再現出来ます。<br>例外: [ESSR0046]コンポーネント(employeeSearchInitAction)が見つかりません<br>修正前の状態で、アドバイスいただいたActionThrowsInterceptorの定義をdiconファイルから取り除いて、AspectCustomizerで名前(actionThrowsInterceptor)だけ指定したところ、HOT/COOL deployどちらでも期待通りに動作しました!明示的に定義しなくともCreatorが登録してくれるんですね。少ない情報から設定状況を読み取っていただいてありがとうございますm(_ _)m。<br>修正版の方はfindLoadedClassInternal(className)の前にfindLoadedClass(className)を入れてnullじゃない方を返せば上手く行くかなと思いましたが、全然上手くいきませんでした…。
HotDeployClassLoader#loadClass()の実装を元に戻しました。
確認しました。明示的に定義しないでCreatorに任せて使いたいと思います。いろいろとありがとうございました。