リリース作業は絶対自動化
@ExportでセッションにいれたオブジェクトをInterceptorで使うとき
まず、@Exportでセッションにオブジェクトを設定する。
public class HogeServiceImpl implements HogeService { public MogeDto mogeDto; public void hoge() { mogeDto = .... } @Export(storage=StorageType.SESSION) public MogeDto getMogeDto() { return mogeDto; } }
で、以下のようなInterceptorの中で、上記で設定したmogeDtoを取り出して、instanceofでチェックすると、思ったとおりの結果にならない。
public class SessionCheckInterceptor extends AbstractMethodInterceptor { private S2Container container; public void setContainer(S2Container container) { this.container = container; } public Object invoke(MethodInvocation invocation) throws Throwable { Map sessionMap = container.getExternalContext().getSessionMap(); Object attrValue = sessionMap.get("mogeDto"); if (attrValue != null) { System.out.println(attrValue instanceof MogeDto); } } }
原因は、以下で説明されているHotDeployClassLoaderがらみ。
http://d.hatena.ne.jp/koichik/20061118#1163869222
HotDeployでなくCoolDeployだと、思ったとおりに動くのだけど、やっぱりHotDeployでさくさく開発したい。
で調べてたら、以下で、HotdeployUtil.rebuildValue() ってのがある。と。
https://www.seasar.org/issues/browse/FLEX-16
で、こんな感じで直したら、うまくいった。
これがスマートな解決方法かわからないけど。。
public class SessionCheckInterceptor extends AbstractMethodInterceptor { private S2Container container; public void setContainer(S2Container container) { this.container = container; } public Object invoke(MethodInvocation invocation) throws Throwable { Map sessionMap = container.getExternalContext().getSessionMap(); Object attrValue = sessionMap.get("mogeDto"); if (attrValue != null) { attrValue = HotDeployUtil.rebuildValue(attrValue); System.out.println(attrValue instanceof MogeDto); } } }
このHotDeployUtil.rebuildValue() だけど、ソースを見ると HotDeployが無効になっているときは、何もせずに、引数のオブジェクトをそのまま返すようになっている。
パフォーマンスの問題にもならなそうだし、このまま製品コードに含めてしまっても、特に問題なさげ。
Proxyクラス
S2Flex2のソースを読んで知った。
http://livedocs.adobe.com/flex/2_jp/langref/flash/utils/Proxy.html
プロパティへのアクセスや、メソッドの呼び出しのプロキシを作れる。
こんな感じでProxyを継承しておくと、
import flash.utils.flash_proxy; import flash.utils.Proxy; use namespace flash_proxy; public dynamic class HogeProxy extends Proxy { flash_proxy override function callProperty(methodName:*, ...args):*{ trace("callProperty methodName:" + methodName + " args:" + args); return methodName; } flash_proxy override function setProperty(name:*,value:*):void{ trace("setProperty name:" + name + " value:" + value); } flash_proxy override function getProperty(name:*):*{ trace("getProperty name:" + name); return name; } }
定義していないプロパティやメソッドが、存在するかのようにアクセスすることができる。
var hogeProxy:HogeProxy = new HogeProxy(); hogeProxy.moge = "もげ"; var f:String = hogeProxy.fuga; hogeProxy.foobar("ふーばー");
S2Flex2を試してみた。(2)
次はサービスを作ってみることにする。
どうやって作るかの説明がサイトにないので、exampleのAddサンプルをみて作ってみる。
とりあえず、こんな感じか。。
まず、Main.mxmlに S2Flex2Serviceとリモート呼び出しの結果を受け取るスクリプトを追加。
ボタンを押したら、MainService の getHoge()メソッドが呼ばれるようにする。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:s2="http://www.seasar.org/s2flex2/mxml" layout="absolute"> <mx:Script> <![CDATA[ import mx.rpc.events.ResultEvent; import mx.rpc.events.FaultEvent; import mx.controls.Alert; import mx.utils.ObjectUtil; public function getHoge():void { service.getHoge(); } public function onResult(event:ResultEvent):void { Alert.show(ObjectUtil.toString(event)); var hoge:String = event.result as String; message.text = hoge; } public function onFault(event:FaultEvent):void { Alert.show(ObjectUtil.toString(event)); } ]]> </mx:Script> <s2:S2Flex2Service id="service" destination="mainService" result="onResult(event)" fault="onFault(event)" showBusyCursor="true" /> <mx:Text id="message" x="26" y="23" text="Hello World !" width="222" height="45" fontSize="30"/> <mx:Button x="26" y="76" label="ボタン" click="getHoge()"/> </mx:Application>
まだサーバ側を作ってないけど、この状態で一回実行してみよう。
実行すると、サービスが見つからないと起こられる。
そりゃそうだ。
ERROR 2007-03-15 16:03:23,046 [http-8080-Processor24] [EFLX0001]適用可能なServiceInvoker[mainService]が見つかりません。 org.seasar.flex2.rpc.remoting.service.exception.InvokerNotFoundRuntimeException: [EFLX0001]適用可能なServiceInvoker[mainService]が見つかりません。
ということで、サービスを作ってみる。
Main.mxmlの上で右クリックしたときのメニューに、"Create Service" というのがあるので、これで作る。
Create Service を実行すると、s2flex2.test.web.flex.MainService と、s2flex2.test.web.flex.MainServiceImpl を生成した。
で、こいつらに、getHoge メソッドを追加。
package s2flex2.test.web.flex; public interface MainService { String getHoge(); }
package s2flex2.test.web.flex.impl; import org.seasar.flex2.rpc.remoting.service.annotation.RemotingService; import s2flex2.test.web.flex.MainService; @RemotingService public class MainServiceImpl implements MainService { public String getHoge() { return "ほげ"; } }
で、実行してみる。
が、まだ InvokerNotFoundRuntimeException が出る。
exampleのAddサンプルを見ると、どうもconvention.dicon のrootPackageNameの設定が違うっぽい。
Addサンプルのconvention.diconだと、以下のようになっていて、
<initMethod name="addRootPackageName"> <arg>"examples.flex2.add"</arg> </initMethod>
サービスクラスは、examples.flex2.add.service.AddService と、examples.flex2.add.service.impl.AddServiceImple になっている。
つまり、Addサンプルでは、ルートパッケージの直下のserviceパッケージにサービスクラスが入っている。
なので、MessageService と MessageServiceImpl のパッケージを、それぞれ s2flex2.test.service と s2flex2.test.service.impl に変更する。
で、実行してみる。
DEBUG 2007-03-15 16:20:22,875 [http-8080-Processor24] HOT deployを開始します DEBUG 2007-03-15 16:20:22,968 [http-8080-Processor24] クラス(s2flex2.test.service.impl.MainServiceImpl[mainService])のコンポーネント定義を登録します DEBUG 2007-03-15 16:20:23,468 [http-8080-Processor24] mainService(クラス:s2flex2.test.service.impl.MainServiceImpl)をRemotingServiceとして登録しました。 DEBUG 2007-03-15 16:20:23,500 [http-8080-Processor24] BEGIN s2flex2.test.service.impl.MainServiceImpl#getHoge() DEBUG 2007-03-15 16:20:23,500 [http-8080-Processor24] END s2flex2.test.service.impl.MainServiceImpl#getHoge() : ほげ DEBUG 2007-03-15 16:20:23,515 [http-8080-Processor24] HOT deployを終了しました
ようやくうまくいった。
ここまでで、MainServiceを追加して、パッケージ移動したけど、Tomcatは最初に起動したままで再起動はしていない。
HotDeployすげぇ。
続けて、サービスクラスを、s2flex2.test.web.flex.serviceパッケージに、移動してみる。
サービスクラスを、s2flex2.test.web.flex.service.MessageService と s2flex2.test.web.flex.service.impl.MessageServiceImpl に変更。
実行してみる。
DEBUG 2007-03-15 16:42:37,328 [http-8080-Processor24] HOT deployを開始します DEBUG 2007-03-15 16:42:37,359 [http-8080-Processor24] クラス(s2flex2.test.web.flex.service.impl.MainServiceImpl[mainService])のコンポーネント定義を登録します DEBUG 2007-03-15 16:42:37,406 [http-8080-Processor24] mainService(クラス:s2flex2.test.web.flex.service.impl.MainServiceImpl)をRemotingServiceとして登録しました。 DEBUG 2007-03-15 16:42:37,406 [http-8080-Processor24] BEGIN s2flex2.test.web.flex.service.impl.MainServiceImpl#getHoge() DEBUG 2007-03-15 16:42:37,406 [http-8080-Processor24] END s2flex2.test.web.flex.service.impl.MainServiceImpl#getHoge() : ほげ DEBUG 2007-03-15 16:42:37,406 [http-8080-Processor24] HOT deployを終了しました
おぉ、うまく動いた。
どうやら、serviceという名前のパッケージに入れれば動くということらしい。
追記:
いや、Tomcatを再起動したら、s2flex2.test.web.flex.service だと動かない。
[EFLX0001]適用可能なServiceInvoker[mainService]が見つかりません。 org.seasar.flex2.rpc.remoting.service.exception.InvokerNotFoundRuntimeException: [EFLX0001]適用可能なServiceInvoker[mainService]が見つかりません。
そうなると、ルートパッケージ直下のserviceに入れるしかないのか。。。
サブアプリケーション単位で分けたい場合は、convention.diconに追加していく感じ?
S2Flex2を試してみた。(1)
環境は以下のとおり。
- Dolteng0.18.0
- Eclipse3.2.0
- JDK1.5.0_08
- Tomcat 5.5.17
Eclipseの新規作成から、Chura Project を選んで、S2Flex2 + S2Dao を選択してプロジェクトを作成。
Root Package Name はとりあえず、s2flex2.test とする。
プロジェクトを作成すると、s2関連のjarが見つからないといわれた。
ビルド・パスのエラーが解決されるまで、プロジェクトをビルドできません プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/commons-logging-1.0.4.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/geronimo-jsp_2.0_spec-1.0.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/geronimo-jta_1.0.1B_spec-1.0.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/geronimo-servlet_2.4_spec-1.0.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/h2-2007-01-30.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-dao-1.0.41-SNAPSHOT.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-dao-tiger-1.0.41-SNAPSHOT.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-extension-2.4.10.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-flex2-1.0.1-SNAPSHOT.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-framework-2.4.10.jar' がありません。 プロジェクト s2flex2 に、必要なライブラリー 'WEB-INF/lib/s2-tiger-2.4.10.jar' がありません。
S2関連のjarがないと言っているので、WEB-INF/lib にjarを入れるために、各種最新版を落としてきたのだが、要求されているバージョンと微妙に違う。。
- S2Container 2.4.11
- S2Tiger 2.4.11
- S2Dao 1.0.41 RC
- S2DaoTiger 1.0.41 RC
- S2Flex2 1.0.1
- S2Flex2Tiger 1.0.0
けど、落とし直すのがめんどくさいので、ビルドパスを設定しなおして、エラーを消去。
で、Doltengが生成したものをみると、以下のようなディレクトリが作られている。
- bin ・・・ Flex2のソースをコンパイルした結果(swfやswc)が入る。
- html-template ・・・ Flex2コンパイル時に使用されるテンプレート
- WEB-INF/src/main/flex
- WEB-INF/src/main/java
- WEB-INF/src/main/resources
- 設定ファイル(dicon)が入っている。
まずは、Main.mxmlを表示してみよう。
Tomcat を起動したら、H2のライブラリがないと怒られる。
org.seasar.framework.beans.IllegalPropertyRuntimeException: [ESSR0059]クラス(org.seasar.extension.dbcp.impl.XADataSourceImpl)のプロパティ(driverClassName)の設定に失敗しました。理由はorg.seasar.framework.exception.ClassNotFoundRuntimeException: [ESSR0044]クラスが見つかりませんでした。詳細はjava.lang.ClassNotFoundException: org.h2.Driver
ビルドパスを設定しなおしたときに、S2の最新版にH2が入っていると思って特に確認しなかったんだけど、違うのか。。あぅ。
落とすのがめんどくさいので、SuperAgile で Chura Project を作ったときに、生成された h2-2007-01-30.jar をコピーしてWEB-INF/libへ入れることにする。
再度Tomcatを起動。
今度はエラーがでないで起動した。今度は大丈夫そうだ。
http://localhost:8080/s2flex2/bin/Main.html
にアクセスすると、Hello World と表示された。