<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3144177333818784642</id><updated>2012-02-17T13:37:10.525+09:00</updated><category term='gimp'/><title type='text'>知識創造技術者の日々</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default?start-index=101&amp;max-results=100'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>109</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3871533691849852270</id><published>2011-01-07T08:19:00.005+09:00</published><updated>2011-01-07T09:06:01.029+09:00</updated><title type='text'>Flash IDE 上でのMVCについて考えてみた（その２）</title><content type='html'>GUIコンポーネントは入れ子の構造となり、また各コンポーネントは MVC のすべての役割をもつため、MVC という枠組みだけでは対応できないと考え、前回の内容を変更しました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;今回作成したサンプル&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;TextArea に最初 0 が表示され、マウスでクリックもしくは Enter キーを押すごとに値が 1 増えるアプリです。&lt;/li&gt;&lt;/ul&gt;&lt;embed align="middle" allowscriptaccess="always" height="80" pluginspage="http://www.macromedia.com/go/getflashplayer" quality="high" src="https://sites.google.com/site/monookigoyadesu/20110107/obenkyo002.swf" type="application/x-shockwave-flash" width="250"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;b&gt;シンボル&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;LIBRARY 内のフォルダ名&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;シンボル名&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Component&lt;/li&gt;&lt;ul&gt;&lt;li&gt;リンク先のクラス&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.Component&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;b&gt;クラス構成&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.Component&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Flash IDE 上で作成したシンボルからリンクされるクラス。&lt;/li&gt;&lt;li&gt;コンポーネント全体を表すクラス。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model.Model&lt;/li&gt;&lt;ul&gt;&lt;li&gt;コンポーネントのモデルのインタフェース。&lt;/li&gt;&lt;li&gt;モデルは可能な限り実装を意識しないで設計したいため、あえてインタフェースを作成。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model.ModelImpl&lt;/li&gt;&lt;ul&gt;&lt;li&gt;コンポーネントのモデルの実装。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model.ModelListener&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Model の変更内容を監視するためのリスナーインタフェース&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view.ModelListenerImpl&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Model の変更を監視し、Model の変更内容に応じて View を更新するクラス。&lt;/li&gt;&lt;li&gt;ModelListenerインタフェースの実装クラス。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view.ViewInitializer&lt;/li&gt;&lt;ul&gt;&lt;li&gt;View を初期化するためのクラス。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.controller パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.controller.Controller&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Controller の Model 寄りの処理を行なう。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.controller.ViewAdapter&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Controller の Component 寄りの処理を行なう。&lt;/li&gt;&lt;li&gt;Component の内部要素に対してリスナーを登録し、イベントを監視する。&lt;/li&gt;&lt;li&gt;Component からのイベントを処理し、必要に応じて Model を更新する。 &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;b&gt;ソース&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.component {&lt;br /&gt;&lt;br /&gt;import com.objectfanatics.samplecomponent.controller.Controller;&lt;br /&gt;import com.objectfanatics.samplecomponent.controller.ViewAdapter;&lt;br /&gt;import com.objectfanatics.samplecomponent.model.Model;&lt;br /&gt;import com.objectfanatics.samplecomponent.model.ModelImpl;&lt;br /&gt;import com.objectfanatics.samplecomponent.view.ModelListenerImpl;&lt;br /&gt;import com.objectfanatics.samplecomponent.view.ViewInitializer;&lt;br /&gt;&lt;br /&gt;import flash.display.Sprite;&lt;br /&gt;import flash.text.TextField;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * FlashIDE 上の LIBRARY にて、フォルダ名が com.objectfanatics.samplecomponent、名前が Component のシンボルに対応するクラスです。&lt;br /&gt; *&lt;br /&gt; * このサンプルでは、GUIコンポーネントという単位を扱い、このクラスが１つの GUI コンポーネントを表しています。&lt;br /&gt; *&lt;br /&gt; * このコンポーネントの内部には TextField などの GUI コンポーネントが内包（FlashIDE上で定義されたシンボルのインスタンスやActionScriptで動的に作成されたものなど）&lt;br /&gt; * されており、それはこのコンポーネントそのものの Model, View, Controller のいずれでもないと考えます。&lt;br /&gt; *&lt;br /&gt; * そのため、このコンポーネントは Model, View, Controller だけでなく、自身を表す Component とその内部の Sub Components で表されると考えます。&lt;br /&gt; *&lt;br /&gt; * View については、Model の内容を常に反映しながら情報を外部に提供するという MVC で言うところの View は、オブジェクトとしては存在しないと考えます。&lt;br /&gt; * なぜなら、この役割は自身を表す Component もしくはその内部の Sub Components によって達成されるからです。&lt;br /&gt; *&lt;br /&gt; * 自身を表す Component とその内部の Sub Components が View に該当するかというと、View としての性質を持っていますが、同時に Model でもあり Controller でも&lt;br /&gt; * あるため、View と表現するのは妥当ではないと考えます。そのため、自身を表す Component とその内部の Sub Components という表現をしています。&lt;br /&gt; *&lt;br /&gt; */&lt;br /&gt;public class Component extends Sprite {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * numberText sub component.&lt;br /&gt;     */&lt;br /&gt;    public var numberText:TextField;&lt;br /&gt;&lt;br /&gt;    public function Component ():void&lt;br /&gt;    {&lt;br /&gt;        // Model を初期化します&lt;br /&gt;        var model:Model = new ModelImpl ();&lt;br /&gt;&lt;br /&gt;        // Model の変更内容を監視し Component に反映させるための ModelListener を初期化します&lt;br /&gt;        model.modelListener = new ModelListenerImpl (this);&lt;br /&gt;&lt;br /&gt;        // Controller を初期化します&lt;br /&gt;        var controller:Controller = new Controller (this, model);&lt;br /&gt;&lt;br /&gt;        // Component もしくは Sub Components からの入力を監視し Controller に伝える処理を行うクラスを初期化します&lt;br /&gt;        new ViewAdapter (this, controller);&lt;br /&gt;&lt;br /&gt;        // View を初期化します&lt;br /&gt;        new ViewInitializer (this, model);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.controller {&lt;br /&gt;&lt;br /&gt;import com.objectfanatics.samplecomponent.component.Component;&lt;br /&gt;import com.objectfanatics.samplecomponent.model.Model;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Controller クラスです.&lt;br /&gt; *&lt;br /&gt; * Component の監視処理の記述は ViewAdapter クラスが行っています。&lt;br /&gt; *&lt;br /&gt; * Controller 自身が Component や Sub Component の監視を行う場合、複数のコンポーネント上で&lt;br /&gt; * ボタンの監視やキーが押されることが、Model の値をインクリメントさせるトリガに成り得ます。&lt;br /&gt; * このような処理を Controller の Component 寄りの処理と言うことにします。&lt;br /&gt; *&lt;br /&gt; * しかし、どのボタンが押されてもキーが押されても Controller としては Model の値をインクリメント&lt;br /&gt; * して欲しいというイベントであると考えられます。このような考えに基づく処理を Controller の&lt;br /&gt; * Model 寄りの処理と言うことにします。&lt;br /&gt; *&lt;br /&gt; * そう考えると、Controller の Model 寄りの処理を Controller が、Component 寄りの処理を&lt;br /&gt; * ViewAdapter が行っていると言うことができます。&lt;br /&gt; */&lt;br /&gt;public class Controller {&lt;br /&gt;&lt;br /&gt;    private var model:Model;&lt;br /&gt;    private var component:Component;&lt;br /&gt;&lt;br /&gt;    public function Controller (component:Component, model:Model):void&lt;br /&gt;    {&lt;br /&gt;        this.component = component;&lt;br /&gt;        this.model = model;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Model の値をインクリメントします.&lt;br /&gt;     */&lt;br /&gt;    public function increment ():void&lt;br /&gt;    {&lt;br /&gt;        model.increment ();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.controller {&lt;br /&gt;&lt;br /&gt;import com.objectfanatics.samplecomponent.component.Component;&lt;br /&gt;&lt;br /&gt;import flash.events.KeyboardEvent;&lt;br /&gt;import flash.events.MouseEvent;&lt;br /&gt;import flash.ui.Keyboard;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Controller の Component 寄りの処理を受け持つクラスです.&lt;br /&gt; *&lt;br /&gt; * Component もしくは Sub Components からの入力を監視し Controller に伝える処理を行います.&lt;br /&gt; */&lt;br /&gt;public class ViewAdapter {&lt;br /&gt;&lt;br /&gt;    private var controller:Controller;&lt;br /&gt;&lt;br /&gt;    public function ViewAdapter (component:Component, controller:Controller):void&lt;br /&gt;    {&lt;br /&gt;        // Controller の格納&lt;br /&gt;        this.controller = controller;&lt;br /&gt;&lt;br /&gt;        // Component のクリックの検出設定&lt;br /&gt;        component.addEventListener (MouseEvent.CLICK, onClicked);&lt;br /&gt;&lt;br /&gt;        // Enter キーの検出設定&lt;br /&gt;        component.addEventListener (KeyboardEvent.KEY_UP, onKeyUp);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private function onClicked (e:MouseEvent):void&lt;br /&gt;    {&lt;br /&gt;        controller.increment ();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private function onKeyUp(e:KeyboardEvent):void {&lt;br /&gt;        if (e.keyCode == Keyboard.ENTER) {&lt;br /&gt;            controller.increment ();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Model インタフェースです.&lt;br /&gt; */&lt;br /&gt;public interface Model {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * ModelListener をセットします。&lt;br /&gt;     * @param modelListener ModelListener&lt;br /&gt;     */&lt;br /&gt;    function set modelListener (modelListener:ModelListener):void;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * 値を返します。&lt;br /&gt;     * @return 値&lt;br /&gt;     */&lt;br /&gt;    function get number ():uint;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * 値を1増やします。&lt;br /&gt;     */&lt;br /&gt;    function increment ():void;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Model の実装クラスです.&lt;br /&gt; */&lt;br /&gt;public class ModelImpl implements Model {&lt;br /&gt;&lt;br /&gt;    private var _modelListener:ModelListener;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * 保持される値&lt;br /&gt;     */&lt;br /&gt;    private var _number:uint = 0;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Model#get number():uint の実装&lt;br /&gt;     */&lt;br /&gt;    public function get number ():uint&lt;br /&gt;    {&lt;br /&gt;        return _number;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Model#set modelListener(modelListener:ModelListener):void の実装&lt;br /&gt;     */&lt;br /&gt;    public function set modelListener (modelListener:ModelListener):void&lt;br /&gt;    {&lt;br /&gt;        this._modelListener = modelListener;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Model#increment():void の実装&lt;br /&gt;     */&lt;br /&gt;    public function increment ():void&lt;br /&gt;    {&lt;br /&gt;        this._modelListener.numberChanged (++_number);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Model の変更内容を監視するためのリスナー&lt;br /&gt; */&lt;br /&gt;public interface ModelListener {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * 値が変更された場合に呼び出されます。&lt;br /&gt;     *&lt;br /&gt;     * @param number 変更後の値&lt;br /&gt;     */&lt;br /&gt;    function numberChanged (number:uint);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.view {&lt;br /&gt;&lt;br /&gt;import com.objectfanatics.samplecomponent.component.Component;&lt;br /&gt;import com.objectfanatics.samplecomponent.model.ModelListener;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Model の変更内容を監視し Component に反映させるための ModelListener の実装クラス。&lt;br /&gt; */&lt;br /&gt;public class ModelListenerImpl implements ModelListener {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * 変更対象の Component&lt;br /&gt;     */&lt;br /&gt;    private var component:Component;&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * コンストラクタ&lt;br /&gt;     * @param view 変更対象の View&lt;br /&gt;     */&lt;br /&gt;    public function ModelListenerImpl (component:Component):void&lt;br /&gt;    {&lt;br /&gt;        this.component = component;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Model の値が変更された時に呼び出され、View 上の表示を変更します。&lt;br /&gt;     * @param currentNumber 現在のの Model の値&lt;br /&gt;     */&lt;br /&gt;    public function numberChanged (currentNumber:uint)&lt;br /&gt;    {&lt;br /&gt;        component.numberText.text = "" + currentNumber;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.view {&lt;br /&gt;&lt;br /&gt;import com.objectfanatics.samplecomponent.component.Component;&lt;br /&gt;import com.objectfanatics.samplecomponent.model.Model;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * View を初期化するためのクラスです.&lt;br /&gt; *&lt;br /&gt; * ここではこのコンポーネント全体の見た目を初期化するため、View ということばをあえて使用しています。&lt;br /&gt; */&lt;br /&gt;public class ViewInitializer {&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * View を初期化します.&lt;br /&gt;     *&lt;br /&gt;     * @param component Component&lt;br /&gt;     * @param model Model&lt;br /&gt;     */&lt;br /&gt;    public function ViewInitializer (component:Component, model:Model):void&lt;br /&gt;    {&lt;br /&gt;        component.numberText.text = "" + model.number;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;今回の所感&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;今回 Component として扱った箇所を前回は View として扱っていてなんとなく気持ち悪かったのですが、なんとなくすっきりした気がします。&lt;br /&gt;&lt;br /&gt;コンポーネントを構成するクラスの数がかなり多くなっていますが、１つのコンポーネントのサブコンポーネントが数十とか数百あり全体のソースが数千行以上に及ぶようなコンポーネントをを作成するのであればこの程度の分割はメリットはあってもデメリットはないと思います。&lt;br /&gt;&lt;br /&gt;それほど大きなコンポーネントを作成しない場合であれば、いくつかもしくはすべてを省略してもかまわないと思います。要はケースバイケースということですね。&lt;br /&gt;&lt;br /&gt;Twinner で画面上のコンポーネントを動かしたりするような場合、処理はどこに書くのかな？　その処理のトリガがGUIからの入力であればトリガの処理は ViewAdapter に記述して、実際の処理は Controller かな。Twinnerなどによる処理や ActionScript を用いてのコンポーネントの処理などが多くデザイン系の比重が大きい場合は、Controller の描画寄りの処理用として別クラスにしたほうがいいかもしれません。しかし、クラス名や責務はなんだろう。Controllerなのか？Viewなのか？&lt;br /&gt;&lt;br /&gt;徹夜後の夕方なのでちょっとヘロヘロです(´・ω・`)&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/monookigoyadesu/20110107/flash_obenkyo_002.7z"&gt;アーカイブ&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3871533691849852270?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3871533691849852270/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2011/01/flash-ide-mvc.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3871533691849852270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3871533691849852270'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2011/01/flash-ide-mvc.html' title='Flash IDE 上でのMVCについて考えてみた（その２）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8406574753274152760</id><published>2011-01-01T09:14:00.000+09:00</published><updated>2011-01-01T09:14:09.970+09:00</updated><title type='text'>asdocのエラー</title><content type='html'>asdoc を作成する際に遭遇したエラーのメモ&lt;br /&gt;&lt;br /&gt;&lt;b&gt;エラー内容&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;[Fatal Error] :3:6: エレメント型 "Hoge" は対応する終了タグ "&amp;lt;/Hoge&amp;gt;" で終了する必要があります。&lt;br /&gt;適格な形式でないテキストが検出されました。詳細については、C:\hoge\fuga\piyo\validation_errors.log を参照してください。&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;ログ内容&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;org.xml.sax.SAXParseException: エレメント型 "Hoge" は対応する終了タグ "&amp;lt;/Hoge&amp;gt;" で終了する必要があります。&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;原因と対応方法&lt;/b&gt;&lt;br /&gt;メソッドの /** */ で囲まれているドキュメント内に Vector.&amp;lt;Hoge&amp;gt; のような箇所があったことが原因。括弧をエスケープして対応。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8406574753274152760?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8406574753274152760/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2011/01/asdoc.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8406574753274152760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8406574753274152760'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2011/01/asdoc.html' title='asdocのエラー'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4976992956017908467</id><published>2010-12-01T19:50:00.001+09:00</published><updated>2010-12-01T19:59:57.692+09:00</updated><title type='text'>asdocでjavadocの-linkオプションのようなことをしようと思ったが、、、</title><content type='html'>自作ライブラリの asdoc から as3 の core に含まれている Number とか Boolean とか Vector などの asdoc へのリンクを貼りたくて、調べてみました。&lt;br /&gt;&lt;br /&gt;すると、同様の要求が下記のように登録されていました。&lt;br /&gt;&lt;br /&gt;&lt;a href="https://bugs.adobe.com/jira/browse/SDK-26395"&gt;ASDoc: Hyperlinks to Actionscript Language Reference documentation&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;For example, if a method in my custom class returns a Boolean, I would like to be able to click on the word "Boolean", which would take me to the Boolean documentation in the AS3.0 Language Reference:&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/AS3LCR/Flash_10.0/Boolean.html"&gt;http://help.adobe.com/en_US/AS3LCR/Flash_10.0/Boolean.html&lt;/a&gt;&lt;/blockquote&gt;まさにこの機能！ (｀・ω・´)&lt;br /&gt;&lt;br /&gt;しかし、type が Minor Enhancement として登録されています。&lt;br /&gt;&lt;br /&gt;マイナーらしいです。 (´・ω・`)&lt;br /&gt;&lt;br /&gt;しかも、&lt;br /&gt;&lt;blockquote&gt;Nice request but out of scope for this release. Deferring.&lt;/blockquote&gt;として、クローズされてます。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.as3commons.org/as3-commons-lang/asdoc/"&gt;as3commonsのasdoc&lt;/a&gt;でも対応してないところをみると、今のところ有効な手段はないかもしれませんね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4976992956017908467?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4976992956017908467/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/12/asdocjavadoc-link.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4976992956017908467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4976992956017908467'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/12/asdocjavadoc-link.html' title='asdocでjavadocの-linkオプションのようなことをしようと思ったが、、、'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2113684312915511884</id><published>2010-11-27T18:27:00.024+09:00</published><updated>2010-11-30T01:34:38.783+09:00</updated><title type='text'>flex-mojos と asdoc</title><content type='html'>&lt;b&gt;公式ページ&lt;/b&gt;&lt;br /&gt;http://flexmojos.sonatype.org/&lt;br /&gt;&lt;br /&gt;&lt;b&gt;flexmojos-maven-plugin のある場所&lt;/b&gt;&lt;br /&gt;&lt;a href="http://repository.sonatype.org/content/groups/flexgroup/org/sonatype/flexmojos/flexmojos-maven-plugin/"&gt;http://repository.sonatype.org/content/groups/flexgroup/org/sonatype/flexmojos/flexmojos-maven-plugin/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;com.adobe.flex.framework系のある場所&lt;/b&gt;&lt;br /&gt;以下あたりを参考にして、バージョンを決めればよさそう。&lt;br /&gt;&lt;a href="https://repository.sonatype.org/content/groups/flexgroup/com/adobe/flex/framework/framework/"&gt;https://repository.sonatype.org/content/groups/flexgroup/com/adobe/flex/framework/framework/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;mvn test と mvn verify ができる最低限の pom.xml&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&lt;br /&gt;    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;!-- pom.xml参考 : http://dev.yoolab.org/maven/content/repositories/releases/org/as3commons/as3commons-project/1.0.1/as3commons-project-1.0.1.pom --&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;br /&gt;    &amp;lt;groupId&amp;gt;com.objectfanatics&amp;lt;/groupId&amp;gt;&lt;br /&gt;    &amp;lt;artifactId&amp;gt;sandbox&amp;lt;/artifactId&amp;gt;&lt;br /&gt;    &amp;lt;packaging&amp;gt;swc&amp;lt;/packaging&amp;gt;&lt;br /&gt;    &amp;lt;name&amp;gt;ObjectFanatics Sandbox Project&amp;lt;/name&amp;gt;&lt;br /&gt;    &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;&lt;br /&gt;    &amp;lt;inceptionYear&amp;gt;2010&amp;lt;/inceptionYear&amp;gt;&lt;br /&gt;    &amp;lt;url&amp;gt;http://www.objectfanatics.com/&amp;lt;/url&amp;gt;&lt;br /&gt;    &amp;lt;description&amp;gt;ObjectFanatics Sandbox Project&amp;lt;/description&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;!-- flex-mojos version --&amp;gt;&lt;br /&gt;        &amp;lt;flex-mojos.version&amp;gt;3.5.0&amp;lt;/flex-mojos.version&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;!-- flex version --&amp;gt;&lt;br /&gt;        &amp;lt;flex.version&amp;gt;3.5.0.12683&amp;lt;/flex.version&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;!-- flashplayer version --&amp;gt;&lt;br /&gt;        &amp;lt;flashplayer.version&amp;gt;${flashplayer.version.major}.${flashplayer.version.minor}.${flashplayer.version.revision}&amp;lt;/flashplayer.version&amp;gt;&lt;br /&gt;        &amp;lt;flashplayer.version.major&amp;gt;10&amp;lt;/flashplayer.version.major&amp;gt;&lt;br /&gt;        &amp;lt;flashplayer.version.minor&amp;gt;0&amp;lt;/flashplayer.version.minor&amp;gt;&lt;br /&gt;        &amp;lt;flashplayer.version.revision&amp;gt;0&amp;lt;/flashplayer.version.revision&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;!-- 開発者情報 --&amp;gt;&lt;br /&gt;    &amp;lt;developers&amp;gt;&lt;br /&gt;        &amp;lt;developer&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;makoto.sato&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;name&amp;gt;Makoto Sato&amp;lt;/name&amp;gt;&lt;br /&gt;            &amp;lt;email&amp;gt;makoto.sato [at] objectfanatics.com&amp;lt;/email&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://www.objectfanatics.com&amp;lt;/url&amp;gt;&lt;br /&gt;            &amp;lt;organization&amp;gt;ObjectFanatics Ltd.&amp;lt;/organization&amp;gt;&lt;br /&gt;            &amp;lt;organizationUrl&amp;gt;http://www.objectfanatics.com&amp;lt;/organizationUrl&amp;gt;&lt;br /&gt;            &amp;lt;timezone&amp;gt;+9&amp;lt;/timezone&amp;gt;&lt;br /&gt;        &amp;lt;/developer&amp;gt;&lt;br /&gt;    &amp;lt;/developers&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;dependencies&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;!-- Player/Air Global dependency. --&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;playerglobal&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;classifier&amp;gt;${flashplayer.version.major}&amp;lt;/classifier&amp;gt;&lt;br /&gt;            &amp;lt;!--&amp;lt;classifier&amp;gt;${flashplayer.version.major}.${flashplayer.version.minor}&amp;lt;/classifier&amp;gt;--&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;!-- for unit testing. http://asunit.org/ --&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.asunit&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;asunit&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;20071011&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;!-- Dependencies for Flex. This includes flex classes. ex: ListCollectionView. --&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;framework&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;!-- Dependencies for Flex. This includes resource bundle. Not having this dependency causes some errors. ex: [ERROR] Unable to resolve resource bundle "collections" for locale "en_US". --&amp;gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;framework&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;rb.swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;utilities&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;flex&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;framework&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;zip&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;classifier&amp;gt;configs&amp;lt;/classifier&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;rpc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;swc&amp;lt;/type&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;        &lt;br /&gt;        &amp;lt;dependency&amp;gt;&lt;br /&gt;            &amp;lt;groupId&amp;gt;com.adobe.flex.framework&amp;lt;/groupId&amp;gt;&lt;br /&gt;            &amp;lt;artifactId&amp;gt;rpc&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;            &amp;lt;type&amp;gt;rb.swc&amp;lt;/type&amp;gt;&lt;br /&gt;            &amp;lt;scope&amp;gt;external&amp;lt;/scope&amp;gt;&lt;br /&gt;        &amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/dependencies&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;build&amp;gt;&lt;br /&gt;        &amp;lt;sourceDirectory&amp;gt;src/main/actionscript&amp;lt;/sourceDirectory&amp;gt;&lt;br /&gt;        &amp;lt;testSourceDirectory&amp;gt;src/test/actionscript&amp;lt;/testSourceDirectory&amp;gt;&lt;br /&gt;        &amp;lt;defaultGoal&amp;gt;test&amp;lt;/defaultGoal&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;plugins&amp;gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-resources-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;encoding&amp;gt;UTF-8&amp;lt;/encoding&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.sonatype.flexmojos&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;flexmojos-maven-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                &amp;lt;version&amp;gt;${flex-mojos.version}&amp;lt;/version&amp;gt;&lt;br /&gt;                &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;&lt;br /&gt;                &amp;lt;dependencies&amp;gt;&lt;br /&gt;                    &amp;lt;dependency&amp;gt;&lt;br /&gt;                        &amp;lt;groupId&amp;gt;com.adobe.flex&amp;lt;/groupId&amp;gt;&lt;br /&gt;                        &amp;lt;artifactId&amp;gt;compiler&amp;lt;/artifactId&amp;gt;&lt;br /&gt;                        &amp;lt;version&amp;gt;${flex.version}&amp;lt;/version&amp;gt;&lt;br /&gt;                        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;&lt;br /&gt;                    &amp;lt;/dependency&amp;gt;&lt;br /&gt;                &amp;lt;/dependencies&amp;gt;&lt;br /&gt;                &amp;lt;configuration&amp;gt;&lt;br /&gt;                    &amp;lt;configurationReport&amp;gt;true&amp;lt;/configurationReport&amp;gt;&lt;br /&gt;                    &amp;lt;targetPlayer&amp;gt;${flashplayer.version}&amp;lt;/targetPlayer&amp;gt;&lt;br /&gt;                    &amp;lt;locales&amp;gt;&lt;br /&gt;                        &amp;lt;param&amp;gt;en_US&amp;lt;/param&amp;gt;&lt;br /&gt;                    &amp;lt;/locales&amp;gt;&lt;br /&gt;                    &amp;lt;updateSecuritySandbox&amp;gt;true&amp;lt;/updateSecuritySandbox&amp;gt;&lt;br /&gt;                    &amp;lt;includeAsClasses&amp;gt;&lt;br /&gt;                        &amp;lt;source&amp;gt;&lt;br /&gt;                            &amp;lt;directory&amp;gt;src/main/actionscript&amp;lt;/directory&amp;gt;&lt;br /&gt;                        &amp;lt;/source&amp;gt;&lt;br /&gt;                    &amp;lt;/includeAsClasses&amp;gt;&lt;br /&gt;                &amp;lt;/configuration&amp;gt;&lt;br /&gt;                &amp;lt;/plugin&amp;gt;&lt;br /&gt;                &amp;lt;plugin&amp;gt;&lt;br /&gt;                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;&lt;br /&gt;                &amp;lt;artifactId&amp;gt;maven-site-plugin&amp;lt;/artifactId&amp;gt;&lt;br /&gt;            &amp;lt;/plugin&amp;gt;&lt;br /&gt;        &amp;lt;/plugins&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;/build&amp;gt;&lt;br /&gt;    &lt;br /&gt;    &amp;lt;repositories&amp;gt;&lt;br /&gt;        &amp;lt;repository&amp;gt;&lt;br /&gt;            &amp;lt;id&amp;gt;flex-mojos-repository&amp;lt;/id&amp;gt;&lt;br /&gt;            &amp;lt;url&amp;gt;http://repository.sonatype.org/content/groups/flexgroup&amp;lt;/url&amp;gt;&lt;br /&gt;        &amp;lt;/repository&amp;gt;&lt;br /&gt;    &amp;lt;/repositories&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;/project&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;asDocの生成&lt;/b&gt;&lt;br /&gt;flex-mojosでやろうとしたが、3系だとVectorとかのクラスを認識せず、4系だとspark.cssが見つからないとか言われる。本家のバグレポートでは、3系でバグレポートがでてるのに4.0でFixedということでバグがクローズされてる。このような開発状況を見るかぎりは flex-mojo を利用するのはリスクが高いですね、、、。今回はとりあえずasDocの生成をflex-sdkを直接使って行うだけに留めるけど、将来的には構成管理全般からflex-mojosを外すことにしよう。&lt;br /&gt;&lt;pre class="prettyprint"&gt;"C:\Program Files\flex_sdk_4.1.0.16076\bin\asdoc.exe" -source-path . -doc-sources .&lt;br /&gt;&lt;/pre&gt;ちなみに、as3のソースコードの内容によって以下のようなエラーが出ることがある。&lt;br /&gt;&lt;pre class="prettyprint"&gt;エラー: toplevel.xml を作成できませんでした : String index out of range: -41&lt;br /&gt;&lt;/pre&gt;原因は未確認。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2113684312915511884?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2113684312915511884/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flex-mojos.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2113684312915511884'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2113684312915511884'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flex-mojos.html' title='flex-mojos と asdoc'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7284841317345363990</id><published>2010-11-10T07:35:00.004+09:00</published><updated>2010-11-11T03:52:45.481+09:00</updated><title type='text'>非同期呼び出しについてのメモ</title><content type='html'>非同期呼び出しが絡んだ設計方法についてのメモです。&lt;br /&gt;&lt;br /&gt;※以下、実装がマルチスレッドなのかシングルスレッドなのかは無視して考えましょう。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;いい感じの本&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.eaipatterns.com/"&gt;Enterprise Integration Patterns&lt;/a&gt; とかいい感じっす。ECMA Script 系で必要とされるような非同期処理を扱う雰囲気の本ではなくて JMS や MQ 系のメッセージイングサーバを意識した本なのですが、最初の方の章が非同期処理に関する説明がいい感じで載っています。&lt;br /&gt;&lt;br /&gt;おいらも読みなおしたいんだけど、日本に置いてきたので今は読めません(´・ω・`)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;同期呼び出しのみの場合&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;スレッド１：処理A -&amp;gt; 処理B -&amp;gt; 処理C のように実行される。&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;ある処理が非同期処理に依存する場合&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;すべての処理が非同期だが、すべての処理が依存関係を持つ場合。&lt;br /&gt;&lt;pre class="prettyprint"&gt;スレッド１：処理Aに処理Bをコールバック登録してフォーク &lt;br /&gt;スレッド２：     処理A実行 -&amp;gt; 処理Bに処理Cをコールバック登録してフォーク&lt;br /&gt;スレッド３：            処理B実行 -&amp;gt; 処理Cにフォーク&lt;br /&gt;スレッド４：                   処理C実行&lt;br /&gt;&lt;/pre&gt;この手の処理が、かなり面倒。そもそも概念的に非同期処理でないものを実装上強引に非同期処理にしているだけであり、同時並行処理のメリットが全く無い（シングルスレッド環境などの制約条件下でしかたなく対応するケースがほとんどだと思われ）。しかし、依存する処理をコールバックに変換するだけなので、同期呼び出しの場合からの機械的な変換は可能。この手の設計になる場合、同期処理で擬似コードを書いてから、その後機械的に非同期処理に変換したほうがいいかも。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;非同期呼び出しにより処理がフォークする場合&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;各処理に依存関係がない場合は以下のように4つのスレッドが別々に動作する。&lt;br /&gt;&lt;pre class="prettyprint"&gt;スレッド１：処理Aフォーク -&amp;gt; 処理Bフォーク -&amp;gt; 処理Cフォーク &lt;br /&gt;スレッド２：              -&amp;gt; 処理A&lt;br /&gt;スレッド３：                               -&amp;gt; 処理B&lt;br /&gt;スレッド４：                                               → 処理C&lt;br /&gt;&lt;/pre&gt;スレッド1の動作は一瞬にして行われるので、処理A,B,Cはほぼ同時に開始する。このような非同期処理は、人間から見てもそこそこ直感的。多くの場合シーケンシャルに動作させた場合よりも高い性能が得られる。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;非同期呼び出し処理がジョインする場合&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;処理A,B,Cのすべてが完了したあとに次の処理が行われる場合の例&lt;br /&gt;&lt;pre class="prettyprint"&gt;スレッド１：処理Aフォーク -&amp;gt; 処理Bフォーク -&amp;gt; 処理Cフォーク &lt;br /&gt;スレッド２：              -&amp;gt; 処理A -&amp;gt; 合流条件確認 -&amp;gt; (失敗)&lt;br /&gt;スレッド３：                               -&amp;gt; 処理B                         -&amp;gt; 合流条件確認 -&amp;gt; (成功) -&amp;gt; 合流後の処理&lt;br /&gt;スレッド４：                                                -&amp;gt; 処理C -&amp;gt; 合流条件確認 -&amp;gt; (失敗)&lt;br /&gt;&lt;/pre&gt;非同期処理のパフォーマンスを享受しつつ、処理の同期もおこなってしまうというおいしいところ取りですね。ジョインする条件の確認や、その条件を構成する情報の登録などをする必要があるのでコーディングレベルでは少しめんどくさいのですが、事前に設計をきちんとやっておけば問題ないでしょう。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;設計方針考察&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;まずは、fork と join の発生する処理は避けて実装する。非同期処理を利用するとしても陸上のリレーのようにコールバックを用いて処理を継続させる方法であれば、join 条件のチェックが必要無いので設計がシンプルになる。この方法で、一通り実装して、実装した機能が仕様を満たしていることを確認する。&lt;br /&gt;&lt;br /&gt;以下書きかけ。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;設計対象の１つの処理を決定する。&lt;/li&gt;&lt;li&gt;処理内にて順次処理とフォークする処理とジョイン後の処理を、最外殻のレベルで分類し、各々の処理の塊をグループとする。&lt;/li&gt;&lt;li&gt;上記グループのうち、最外殻のジョイン処理とそれにジョインされる処理を１つのグループとして扱う。&lt;/li&gt;&lt;li&gt;複数のグループが残った場合、上記の各グループをメソッド化し、それそれを順次実行する。（各々が依存関係を持たないため並行動作が可能）&lt;/li&gt;&lt;li&gt;単一の順次処理の場合はそのまま記述すればよい。非同期処理は必要ない。&lt;/li&gt;&lt;li&gt;単一のジョインされるグループが残った場合、ジョイン実行条件のための情報（ジョイン実行条件判断クロージャから見えるスコープのフラグなど）を用意し、ジョイン実行条件を判断するクロージャを用意し、ジョイン実行条件のための情報の変更を通知するためのクロージャを用意し、ジョイン後の処理のクロージャを用意し、残りのグループを各メソッドとして作成して引数にジョイン実行条件判断用のクロージャと情報通知用クロージャとジョイン後の処理のクロージャを渡すようにする。&lt;/li&gt;&lt;/ol&gt;以降、上記の1からをネストして行う。&lt;br /&gt;この説明じゃおいら自身以外にはわからんよねｗ　まぁ、個人的なメモなので、、、。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;まとめ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;同一スレッドでの順次処理、フォーク、ジョインの３種類を適切に考えて設計すればよいということですね。&lt;br /&gt;&lt;br /&gt;このような概念を用いた設計はプログラミング言語で記述することは直感的ではないと思うので（少なくともおいらには）、コーディングに入る前にアクティビティ図のような形で設計してみたほうがよいと思います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7284841317345363990?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7284841317345363990/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7284841317345363990'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7284841317345363990'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/blog-post.html' title='非同期呼び出しについてのメモ'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5119370815466603215</id><published>2010-11-04T04:15:00.008+09:00</published><updated>2010-11-04T20:30:16.880+09:00</updated><title type='text'>Flash IDE 上でのアルファを変えるだけの簡単なボタンの作成</title><content type='html'>今回は、Flashの勘所を友人に教わりつつ、簡単なボタンのコンポーネントを作成してみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;概要&lt;/b&gt;&lt;br /&gt;任意のSpriteを継承したオブジェクトに対して、マウスのロールオーバー時に alpha の値を変更する振る舞いを付加するコンポーネントおよびライブラリです。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;仕様&lt;/b&gt;&lt;br /&gt;AlphaTransitiveButtonクラス&lt;br /&gt;&lt;ul&gt;&lt;li&gt;概要&lt;/li&gt;&lt;ul&gt;&lt;li&gt;ロールオーバー時に alpha が変化する Sprite です。&lt;/li&gt;&lt;li&gt;ボタンモードはオンになります。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;メリット&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Flash IDE 上のシンボルからリンクするだけで、シンボルに対してロールオーバー時に alpha が 0.5 に変化する振る舞いを与えることができます。&lt;/li&gt;&lt;li&gt;自前の ActionScript を作成する必要がありません。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt; 備考&lt;br /&gt;以下の場合、AlphaTransitiveButton クラスを使用せずに ButtonUtils の addXxxBehavior() 系のメソッドを利用の検討を推奨します。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;既に継承を使用しているために継承が使えない場合。&lt;/li&gt;&lt;li&gt;Alpha を独自に設定したい場合。&lt;/li&gt;&lt;li&gt;継承を使いたくない場合。（例：10種類の振る舞いを追加するために10回継承するということを避けたい場合）&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;ButtonUtilsクラス&lt;br /&gt;&lt;ul&gt;&lt;li&gt;概要&lt;/li&gt;&lt;ul&gt;&lt;li&gt;指定された Sprite クラス(もしくは Sprite を継承したクラス)にロールオーバー時に alpha が変化する振る舞いを付加します。&lt;/li&gt;&lt;li&gt; ボタンモードはオンになります。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;備考&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Flash IDE 上のシンボルに対して本メソッドのデフォルトの振る舞いを追加する場合は AlphaTransitiveButton クラスの利用も検討してみてください。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;b&gt;サンプル&lt;/b&gt;&lt;br /&gt;&lt;embed align="middle" allowscriptaccess="always" height="200" pluginspage="http://www.macromedia.com/go/getflashplayer" quality="high" src="https://sites.google.com/site/monookigoyadesu/20101104/20101104_alpha_transitive_button.swf" type="application/x-shockwave-flash" width="550"&gt;&lt;/embed&gt; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;上のボタンは AlphaTransitiveButton クラスにリンクしています。&lt;/li&gt;&lt;li&gt;下のボタンは、ボタンのシンボルの1フレーム目で ButtonUtils#addAlphaTransitiveButtonBehavior(target, rollOverAlpha) を呼び出し、rollOverAlpha を0.8に設定しています。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;ソース&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;AlphaTransitiveButtonクラス&lt;br /&gt;&lt;pre class="prettyprint"&gt;package {&lt;br /&gt;    &lt;br /&gt;    import flash.display.Sprite;&lt;br /&gt;    import flash.events.MouseEvent;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * ロールオーバー時に alpha が変化する Sprite です。&lt;br /&gt;     * ボタンモードはオンになります。&lt;br /&gt;     * &lt;br /&gt;     * メリット&lt;br /&gt;     * 　・　Flash IDE 上のシンボルからリンクするだけで、シンボルに対してロールオーバー時に alpha が 0.5 に変化する振る舞いを与えることができます。&lt;br /&gt;     * 　・　自前の ActionScript を作成する必要がありません。&lt;br /&gt;     * &lt;br /&gt;     * 備考&lt;br /&gt;     * 　・　以下の場合、AlphaTransitiveButton クラスを使用せずに ButtonUtils の addXxxBehavior() 系のメソッドを利用の検討を推奨します。&lt;br /&gt;     * 　　　・　既に継承を使用しているために継承が使えない場合。&lt;br /&gt;     * 　　　・　Alpha を独自に設定したい場合。&lt;br /&gt;     * 　　　・　継承を使いたくない場合。（例：10種類の振る舞いを追加するために10回継承するということを避けたい場合）&lt;br /&gt;     * &lt;br /&gt;     * @see ButtonUtils#addAlphaTransitiveButtonBehavior(Sprite, Number)&lt;br /&gt;     */&lt;br /&gt;    public class AlphaTransitiveButton extends Sprite {&lt;br /&gt;        &lt;br /&gt;        public function AlphaTransitiveButton() {&lt;br /&gt;            ButtonUtils.addAlphaTransitiveButtonBehavior(this);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ButtonUtilsクラス&lt;br /&gt;&lt;pre class="prettyprint"&gt;package {&lt;br /&gt;    &lt;br /&gt;    import flash.display.Sprite;&lt;br /&gt;    import flash.events.MouseEvent;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * ボタン関連のユーティリティクラスです。&lt;br /&gt;     */&lt;br /&gt;    public class ButtonUtils extends Sprite {&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定された Sprite クラス(もしくは Sprite を継承したクラス)にロールオーバー時に alpha が変化する振る舞いを付加します。&lt;br /&gt;         * ボタンモードはオンになります。&lt;br /&gt;         * Flash IDE 上のシンボルに対して本メソッドのデフォルトの振る舞いを追加する場合は AlphaTransitiveButton クラスの利用も検討してみてください。&lt;br /&gt;         * &lt;br /&gt;         * 注： target が Dynamic Text の TextArea の場合など、特定の条件下でマウスオーバー時にマウスカーソルの形状が変化しない場合があります。(flash側の問題)&lt;br /&gt;         * &lt;br /&gt;         * @param target 対象となる Sprite&lt;br /&gt;         * @param rollOverAlpha ロールオーバー時の alpha の値&lt;br /&gt;         * @see AlphaTransitiveButton&lt;br /&gt;         */&lt;br /&gt;        public static function addAlphaTransitiveButtonBehavior(target:Sprite, rollOverAlpha:Number = 0.5) {&lt;br /&gt;            target.buttonMode = true;&lt;br /&gt;            target.addEventListener(MouseEvent.ROLL_OVER, function(e:MouseEvent):void {&lt;br /&gt;                e.currentTarget.alpha = rollOverAlpha;&lt;br /&gt;            });&lt;br /&gt;            target.addEventListener(MouseEvent.ROLL_OUT, function(e:MouseEvent):void {&lt;br /&gt;                e.currentTarget.alpha = 1;&lt;br /&gt;            });&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;a href="https://sites.google.com/site/monookigoyadesu/20101104/20101104_alpha_transitive_button.7z"&gt;アーカイブ&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5119370815466603215?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5119370815466603215/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flash-ide.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5119370815466603215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5119370815466603215'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flash-ide.html' title='Flash IDE 上でのアルファを変えるだけの簡単なボタンの作成'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8983362935751309757</id><published>2010-11-01T03:04:00.011+09:00</published><updated>2011-01-07T09:04:17.560+09:00</updated><title type='text'>Flash IDE 上でのMVCについて考えてみた</title><content type='html'>&lt;a href="http://kcw-diary.blogspot.com/2011/01/flash-ide-mvc.html"&gt;Flash IDE 上でのMVCについて考えてみた（その２）&lt;/a&gt; が最新です。&lt;br /&gt;&lt;br /&gt;近々、Flash IDE で開発を行うことになりました。&lt;br /&gt;&lt;br /&gt;開発に入る前の実験として、ステージ上に色々とコンポーネントを配置して、Documentクラスに ActionScript のコードを記述して、なんとなく動くものを作っていたというのがこれまでの話。しかし、これでは保守性に難があるなぁと思う今日この頃。&lt;br /&gt;&lt;br /&gt;保守性を向上させようと考えた場合に、すぐに思い浮かぶのはコンポーネント化。コンポーネント内部はシンプルなMVCがよさそう。&lt;br /&gt;&lt;br /&gt;ということで、実験してみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;方式&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Flash IDE 上で作成したシンボルから as ファイルにリンクを張る方式。&lt;/li&gt;&lt;li&gt;名前空間は Flash IDE 上の LIBRARY 内にフォルダを作成して対応する。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;今回作成するサンプル&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;TextArea に最初 0 が表示され、マウスでクリックするたびに値が 1 増えるアプリ。&lt;/li&gt;&lt;/ul&gt;&lt;embed src="https://sites.google.com/site/monookigoyadesu/20101031_01/obenkyo001.swf" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" align="middle" height="80" width="250"&gt;&lt;/embed&gt; &lt;br /&gt;&lt;br /&gt;&lt;b&gt;シンボル&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;LIBRARY 内のフォルダ名&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;シンボル名&lt;/li&gt;&lt;ul&gt;&lt;li&gt;View&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;リンク先のクラス&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view.View&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;クラス構成&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model.Model&lt;/li&gt;&lt;ul&gt;&lt;li&gt;コンポーネントのモデルのインタフェース。&lt;/li&gt;&lt;li&gt;モデルは可能な限り実装を意識しないで設計したいため、あえてインタフェースを作成。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.model.ModelImpl&lt;/li&gt;&lt;ul&gt;&lt;li&gt;コンポーネントのモデルの実装。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt; com.objectfanatics.samplecomponent.model.ModelListener&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Model の変更内容を監視するためのリスナーインタフェース&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;com.objectfanatics.samplecomponent.view.View&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Flash IDE 上で作成したシンボルからリンクされるクラス。&lt;/li&gt;&lt;li&gt;View として存在すると同時に、コンポーネント全体を構築する役割も持つ。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt; com.objectfanatics.samplecomponent.view.ModelListenerImpl&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Model の変更を監視し、Model の変更内容に応じて View を更新するクラス。&lt;/li&gt;&lt;li&gt; ModelListenerインタフェースの実装クラス。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt; com.objectfanatics.samplecomponent.controller パッケージ&lt;/li&gt;&lt;ul&gt;&lt;li&gt; com.objectfanatics.samplecomponent.controller.Controller&lt;/li&gt;&lt;ul&gt;&lt;li&gt;View の内部要素に対してリスナーを登録し、イベントを監視する。&lt;/li&gt;&lt;li&gt;View からのイベントを処理し、必要に応じて Model を更新する。&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;クラスのソース&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt; &lt;br /&gt; public interface Model {&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * ModelListener をセットします。&lt;br /&gt;   * @param modelListener ModelListener&lt;br /&gt;   */&lt;br /&gt;  function setModelListener(modelListener:ModelListener):void;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 値を返します。&lt;br /&gt;   * @return 値&lt;br /&gt;   */&lt;br /&gt;  function getNumber():uint;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 値を1増やします。&lt;br /&gt;   */&lt;br /&gt;  function increment():void;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt; &lt;br /&gt; public class ModelImpl implements Model {&lt;br /&gt;  &lt;br /&gt;  private var modelListener:ModelListener;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 保持される値&lt;br /&gt;   */&lt;br /&gt;  private var number:uint = 0;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Model#getNumber():uint の実装&lt;br /&gt;   */&lt;br /&gt;  public function getNumber():uint {&lt;br /&gt;   return number;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Model#setModelListener(modelListener:ModelListener):void の実装&lt;br /&gt;   */&lt;br /&gt;  public function setModelListener(modelListener:ModelListener):void {&lt;br /&gt;   this.modelListener = modelListener;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Model#increment():void の実装&lt;br /&gt;   */&lt;br /&gt;  public function increment():void {&lt;br /&gt;   this.modelListener.numberChanged(++number);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.model {&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Model の変更内容を監視するためのリスナー&lt;br /&gt;  */&lt;br /&gt; public interface ModelListener {&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 値が変更された場合に呼び出されます。&lt;br /&gt;   * @param number 現在の値&lt;br /&gt;   */&lt;br /&gt;  function numberChanged(number:uint);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.view {&lt;br /&gt; &lt;br /&gt; import flash.display.Sprite;&lt;br /&gt; &lt;br /&gt; import com.objectfanatics.samplecomponent.model.Model;&lt;br /&gt; import com.objectfanatics.samplecomponent.model.ModelImpl;&lt;br /&gt; import com.objectfanatics.samplecomponent.model.ModelListener;&lt;br /&gt; import com.objectfanatics.samplecomponent.controller.Controller;&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * FlashIDE 上の LIBRARY にて、フォルダ名が com.objectfanatics.samplecomponent、名前が View のシンボルに対応するクラス。&lt;br /&gt;  * View という名前ですが、FlashIDE上で作成したシンボルからのリンクとなっているため、コンポーネント全体の初期化も行っています。&lt;br /&gt;  * 純粋な View としての処理は、 Model には依存しますが Controller には依存しません。&lt;br /&gt;  */&lt;br /&gt; public class View extends Sprite {&lt;br /&gt;  &lt;br /&gt;  private const model:Model = new ModelImpl();&lt;br /&gt;  &lt;br /&gt;  public function View():void {&lt;br /&gt;   initView();&lt;br /&gt;   model.setModelListener(new ModelListenerImpl(this));&lt;br /&gt;   new Controller(this, model);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private function initView():void {&lt;br /&gt;   this.numberText.text = "" + model.getNumber();&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.view {&lt;br /&gt;&lt;br /&gt; import com.objectfanatics.samplecomponent.model.ModelListener;&lt;br /&gt;  &lt;br /&gt; /**&lt;br /&gt;  * Model の変更内容を監視し View に反映させるための ModelListener の実装クラス。&lt;br /&gt;  */&lt;br /&gt; public class ModelListenerImpl implements ModelListener {&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 変更対象の View&lt;br /&gt;   */&lt;br /&gt;  private var view:View;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * コンストラクタ&lt;br /&gt;   * @param view 変更対象の View&lt;br /&gt;   */&lt;br /&gt;  public function ModelListenerImpl(view:View):void {&lt;br /&gt;   this.view = view;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * Model の値が変更された時に呼び出され、View 上の表示を変更します。&lt;br /&gt;   * @param currentNumber 現在のの Model の値&lt;br /&gt;   */&lt;br /&gt;  public function numberChanged(currentNumber:uint) {&lt;br /&gt;   view.numberText.text = "" + currentNumber;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.samplecomponent.controller {&lt;br /&gt; &lt;br /&gt; import flash.events.MouseEvent;&lt;br /&gt; &lt;br /&gt; import com.objectfanatics.samplecomponent.view.View;&lt;br /&gt; import com.objectfanatics.samplecomponent.model.Model;&lt;br /&gt; &lt;br /&gt; public class Controller { &lt;br /&gt;  &lt;br /&gt;  private var model:Model;&lt;br /&gt;  &lt;br /&gt;  private var view:View;&lt;br /&gt;  &lt;br /&gt;  public function Controller(view:View, model:Model):void {&lt;br /&gt;   &lt;br /&gt;   // Model と View の格納&lt;br /&gt;   this.model = model;&lt;br /&gt;   this.view = view;&lt;br /&gt;   &lt;br /&gt;   // View のクリックの検出設定&lt;br /&gt;   view.addEventListener(MouseEvent.CLICK, function():void{model.increment()});&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;今回の所感&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;単純な仕様のコンポーネントであれば、この方法でも十分な保守性が得られるのではないかと思いました。しかし、複雑になるとどうなるか全く見当も付きません。実際に複雑なケースに適用してみて実際に問題が生じたときに、その問題をシンプルに表現できる例題を作成して考察してみようと思います。&lt;br /&gt;&lt;br /&gt;全体的な仕組みとして再利用が効きそうなポイントが多々あるのですが、ことごとくうまくいきませんでした。たとえば、Viewクラスの内部は Template Method を適用すればコード量抑えられるしロジックを完全に隠蔽できるので保守性が上がりそうなものです。しかし、abstract class が使えないために Template Method のメリットがかなり小さくなってしまいます。通常のクラスで Template Method を試してもみたのですが、Generics が使えないために手動での強引な型変換が必要となり、ソースがかなり長く見辛くなってしまいました。&lt;br /&gt;&lt;br /&gt;まだ as3 を触り始めてまもないので、当面は粛々と実験していきたいと思います。&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/monookigoyadesu/20101031_01/20101031_flash_obenkyo_001.7z"&gt;アーカイブ&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8983362935751309757?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8983362935751309757/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flash-ide-mvc.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8983362935751309757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8983362935751309757'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/11/flash-ide-mvc.html' title='Flash IDE 上でのMVCについて考えてみた'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3643825658924122108</id><published>2010-07-30T09:03:00.005+09:00</published><updated>2010-07-30T09:15:37.087+09:00</updated><title type='text'>カナダネタ：ホテル予約編</title><content type='html'>突然ですが、業務として8月から半年ほどバンクーバー（カナダ）に行くことになりました。&lt;br /&gt;&lt;br /&gt;ということで以下、ホテルの予約メモ。&lt;br /&gt;なにげに結構大変でしたｗ&lt;br /&gt;&lt;br /&gt;まず、安い宿がほとんどありません。数年前シリコンバレーにいた時は、ダウンタウンの交通の便がよいところでさえシングルルーム（風呂、トイレ、朝食、電話、高速インターネット回線付き）で$1,050/month、ダブルでも$1,200/month程度で借りられました。飛び込みでも普通のシングルルームで45$あれば借りることができました。月極のフラットを１室借りる場合は、$1,000/month前後でした（電話回線の契約とか自分でする必要がありますが）。しかし、バンクーバーではそうはいかないようです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ホテルを物色してみた&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.shaughnessyvillage.com/"&gt;Shaughnessy Village Vancouver&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;かなり安い宿です。8月は最高値なのですが、それでも$1045/momth。安いです。よさそうなので、メールでいくつか質問してみました。すると、3ヶ月で$915/month, 6ヶ月で$885/monthとのこと。さらに安い！ しかし、途中でのキャンセルについては支払った金額が全く払い戻されないということでした。個人的に、過去にこのような厳しい払い戻しルールの長期滞在用ホテルは経験したことも聞いたこともなく、メールが英文メールとしてもあまりにもぶっきらぼうであり、また、いくつかの質問をさらっと無視されてしまったので、念のため、&lt;a href="http://www.tripadvisor.jp/Hotel_Review-g154943-d186211-Reviews-Shaughnessy_Village-Vancouver_British_Columbia.html"&gt;評判をググッてみました&lt;/a&gt;。う～む。賛否両論ですが、事前に長期予約をするにはリスクが大きそうな感じですね。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.ywcahotel.com/"&gt;YWCA of Vancouver&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;口コミの評価がかなり高いです。Single (1 single bed) with semi- private bath*, TV の weekly rate が $74/night ということで、かなりリーズナブル。semi- private bath* は、2部屋で共有とのこと。"We also offer residence rate if you stay for a minimum of 30 days"とのことで、もっと長く止まるなら、もう少し安くなりそうです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.kingstonhotelvancouver.com/"&gt;The Kingston Hotel&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;シャワールームが共有で、シングルルームが $75 - $125 plus tax とのこと。8月はハイシーズンなので、125$/nightになりそうですね。monthlyのrateも乗っていないので、今回は見送り。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;結局・・・&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;結局、とりあえずYWCAを1ヶ月だけおさえることにして、その間に家具付きのフラットを借りる方向で進めてみることにしました。その際、もし途中キャンセルが可能なら６ヶ月間の予約を入れるという選択肢も残しておきます。&lt;br /&gt;&lt;br /&gt;ということで、availability と monthly rate の確認と、6ヶ月の予約を入れるが途中キャンセルする可能性があるという状況でよい案がないかなという質問をメールで確認したところ、非常に丁寧な回答メールを頂きました。以下要約。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;30日以上連続して宿泊する場合は、月単位のResidence形式を選択することが可能。その際、ホテルスタッフからの承認が必要になる（&lt;a href="http://www.ywcahotel.com/residency"&gt;Residenceの情報&lt;/a&gt;）。しかし、８月はハイシーズンなので daily のレートのみ。&lt;/li&gt;&lt;li&gt;長期滞在で部屋を出る日付が未定の場合は、ひとまず長期の予約をしておいて、部屋を出る１ヶ月前に話せばよい。&lt;/li&gt;&lt;li&gt;全館禁煙。&lt;/li&gt;&lt;li&gt;無線LANはロビーと各部屋で利用可能。価格は $6.00/day, $22.00/week, or $33.00/month。&lt;/li&gt;&lt;/ul&gt;weekly rate も residence rate も適用できないのは残念ですが、とりあえず8末まではここを押さえようとしたところ、シングルが空いてませんでした(´・ω・`)&lt;br /&gt;&lt;br /&gt;となると、ダブルになるので１日 $98.00 です。う～む、高いな。シャワー共有でこの値段は割に合わないなぁ、、、。しかし、今後ここに residence rate で宿泊する可能性も考えると、事前調査という意味ではアリか、、、、。このシーズンはどこも満室だし、中級ホテルでも$200/day弱するし、、、。&lt;br /&gt;&lt;br /&gt;ということで、到着日の8日から、某お祭りが終わって落ち着く頃ということで18日まで10夜分だけ予約を取ることにしました。（そして、PDF付きの確認メールがスパムフィルタにかかるのはお約束ｗ）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3643825658924122108?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3643825658924122108/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/07/blog-post_30.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3643825658924122108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3643825658924122108'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/07/blog-post_30.html' title='カナダネタ：ホテル予約編'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8146743473011588611</id><published>2010-07-28T15:34:00.003+09:00</published><updated>2010-07-28T15:35:43.258+09:00</updated><title type='text'>就業規則の届出をしていない場合の旅費規程について</title><content type='html'>弊社は現在常時10人以上の労働者を使用していないため、労働基準監督署に就業規則を届けていません。そのため、旅費規程などについても届出をしていません。その場合、旅費規程により経費として扱われることが妥当な場合でも、所得税が課税される可能性がありうるのではという疑問があります。&lt;br /&gt;&lt;br /&gt;ということで、労働基準監督署に聞いてみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;労働基準監督署曰く&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;旅費規定等を単独で届け出ることはできず、就業規則を含めて提出する必要がある。&lt;/li&gt;&lt;li&gt;税金については関知しない。&lt;/li&gt;&lt;li&gt;今回の件では特に届けでの必要はない。&lt;/li&gt;&lt;/ul&gt;とのこと。今度は税務署に聞いてみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;税務署曰く&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;労働基準監督署に届けるかどうかは関係ない。&lt;/li&gt;&lt;li&gt;調査が必要な場合などに、該当する書類を見せられるようにしておけばよい。&lt;/li&gt;&lt;li&gt;書類の内容の妥当性は、地域性その他を含めた全体的な視点で判断される。&lt;/li&gt;&lt;/ul&gt;とのことでした。&lt;br /&gt;&lt;br /&gt;妥当な規則を事前に用意していれば、特に問題なさそうです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8146743473011588611?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8146743473011588611/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/07/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8146743473011588611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8146743473011588611'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/07/blog-post.html' title='就業規則の届出をしていない場合の旅費規程について'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2052121990938678557</id><published>2010-06-07T12:59:00.002+09:00</published><updated>2010-06-07T13:01:50.448+09:00</updated><title type='text'>Utils.as</title><content type='html'>&lt;pre class="prettyprint"&gt;package {&lt;br /&gt;    import flash.filesystem.File;&lt;br /&gt;    import flash.filesystem.FileMode;&lt;br /&gt;    import flash.filesystem.FileStream;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * とりあえず、静的な便利メソッドを入れ込んでおくクラス。&lt;br /&gt;     * &lt;br /&gt;     * TODO: Air 以外の開発をする際に、Air 専用とそれ以外を分離しましょう。&lt;br /&gt;     * &lt;br /&gt;     * 方針&lt;br /&gt;     *         ・ActionScriptはオーバーロードができないので、メソッド名に引数情報もいれる。&lt;br /&gt;     *         ・見かけの簡潔さを求めず、分かりやすさを求める。初めて見る人でもシグニチャだけで機能を確実に理解できることを目指す。&lt;br /&gt;     *         ・管理しきれなくなって『具体的に困る』ことになったら別ライブラリへの分割を考える。&lt;br /&gt;     */&lt;br /&gt;    public class Utils {&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定された XML ファイルを読み込み XML オブジェクトを返します。&lt;br /&gt;         */&lt;br /&gt;        public static function readXmlFromFile(xmlFile:File):XML {&lt;br /&gt;            return new XML(readUTFBytesFromFile(xmlFile));&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定されたファイルを読み込み UTFBytes を返します。&lt;br /&gt;         */&lt;br /&gt;        public static function readUTFBytesFromFile(utfFile:File):String {&lt;br /&gt;            var fileStream:FileStream = new FileStream();&lt;br /&gt;            fileStream.open(utfFile, FileMode.READ);&lt;br /&gt;            var utfBytes:String = fileStream.readUTFBytes(utfFile.size);&lt;br /&gt;            fileStream.close();&lt;br /&gt;            return utfBytes;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定されたファイルに対して指定された XML を書き込みます。&lt;br /&gt;         */&lt;br /&gt;        public static function writeXmlToFile(xml:XML, file:File):void {&lt;br /&gt;            writeUTFBytesToFile(xml.toXMLString(), file);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定されたファイルに対して UTFBytes を書き込みます。&lt;br /&gt;         */&lt;br /&gt;        public static function writeUTFBytesToFile(utfBytes:String, file:File):void {&lt;br /&gt;            var fileStream:FileStream = new FileStream();&lt;br /&gt;            fileStream.open(file, FileMode.WRITE);&lt;br /&gt;            fileStream.writeUTFBytes(utfBytes);&lt;br /&gt;            fileStream.close();&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        /**&lt;br /&gt;         * 指定されたファイルをファイルシステム中に作成します。既に指定されたファイルが存在する場合には何もしません。&lt;br /&gt;         */&lt;br /&gt;        public static function createFile(file:File):void {&lt;br /&gt;            if (!file.exists) {&lt;br /&gt;                var fileStream:FileStream = new FileStream();&lt;br /&gt;                fileStream.open(file, FileMode.WRITE);&lt;br /&gt;                fileStream.close();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2052121990938678557?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2052121990938678557/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/06/utilsas.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2052121990938678557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2052121990938678557'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/06/utilsas.html' title='Utils.as'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7914775322946210340</id><published>2010-06-02T20:33:00.000+09:00</published><updated>2010-06-02T20:33:04.191+09:00</updated><title type='text'>FlashのUI系コンポーネント調査</title><content type='html'>FlashのUI系のコンポーネントについて全く知識がないので、少し調査してみました。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;クラス階層&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Object.html"&gt;Object&lt;/a&gt;&lt;br /&gt;・言うまでもなく、あらゆるクラスのベースとなるクラス。特にUIであるかどうかとは無関係。&lt;br /&gt;・パッケージはトップレベル。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/EventDispatcher.html"&gt;flash.events.EventDispatcher&lt;/a&gt;&lt;br /&gt;・&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/IEventDispatcher.html"&gt;flash.events.IEventDispatcher&lt;/a&gt; の実装クラス。&lt;br /&gt;・イベントを扱うための汎用的な機能を持つクラス。リスナーの追加削除とかイベントの送信とか。&lt;br /&gt;・特にUIであるかどうかとは無関係。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html"&gt;flash.display.DisplayObject&lt;/a&gt;&lt;br /&gt;・display list に配置されるすべてのオブジェクトのベースクラス。&lt;br /&gt;・x,y,zとかalphaとかwidthとかvisibleとかマウス位置とか、表示されるものとしての基本機能を持っている。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html"&gt;flash.display.InteractiveObject&lt;/a&gt;&lt;br /&gt;・表示されるオブジェクトでマウスやキーボードやその他の入力デバイスを扱うものすべての抽象クラス。&lt;br /&gt;・このクラスはnewできないし、上記までのクラスもUIを作成するうえでプログラマが明示的に new することはなさそうです。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html"&gt;flash.display.DisplayObjectContainer&lt;/a&gt;&lt;br /&gt;・display object の入れ物クラス。&lt;br /&gt;・z 軸上に複数の display object を child として配置できる。&lt;br /&gt;・このサブクラスには Loader, Sprite, Stage, TextLine があります。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Loader.html"&gt;flash.display.Loader&lt;/a&gt;&lt;br /&gt;・java の ClassLoader のようなものを想像していると DisplayObjectContainer のサブクラスということに違和感を感じるが、実際は swf ファイルおよび画像ファイルをロードして表示するものなので、表示オブジェクトのローダーと言える。&lt;br /&gt;・flex 用のサブクラスとして mx.core.FlexLoader があり、toString() メソッドが DisplayObjects の階層を表すようになっている。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/engine/TextLine.html"&gt;flash.text.engine.TextLine&lt;/a&gt;&lt;br /&gt;・display text 上に文字列を表示するためのオブジェクト。&lt;br /&gt;・final クラスなので継承できないし、ユーザが直接 new することもできない。&lt;br /&gt;・flash.text.engine 系のパッケージと関わらない限りは必要なさそう。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Stage.html"&gt;flash.display.Stage&lt;/a&gt;&lt;br /&gt;・ブラウザ内なら flash の表示領域が Stage で、Airなら各 NativeWindow が Stage を持つ。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Sprite.html"&gt;flash.display.Sprite&lt;/a&gt;&lt;br /&gt;・UI 系の一般的なベースクラスで、MovieClip からtimelineを抜いたようなもの。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7914775322946210340?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7914775322946210340/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/06/flashui.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7914775322946210340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7914775322946210340'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/06/flashui.html' title='FlashのUI系コンポーネント調査'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8919165769661531872</id><published>2010-05-23T09:23:00.002+09:00</published><updated>2010-05-23T11:01:37.278+09:00</updated><title type='text'>開発環境メモ</title><content type='html'>&lt;span style="font-size: large;"&gt;WindowsXP環境開発環境メモ&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;GAE, git, svn, maven を前提とした環境。&lt;br /&gt;今のところ、GAE系やGITの環境の試行錯誤中。&lt;br /&gt;&lt;br /&gt;TODO: とりあえずメモなので、あとでちゃんと書きましょう。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;7zip&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.7-zip.org/"&gt;http://www.7-zip.org/&lt;/a&gt;&amp;nbsp;からダウンロードしてすべてデフォルトでインストール。&lt;/li&gt;&lt;li&gt;以降、アーカイブの展開は7zipを使います。(Windows付属のはどうもバギーなので)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;ブラウザのインストール&lt;br /&gt;各種ブラウザの動作確認を行うため、複数のブラウザをインストールする。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Firefoxのインストール&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://mozilla.jp/firefox/"&gt;http://mozilla.jp/firefox/&lt;/a&gt; から最新版をダウンロードしてすべてデフォルト設定でインストールする。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Google Chrome のインストール&lt;/li&gt;&lt;ul&gt;&lt;li&gt; &lt;a href="http://www.google.co.jp/chrome/"&gt;http://www.google.co.jp/chrome/&lt;/a&gt; から最新版をダウンロードしてすべてデフォルト設定でインストールする。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;Java&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://java.sun.com/"&gt;http://java.sun.com/&lt;/a&gt; から Java SE の最新版をダウンロードして、すべてデフォルト設定でインストールする。&lt;/li&gt;&lt;li&gt;環境変数 JAVA_HOME を適切に設定する。（C:\Program Files\Java\jdk1.6.0_20 等）&lt;/li&gt;&lt;li&gt;環境変数 PATH に %JAVA_HOME%\bin を設定する。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;maven&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://maven.apache.org/"&gt;http://maven.apache.org/&lt;/a&gt;&amp;nbsp;から安定版の最新のバイナリをダウンロード。(ex. apache-maven-2.2.1-bin.zip)&lt;/li&gt;&lt;li&gt;C:\Program Files 直下にコピー。(ex. C:\Program Files\apache-maven-2.2.1)&lt;/li&gt;&lt;li&gt;環境変数 MAVEN_HOME を設定。&lt;/li&gt;&lt;li&gt;環境変数 Path に %MAVEN_HOME%\bin を追加。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Eclipse&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/downloads/"&gt;http://www.eclipse.org/downloads/&lt;/a&gt; から Eclipse IDE for Java EE Developers の galileo の最新版をダウンロード。&lt;/li&gt;&lt;li&gt;C:\Program Files\eclipse として展開する。&lt;/li&gt;&lt;li&gt;文字コードの設定&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;Window -&amp;gt; Preferences -&amp;gt; General -&amp;gt; Workspace -&amp;gt; Text file encoding を utf-8 に設定。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;xmlのwidthを999、インデントをスペース2つに変更する。&lt;/li&gt;&lt;li&gt;eclipseにjdkのソースをアタッチ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;Window -&amp;gt; Preferences... -&amp;gt; Java -&amp;gt; Installed JREs に移動。&lt;/li&gt;&lt;li&gt;jre を選択して、Edit... ボタンを押下。&lt;/li&gt;&lt;li&gt;C:\tmp\devenv\jdk\jre\lib\rt.jar を選択。&lt;/li&gt;&lt;li&gt;Source Attachement... ボタンを押下。&lt;/li&gt;&lt;li&gt;C:/Program Files/Java/jdk1.6.0_20/src.zip をアタッチ。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;eclipseにJavaDocをアタッチ&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Sunのサイトからドキュメントをダウンロードして、src.zipと同じフォルダに置く。&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;Window -&amp;gt; Preferences... -&amp;gt; Java -&amp;gt; Installed JREs に移動。&lt;/li&gt;&lt;li&gt;jre を選択して、Edit... ボタンを押&lt;/li&gt;&lt;li&gt;C:\tmp\devenv\eclipse\jre\lib\rt.jar を選択。&lt;/li&gt;&lt;li&gt;JavaDoc Location... ボタンを押下。&lt;/li&gt;&lt;li&gt;Javadoc in archive と Workspace file を選択。&lt;/li&gt;&lt;li&gt;Archive path を設定先ほどダウンロードしたドキュメントのzipに設定。&lt;/li&gt;&lt;li&gt;Path within archive を設定。（ex. docs/api）&lt;/li&gt;&lt;li&gt;ソース上の対象を選択してShift+F2キーを押せば、システム設定のブラウザ経由でJavaDocが起動します。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;m2eclipseの設定&lt;/li&gt;&lt;ul&gt;&lt;li&gt;アップデートサイト http://m2eclipse.sonatype.org/sites/m2e からインストールする。&lt;/li&gt;&lt;li&gt;[Window] -&amp;gt; [Preferences...] -&amp;gt; [Maven] にて、以下のオプションをチェック。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Download Artifact Sources&lt;/li&gt;&lt;li&gt;Download Artifact JavaDoc&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;デフォルトのmavenが3.0系のSNAPSHOT版の場合は、[Window] -&amp;gt; [Preferences...] -&amp;gt; [Maven]&amp;nbsp;&amp;nbsp;-&amp;gt; [Installations] -&amp;gt; [Add] から Program Files 以下にインストールした maven を指定する。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Google 関連プラグインの設定&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Georgia, serif; font-size: 13px; line-height: 20px;"&gt;&lt;a href="http://dl.google.com/eclipse/plugin/3.5" style="color: #5588aa; text-decoration: none;"&gt;http://dl.google.com/eclipse/plugin/3.5&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Georgia, serif; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px; line-height: 20px;"&gt;Google plugin と Google App Engine を選択してインストール。&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;subclipse プラグインの設定&lt;/li&gt;&lt;ul&gt;&lt;li&gt;アップデートサイト&amp;nbsp;&lt;a href="http://subclipse.tigris.org/update_1.6.x"&gt;http://subclipse.tigris.org/update_1.6.x&lt;/a&gt; からインストールする。その際、オプショナルコンポーネントはすべて無視する。&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;SVN インタフェースを SVNKit (Pure Java) に設定する。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;[Window] -&amp;gt; [Preferences...] -&amp;gt; [Team] -&amp;gt; [SVN] -&amp;gt; [SVNインタフェース] -&amp;gt; [SVNKit (Pure Java)]&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;EGit プラグインの設定。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;アップデートサイト &lt;a href="http://download.eclipse.org/egit/updates"&gt;http://download.eclipse.org/egit/updates&lt;/a&gt;&amp;nbsp;からインストールする。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;ul&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8919165769661531872?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8919165769661531872/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/blog-post.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8919165769661531872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8919165769661531872'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/blog-post.html' title='開発環境メモ'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5964618209977967008</id><published>2010-05-11T02:07:00.006+09:00</published><updated>2010-05-11T06:15:46.480+09:00</updated><title type='text'>Flex のコンポーネント遅延ロードとデータバインディングとモデリングに関する考察</title><content type='html'>Flexではコンポーネントの遅延ローディングがデフォルトで行われるようになっています。そのため、mxml ファイル内で定義されたコンポーネントに対して同一の mxml ファイル内の ActionScript からアクセスしても、null が返る可能性があります。&lt;br /&gt;&lt;br /&gt;そのような場合、内部コンポーネントを定義するXML要素の属性として、ActionScript 内の変数をバインディングするというワークアラウンドで乗り切ることができます。しかし、データバインディングをする場合、モデルが既にあったとしても、バインディング用の変数をわざわざ用意する必要があります。モデルの中で配列で100要素バインディングするとしたら、100種類の変数を用意する必要があります。&lt;br /&gt;&lt;br /&gt;これも、ArrayCollection 型を使用することで解決できますが、既に Vector でデータを持っているモデルがあるとしたら、毎回移し変えなければなりません。&lt;br /&gt;&lt;br /&gt;このように、ワークアラウンドで乗り切ることもできますが、あまり建設的ではないように思えます。まだまだ落とし穴があるように思えますし、、、。&lt;br /&gt;&lt;br /&gt;ということで、今後の作業効率や成果物の品質にも大きく影響すると考えられるので、この機会に確認しておこうと思います。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;例１：ある state で生成された情報を、これから初めて遷移される state に表示する場合。&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;ソース&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex1"&gt;Ex1.mxml&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;思惑&lt;br /&gt;&lt;ul&gt;&lt;li&gt;State 1 が初期状態。&lt;/li&gt;&lt;li&gt;State 1 上の入力フォームから結果表示用ラベルに A と B の値を入力し、add ボタンを押下する。&lt;/li&gt;&lt;li&gt;State 2 に遷移し、A + B の結果が表示される。&lt;/li&gt;&lt;/ul&gt;結果&lt;br /&gt;&lt;ul&gt;&lt;li&gt;State 2 で表示される結果表示用ラベルの値が null となり、エラーが発生。&lt;/li&gt;&lt;/ul&gt;考察&lt;br /&gt;&lt;ul&gt;&lt;li&gt;creationPolicy を all にすることにより遅延ロードを抑制できないか？&lt;/li&gt;&lt;li&gt;ドキュメントによると、単一ビューコンテナでは、auto でも all でも同じ動作となり、『デフォルトでは、アプリケーションが最初に起動されたときに単一ビューコンテナのすべての子が生成されます。』となるらしい。生成されてるのに null なのはなぜ？ (´・ω・`)&lt;/li&gt;&lt;li&gt;State が絡む場合はダメらしい。結局、State の遷移を先に行うしかないらしい。&lt;/li&gt;&lt;/ul&gt;解決法&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ある State に含まれるコンポーネントへのアクセスは、その State に遷移してから行う。&lt;/li&gt;&lt;/ul&gt;解決後のソース&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex1_1"&gt;Ex1_1.mxml&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;例２：複雑なモデル内部のデータを参照する場合。&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;バインディング版&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex2"&gt;Ex2.mxml&lt;/a&gt;&lt;/li&gt;&lt;li&gt;特に問題なく動作する。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;例３：配列へバインディングしようとして失敗する版&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex2_1"&gt;Ex2_1.mxml&lt;/a&gt;&lt;/li&gt;&lt;li&gt;最初の１回目はうまく行くが、２回目以降も最初の結果が出続ける。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;例４：ArrayCollection を用いて対応する版&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex2_2"&gt;Ex2_2.mxml&lt;/a&gt;&lt;/li&gt;&lt;li&gt;問題なく動作するが、バインディングのために設計を崩すことになった。バインディングするよりも、特定のタイミングでデータをリロードしてくれるような設計の方がありがたいのだが。例えば状態遷移のタイミングとか。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;例５：ボタンクリックのタイミングでデータを格納する版&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex2_3"&gt;Ex2_3.mxml&lt;/a&gt;&lt;/li&gt;&lt;li&gt;サブコンポーネントに対する text の指定を、親コンポーネント側で決定することが自然な設計であれば、無理にバインディングする必要はない。そのため、クリックのハンドラでラベルの表示を行っている。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;例６：Stateに入るタイミングでデータを格納する版&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソース：&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008#Ex2_4"&gt;Ex2_4.mxml&lt;/a&gt;&lt;/li&gt;&lt;li&gt;サブコンポーネントに対する text の指定を、親コンポーネント側で決定することが自然な設計であれば、無理にバインディングする必要はない。状態遷移をする箇所が一箇所であればその場所にラベルにデータを書き込む処理を埋め込めば良いのだが、ソースの様々な箇所から状態遷移が発生する場合には同様の処理を複数回記述することになる。その際、状態遷移をトリガーにした方がシンプルになる場合は、State に入るイベントを用いた方がよい。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;付録：ソース&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex1"&gt;&lt;/a&gt;&lt;br /&gt;Ex1.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    var a:String = aNs.value.toString();&lt;br /&gt;    var b:String = bNs.value.toString();&lt;br /&gt;    var result:String = (aNs.value + bNs.value).toString();&lt;br /&gt;    Alert.show("resultLabel = " + resultLabel); // ここで、resultLabel が null になる。&lt;br /&gt;    resultLabel.text = a + " + " + b + " = " + result;&lt;br /&gt;    currentState = "State2";&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="A"&amp;gt;&lt;br /&gt;   &amp;lt;!--- A の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="aNs"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="B"&amp;gt;&lt;br /&gt;   &amp;lt;!--- B の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="bNs"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- A + B = (A+Bの結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex1_1"&gt;&lt;/a&gt;&lt;br /&gt;Ex1_1.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    var a:String = aNs.value.toString();&lt;br /&gt;    var b:String = bNs.value.toString();&lt;br /&gt;    var result:String = (aNs.value + bNs.value).toString();&lt;br /&gt;    currentState = "State2";&lt;br /&gt;    Alert.show("resultLabel = " + resultLabel); // ここで、resultLabel が null ではなく、きちんと表示される。&lt;br /&gt;    resultLabel.text = a + " + " + b + " = " + result;&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="A"&amp;gt;&lt;br /&gt;   &amp;lt;!--- A の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="aNs"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="B"&amp;gt;&lt;br /&gt;   &amp;lt;!--- B の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="bNs"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- A + B = (A+Bの結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex2"&gt;&lt;/a&gt;&lt;br /&gt;Ex2.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State2";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &amp;lt;!--- State2 から State1 に戻るボタン --&amp;gt;&lt;br /&gt;   private function backButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State1";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 1"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値1 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v1Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 2"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値2 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v2Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 3"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値3 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v3Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- v1 + v2 + v3 = (v1+v2+v3の結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2" text="{v1Ns.value} + {v2Ns.value} + {v3Ns.value} = {v1Ns.value + v2Ns.value + v3Ns.value}"/&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State2" label="back" id="backButton" click="backButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex2_1"&gt;&lt;/a&gt;&lt;br /&gt;Ex2_1.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- 値を保持する Vector --&amp;gt;&lt;br /&gt;   private var values:Vector.&amp;lt;Number&amp;gt; = new Vector.&amp;lt;Number&amp;gt;();&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    // コンポーネントの値を values に格納。&lt;br /&gt;    values.push(v1Ns.value);&lt;br /&gt;    values.push(v2Ns.value);&lt;br /&gt;    values.push(v3Ns.value);&lt;br /&gt;    &lt;br /&gt;    currentState = "State2";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &amp;lt;!--- State2 から State1 に戻るボタン --&amp;gt;&lt;br /&gt;   private function backButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State1";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 1"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値1 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v1Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 2"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値2 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v2Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 3"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値3 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v3Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- v1 + v2 + v3 = (v1+v2+v3の結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2" text="{values[0]} + {values[1]} + {values[2]} = {values[0] + values[1] + values[2]}"/&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State2" label="back" id="backButton" click="backButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex2_2"&gt;&lt;/a&gt;&lt;br /&gt;Ex2_2.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.collections.ArrayCollection;&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &lt;br /&gt;   [Bindable]&lt;br /&gt;   /**&lt;br /&gt;    * 値を保持する ArrayCollection&lt;br /&gt;    */&lt;br /&gt;   private var values:ArrayCollection = new ArrayCollection(new Array(3));&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド&lt;br /&gt;    */&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    // コンポーネントの値を values に格納。&lt;br /&gt;    values.setItemAt(v1Ns.value, 0);&lt;br /&gt;    values.setItemAt(v2Ns.value, 1);&lt;br /&gt;    values.setItemAt(v3Ns.value, 2);&lt;br /&gt;    &lt;br /&gt;    currentState = "State2";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &amp;lt;!--- State2 から State1 に戻るボタン --&amp;gt;&lt;br /&gt;   private function backButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State1";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 1"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値1 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v1Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 2"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値2 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v2Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 3"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値3 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v3Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- v1 + v2 + v3 = (v1+v2+v3の結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2" text="{values.getItemAt(0)} + {values.getItemAt(1)} + {values.getItemAt(2)} = {values.getItemAt(0) + values.getItemAt(1) + values.getItemAt(2)}"/&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State2" label="back" id="backButton" click="backButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex2_3"&gt;&lt;/a&gt;&lt;br /&gt;Ex2_3.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- 値を保持する Vector --&amp;gt;&lt;br /&gt;   private var values:Vector.&amp;lt;Number&amp;gt; = new Vector.&amp;lt;Number&amp;gt;();&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    // コンポーネントの値を values に格納。&lt;br /&gt;    if (values.length == 0) {&lt;br /&gt;     values.push(v1Ns.value);&lt;br /&gt;     values.push(v2Ns.value);&lt;br /&gt;     values.push(v3Ns.value);&lt;br /&gt;    } else {&lt;br /&gt;     values[0] = v1Ns.value;&lt;br /&gt;     values[1] = v2Ns.value;&lt;br /&gt;     values[2] = v3Ns.value;&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    currentState = "State2";&lt;br /&gt;    &lt;br /&gt;    // ラベルの値を直接指定する。&lt;br /&gt;    resultLabel.text = values[0].toString() + ' + ' + values[1].toString() + ' + ' + values[2].toString() + ' = ' + (values[0] + values[1] + values[2]);&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &amp;lt;!--- State2 から State1 に戻るボタン --&amp;gt;&lt;br /&gt;   private function backButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State1";&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 1"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値1 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v1Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 2"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値2 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v2Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 3"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値3 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v3Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- v1 + v2 + v3 = (v1+v2+v3の結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2"/&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State2" label="back" id="backButton" click="backButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=3144177333818784642&amp;amp;postID=5964618209977967008" name="Ex2_4"&gt;&lt;/a&gt;&lt;br /&gt;Ex2_4.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- 値を保持する Vector --&amp;gt;&lt;br /&gt;   private var values:Vector.&amp;lt;Number&amp;gt; = new Vector.&amp;lt;Number&amp;gt;();&lt;br /&gt;   &lt;br /&gt;   &amp;lt;!--- A + B の計算をして resultLabel に値を設定し、State2 に遷移するメソッド --&amp;gt;&lt;br /&gt;   private function addButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    // コンポーネントの値を values に格納。&lt;br /&gt;    if (values.length == 0) {&lt;br /&gt;     values.push(v1Ns.value);&lt;br /&gt;     values.push(v2Ns.value);&lt;br /&gt;     values.push(v3Ns.value);&lt;br /&gt;    } else {&lt;br /&gt;     values[0] = v1Ns.value;&lt;br /&gt;     values[1] = v2Ns.value;&lt;br /&gt;     values[2] = v3Ns.value;&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    currentState = "State2";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &amp;lt;!--- State2 から State1 に戻るボタン --&amp;gt;&lt;br /&gt;   private function backButton_clickHandler(event:MouseEvent):void {&lt;br /&gt;    currentState = "State1";&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- state を用いて画面遷移を模倣 --&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;!-- A と B の値を入力する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State1"/&amp;gt;&lt;br /&gt;  &amp;lt;!-- A + B の結果を表示する画面 --&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="State2" enterState="resultLabel.text = values[0].toString() + ' + ' + values[1].toString() + ' + ' + values[2].toString() + ' = ' + (values[0] + values[1] + values[2])"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State1用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="State1"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 1"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値1 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v1Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 2"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値2 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v2Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="Value 3"&amp;gt;&lt;br /&gt;   &amp;lt;!--- 値3 の値入力用 NumericStepper --&amp;gt;&lt;br /&gt;   &amp;lt;s:NumericStepper id="v3Ns"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State1" label="add" id="addButton" click="addButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- State2用コンポーネント群 --&amp;gt;&lt;br /&gt; &amp;lt;!--- v1 + v2 + v3 = (v1+v2+v3の結果) という文字列を表示するためのラベル --&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="resultLabel" includeIn="State2"/&amp;gt;&lt;br /&gt; &amp;lt;s:Button includeIn="State2" label="back" id="backButton" click="backButton_clickHandler(event)"/&amp;gt;&lt;br /&gt; &lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5964618209977967008?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5964618209977967008/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/flex.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5964618209977967008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5964618209977967008'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/flex.html' title='Flex のコンポーネント遅延ロードとデータバインディングとモデリングに関する考察'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7403799532388916966</id><published>2010-05-06T19:23:00.004+09:00</published><updated>2010-05-08T04:02:16.470+09:00</updated><title type='text'>flex で creationComplete 時に stage == null になる問題。</title><content type='html'>&lt;a href="http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Stage.html"&gt;ドキュメント&lt;/a&gt;によると、少なくとも activate されている間は stage が生きているらしいです。&lt;br /&gt;&lt;br /&gt;そのため、Event.ACTIVATE と Event.RESIZE イベント内なら確実に stage を扱えそうです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7403799532388916966?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7403799532388916966/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/flex-creationcomplete-stage-null.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7403799532388916966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7403799532388916966'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/flex-creationcomplete-stage-null.html' title='flex で creationComplete 時に stage == null になる問題。'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3494002554597471352</id><published>2010-05-02T19:37:00.001+09:00</published><updated>2010-05-10T05:24:43.952+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gimp'/><title type='text'>GIMPを使い始めてみようと思ったり思わなかったり。</title><content type='html'>以下、GIMPを使おうと思い立ってから以降のメモ書き。&lt;br /&gt;&lt;br /&gt;今は何でも屋としてサイト開発をしているので、グラフィック系のチームに画像やレイアウトの注文を任せるようなことができない今日この頃。&lt;br /&gt;&lt;br /&gt;グラフィックもやらにゃいかんだろうと思い、どうしたものかと思案中。&lt;br /&gt;&lt;br /&gt;PhotoShop をいきなり購入しても、3日で飽きたとかしゃれにならんし。&lt;br /&gt;&lt;br /&gt;ということで、GIMPに挑戦してみる。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;公式ページ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.gimp.org/"&gt;http://www.gimp.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Windows版ダウンロードページ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.gimp.org/windows/"&gt;http://www.gimp.org/windows/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ダウンロード＆インストール&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;アプリとマニュアルの両方をダウンロードして実行。本体は国際化されているので、何語版というのはありません。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3494002554597471352?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3494002554597471352/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/gimp.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3494002554597471352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3494002554597471352'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/05/gimp.html' title='GIMPを使い始めてみようと思ったり思わなかったり。'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5697439513211940013</id><published>2010-04-22T11:52:00.003+09:00</published><updated>2010-04-22T11:58:40.249+09:00</updated><title type='text'>作業メモ：BlazeDS + Flex 環境の Enum ルール</title><content type='html'>今回は、BlazeDS + Flex 環境で Enum をどのように扱うかについて考察してみます。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;基本事項&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;基本的な設定やその他基本事項については、以下に準じます。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4_17.html"&gt;作業ログ：GAE/J + BlazeDS 4 環境について考えてみた。&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/login-sessionduplicate.html"&gt;作業ログ：login機能使用時の SessionDuplicate 問題&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html"&gt;作業メモ：FlexのRemotingでActionScriptからjavaに型をマッピングする方法&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaactionscript.html"&gt;作業メモ：FlexのRemotingでjavaからにActionScript型をマッピングする方法&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;ActionScript 側の enum 名格納変数について&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ActionScript 側の enum 名格納変数を name とします。AMFで通信される情報も java の Enum#name() に準じたものにします。そのため、以下のような独自のEnumProxyを定義します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.flex.messaging.io;&lt;br /&gt;&lt;br /&gt;import java.util.Collections;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import flex.messaging.io.AbstractProxy;&lt;br /&gt;import flex.messaging.io.BeanProxy;&lt;br /&gt;&lt;br /&gt;public class EnumProxy extends BeanProxy {&lt;br /&gt;&lt;br /&gt;    private static final String ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME = "name";&lt;br /&gt;    private static final List&amp;lt;String&amp;gt; propertyNames = Collections.singletonList(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME);&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    public Object createInstance(String className) {&lt;br /&gt;        return new EnumStub((Class&amp;lt;Enum&amp;gt;) AbstractProxy.getClassFromClassName(className));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Object getValue(Object instance, String propertyName) {&lt;br /&gt;        if (propertyName.equals(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME)) {&lt;br /&gt;            return Enum.class.cast(instance).name();&lt;br /&gt;        } else {&lt;br /&gt;            throw new IllegalArgumentException("No property named: " + propertyName + " on enum type");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setValue(Object instance, String propertyName, Object value) {&lt;br /&gt;        if (propertyName.equals(ACTION_SCRIPT_ENUM_NAME_PROPERTY_NAME)) {&lt;br /&gt;            EnumStub.class.cast(instance).value = String.class.cast(value);&lt;br /&gt;        } else {&lt;br /&gt;            throw new IllegalArgumentException("no EnumStub property: " + propertyName);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    public Object instanceComplete(Object instance) {&lt;br /&gt;        EnumStub es = EnumStub.class.cast(instance);&lt;br /&gt;        return Enum.valueOf((Class) es.cl, es.value);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    public List getPropertyNames(Object instance) {&lt;br /&gt;        if (!(instance instanceof Enum)) {&lt;br /&gt;            throw new IllegalArgumentException("getPropertyNames called with non Enum object");&lt;br /&gt;        } else {&lt;br /&gt;            return propertyNames;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private class EnumStub {&lt;br /&gt;        private Class&amp;lt;?&amp;gt; cl;&lt;br /&gt;        private String value;&lt;br /&gt;        private EnumStub(Class&amp;lt;?&amp;gt; c) {&lt;br /&gt;            cl = c;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;同時に HttpFlexSession の static ブロックで以下のように定義し、あらゆる Enum 型に対して EnumProxy が適用されるようにします。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// patch for enum serialization&lt;br /&gt;  static {&lt;br /&gt;      PropertyProxyRegistry.getRegistry().register(Enum.class, new EnumProxy());&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;ActionScript 側の enum ルール&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ActionScript 側の enum は、以下のような形式で作成します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// Sample enum class.&lt;br /&gt;package com.objectfanatics.englishfanatics.dataobject {&lt;br /&gt;    import com.objectfanatics.flex.EnumBase;&lt;br /&gt;    &lt;br /&gt;    // fqcn of java counterpart enum class&lt;br /&gt;    [RemoteClass(alias="com.objectfanatics.sample.SampleEnum")]&lt;br /&gt;    &lt;br /&gt;    // class name should be the same as the name of the java counterpart enum class.&lt;br /&gt;    public class SampleEnum extends EnumBase {&lt;br /&gt;        &lt;br /&gt;        // enums&lt;br /&gt;        //  - const name and the value of the first parameter of the constructor should be the same.&lt;br /&gt;        public static const KUMA_SAN:SampleEnum = new SampleEnum("KUMA_SAN", "くまさん");&lt;br /&gt;        public static const TANUKI_SAN:SampleEnum = new SampleEnum("TANUKI_SAN", "たぬきさん");&lt;br /&gt;        &lt;br /&gt;        // constructor&lt;br /&gt;        //  - default parameter values are required for deserialized enums.&lt;br /&gt;        //  - this must be invoked only for enum constant creation in this class and deserialized enum creation.&lt;br /&gt;        public function SampleEnum(name:String = null, string:String = null) {&lt;br /&gt;            super(name, string);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // returns all enum constants in this class.&lt;br /&gt;        //  - this method is workaround for ActionScript3.0's limitation. &lt;br /&gt;        //    static methods are not inherited and cannot be overridden in ActionScript 3.0.&lt;br /&gt;        public static function values():Array {&lt;br /&gt;            return superValues();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;すべての enum は下記のベースクラスを継承します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.flex {&lt;br /&gt;    import flash.utils.getDefinitionByName;&lt;br /&gt;    import flash.utils.getQualifiedClassName;&lt;br /&gt;    &lt;br /&gt;    /**&lt;br /&gt;     * Base class of enum object.&lt;br /&gt;     */&lt;br /&gt;    public class EnumBase {&lt;br /&gt;        // key = enum class name, value = enum array.&lt;br /&gt;        private static const valuesMap:Object = new Object();&lt;br /&gt;        &lt;br /&gt;        // enum class name&lt;br /&gt;        private var enumClassName:String;&lt;br /&gt;        &lt;br /&gt;        // enum name&lt;br /&gt;        public var name:String;&lt;br /&gt;        &lt;br /&gt;        // string for presentation&lt;br /&gt;        protected var string:String;&lt;br /&gt;        &lt;br /&gt;        public function EnumBase(name:String = null, string:String = null) {&lt;br /&gt;            this.name = name;&lt;br /&gt;            this.string = string;&lt;br /&gt;            enumClassName = getQualifiedClassName(this);&lt;br /&gt;            if (string != null) {&lt;br /&gt;                // for normal enum&lt;br /&gt;                var values:Array = valuesMap[enumClassName];&lt;br /&gt;                if (values == null) values = new Array();&lt;br /&gt;                valuesMap[enumClassName] = values;&lt;br /&gt;                values.push(this);&lt;br /&gt;            } else {&lt;br /&gt;                // for deserialized enum&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // This method name is weird because of ActionScript 3.0's limitation.&lt;br /&gt;        //   - Static methods are not inherited and cannot be overridden in ActionScript 3.0.&lt;br /&gt;        public static function superValues():Array {&lt;br /&gt;            // TODO: check.&lt;br /&gt;            var blocks:Array = new Error().getStackTrace().split("at ");&lt;br /&gt;            var block:String = blocks[2];&lt;br /&gt;            var startIndex:int = block.indexOf("at ");// start of first line&lt;br /&gt;            var endIndex:int = block.indexOf("$");    // end of class name&lt;br /&gt;            var enumClassName:String = block.substring(startIndex + 1, endIndex);&lt;br /&gt;            return valuesMap[enumClassName];&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public function toString():String {&lt;br /&gt;            if (string == null) {&lt;br /&gt;                var enumClass:Class = getDefinitionByName(enumClassName) as Class;&lt;br /&gt;                this.string = enumClass[name].string;&lt;br /&gt;            }&lt;br /&gt;            return string;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        //use equality instead of identity.&lt;br /&gt;        public function equals(other:EnumBase):Boolean {&lt;br /&gt;            return this.name == other.name;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;java 側の enum ルール&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Java 側の enum は、ActionScript 側の name プロパティと Java 側の Enum#name() の値が対応していれば、どのような形でもかまいません。&lt;br /&gt;&lt;br /&gt;以下例。&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.sample;&lt;br /&gt;&lt;br /&gt;public enum SampleEnum {&lt;br /&gt;    KUMA_SAN, TANUKI_SAN;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;(´・ω・`) まだまともにに使ってないから、落とし穴がいっぱいありそうな気がする今日この頃。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5697439513211940013?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5697439513211940013/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-flex-enum.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5697439513211940013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5697439513211940013'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-flex-enum.html' title='作業メモ：BlazeDS + Flex 環境の Enum ルール'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2661083050049703150</id><published>2010-04-21T16:23:00.006+09:00</published><updated>2010-04-22T03:31:29.200+09:00</updated><title type='text'>作業メモ：FlexのRemotingでjavaからにActionScript型をマッピングする方法</title><content type='html'>前回は、Flex の Remoting で ActionScript から java に型をマッピングする方法について、実際に動作を確認しながら考えてみました。&lt;br /&gt;&lt;br /&gt;今回は、その逆の方向ということで、java から ActionScript に型をマッピングする方法について、実際に動作を確認しながら考えてみます。&lt;br /&gt;&lt;br /&gt;基本的な事項は&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html"&gt;作業メモ：FlexのRemotingでActionScriptからjavaに型をマッピングする方法&lt;/a&gt;参照のこと。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Private Fields in Java to Public Fields in ActionScript&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;基本的に動くようです。&lt;br /&gt;&lt;br /&gt;以下、JavaBeans規約を勘違いしてやらかした例。(´・ω・`)&lt;br /&gt;&lt;br /&gt;前回 services-config.xml ファイルのチャネルの serialization の設定として include-read-only オプションを追加したのですが、うまく動作しないようです。&lt;br /&gt;&lt;br /&gt;シリアライズ対象の Java のクラスは以下のフィールドを持っていて、すべてのフィールドは getter を持っています。&lt;br /&gt;&lt;pre class="prettyprint"&gt;private long id;&lt;br /&gt;private String eText;&lt;br /&gt;private PartOfSpeech partOfSpeech;&lt;br /&gt;private String jText;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;仕様どおりなら、public な getter があるので正しく動作するはずです。実装的にも Bean の introspection を利用し判断しているのであれば、問題なく動作するはずなのですが、、、。&lt;br /&gt;&lt;br /&gt;しかも、気持ち悪いことに、id だけは正しく伝わっていました。&lt;br /&gt;&lt;br /&gt;試しに Java 側の private フィールドを public に変更してみたところ、ActionScript 側にデータが正しく伝わりました。&lt;br /&gt;&lt;br /&gt;ということで、原因を調査してみることにしました。&lt;br /&gt;&lt;br /&gt;結論。JavaBeans規約的に、おいらが間違ってました。&lt;br /&gt;(´・ω・`) 先頭の２文字が大文字の場合、プロパティ名の先頭は小文字に変換されないのです。&lt;br /&gt;&lt;br /&gt;JavaBeans API specification(1.01) の 8.8 Capitalization of inferred names にかかれています。&lt;br /&gt;すっかり忘れてました。Sun出身なのにｗ&lt;br /&gt;&lt;br /&gt;&lt;a name="Enums_in_Java_to_Enum_Like_Objects_in_ActionScript"&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Enums in Java to Enum Like Objects in ActionScript&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(´・ω・`) TypeError: Error #1034: 強制型変換に失敗しました。&lt;br /&gt;&lt;br /&gt;おいらはいままでのところ、&lt;a href="http://kcw-diary.blogspot.com/2010/04/blazedsremotingservicejavaenum.html"&gt;作業ログ：BlazeDSのRemotingServiceでJavaのenumを扱う方法&lt;/a&gt;で書いたような方法で Enum を扱っていました。そのため、Java 側から String として渡ってくる情報を ActionScript 上で Enum 的オブジェクトに変換しなければなりません。しかし、FlashPlayer 側に手を入れるわけにも行きません。&lt;br /&gt;&lt;br /&gt;少し調べてみると、&lt;a href="http://bugs.adobe.com/jira/browse/BLZ-17"&gt;BLZ-17&lt;/a&gt; に java の Enum と AS3 のクラスのマッピングができるようになっているという話を発見。&lt;br /&gt;&lt;br /&gt;そちらに書かれている方法どおりにやってみたところ、問題なく動作しました。&lt;br /&gt;&lt;br /&gt;初期化用の static ブロックは、web.xml の先頭で listener として読み込まれているという理由で、flex.messaging.HttpFlexSession クラスの先頭に追加しました。以下、追加されたソースです。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// patch for enum serialization&lt;br /&gt;    static {&lt;br /&gt;            PropertyProxyRegistry.getRegistry().register(Enum.class, new EnumProxy());&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2661083050049703150?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2661083050049703150/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flexremotingjavaactionscript.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2661083050049703150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2661083050049703150'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flexremotingjavaactionscript.html' title='作業メモ：FlexのRemotingでjavaからにActionScript型をマッピングする方法'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3148942906191083255</id><published>2010-04-20T02:37:00.242+09:00</published><updated>2010-04-21T17:06:03.377+09:00</updated><title type='text'>作業メモ：FlexのRemotingでActionScriptからjavaに型をマッピングする方法</title><content type='html'>今回は、Flex の Remoting で ActionScript から java に型をマッピングする方法について、実際に動作を確認しながら考えてみます。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;基本情報&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;基本的な情報は以下に書かれています。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ActionScriptからJavaへのデータマッピング規則&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_2.html#298895"&gt;&lt;br /&gt;Converting data from ActionScript to Java&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JavaとActionScriptのデータマッピングを明示的に指定する方法&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#296603"&gt;&lt;br /&gt;Explicitly mapping ActionScript and Java objects&lt;/a&gt;&lt;/li&gt;&lt;li&gt;JavaからActionScriptへのデータマッピング規則&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#304283"&gt;&lt;br /&gt;Converting data from Java to ActionScript&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;以下、各型についてマッピングの実験をしてみます。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : Boolean, String of "true" or "false"  to java.lang.Boolean&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaBooleanTest(boolean asBooleanTrue, boolean asBooleanFalse, boolean stringTrue, boolean stringFalse) {&lt;br /&gt;    return &lt;br /&gt;        (asBooleanTrue  == true ) &amp;amp;&amp;amp; &lt;br /&gt;        (asBooleanFalse == false) &amp;amp;&amp;amp;&lt;br /&gt;        (stringTrue     == true ) &amp;amp;&amp;amp;&lt;br /&gt;        (stringFalse    == false);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaBooleanTest():void {&lt;br /&gt;    remoteObjectWrapper.invoke(true, false, "true", "false");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : flash.utils.ByteArray to byte []&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaByteArrayTest(byte[] bytes) {&lt;br /&gt;    return &lt;br /&gt;        (bytes[0] == 0 ) &amp;amp;&amp;amp; &lt;br /&gt;        (bytes[1] == 1 ) &amp;amp;&amp;amp; &lt;br /&gt;        (bytes[2] == 2 );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaByteArrayTest():void {&lt;br /&gt;    var byteArray:ByteArray = new ByteArray();&lt;br /&gt;    byteArray.writeByte(0);&lt;br /&gt;    byteArray.writeByte(1);&lt;br /&gt;    byteArray.writeByte(2);&lt;br /&gt;    remoteObjectWrapper.invoke(byteArray);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : Date to java.util.Date&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaDateTest(Date date) {&lt;br /&gt;    return date.getTime() == 1271699264375L;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaDateTest():void {&lt;br /&gt;    var date:Date = new Date();&lt;br /&gt;    date.time = 1271699264375;&lt;br /&gt;    remoteObjectWrapper.invoke(date);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : int/uint to java.lang.Integer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaIntTest(int intValue, int uintValue1, int uintValue2) {&lt;br /&gt;    return&lt;br /&gt;        (intValue   == -1        ) &amp;amp;&amp;amp;&lt;br /&gt;        (uintValue1 == 2147483647) &amp;amp;&amp;amp; // rounded from 2147483648&lt;br /&gt;        (uintValue2 == 2147483647);   // rounded from 2147483649&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaIntTest():void {&lt;br /&gt;    var intValue:int = -1;&lt;br /&gt;    // java: Integer.MAX_VALUE = 2147483647.&lt;br /&gt;    var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!&lt;br /&gt;    var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!&lt;br /&gt;    remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;このテストの結果から、以下のことが分かります。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ActionScript 側 の uint は Integer.MAX_VALUE = 2147483647 よりも大きい値を扱うことができる。&lt;/li&gt;&lt;li&gt;Java 側は、Integer.MAX_VALUE より大きい値が渡されると Integer.MAX_VALUE に丸めてしまう。&lt;/li&gt;&lt;li&gt;このことから、Java との連携が決まっている場合、uint は使わないほうが無難のようです。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : Number to java.lang.Double&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaNumberTest(double numberValue) {&lt;br /&gt;    return&lt;br /&gt;        (numberValue == -1.5);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaNumberTest():void {&lt;br /&gt;    remoteObjectWrapper.invoke(new Number(-1.5));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : String to java.lang.String&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaStringTest(String stringValue1, String stringValue2, String stringValue3) {&lt;br /&gt;    return&lt;br /&gt;        (stringValue1.equals("")) &amp;amp;&amp;amp;&lt;br /&gt;        (stringValue2.equals("foo")) &amp;amp;&amp;amp;&lt;br /&gt;        (stringValue3 == null); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaStringTest():void {&lt;br /&gt;    var stringValue1:String = "";&lt;br /&gt;    var stringValue2:String = "foo";&lt;br /&gt;    var undefinedValue:String;   // Note: undefined is converted to null.&lt;br /&gt;    var nullValue:String = null; // Note: null is converted to null.&lt;br /&gt;    remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ActionScript の undefined と null は、Java の null に変換されるようです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : Object (generic) to java.util.Map&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaGenericObjectTest(Map&amp;lt;String,Object&amp;gt; nullValue, Map&amp;lt;String,Object&amp;gt; simpleObject, Map&amp;lt;String,Object&amp;gt; hasNullProperty, Map&amp;lt;String,Object&amp;gt; hasStringProperty, Map&amp;lt;String,Object&amp;gt; hasDateProperty, Map&amp;lt;String,Object&amp;gt; hasNestedProperty) {&lt;br /&gt;    return&lt;br /&gt;        (nullValue == null) &amp;amp;&amp;amp;&lt;br /&gt;        (simpleObject != null) &amp;amp;&amp;amp;&lt;br /&gt;        (hasNullProperty.get("property") == null) &amp;amp;&amp;amp;&lt;br /&gt;        (hasStringProperty.get("property").equals("foo")) &amp;amp;&amp;amp;&lt;br /&gt;        (Date.class.isInstance(hasDateProperty.get("property"))) &amp;amp;&amp;amp;&lt;br /&gt;        (Date.class.isInstance(Map.class.cast(hasNestedProperty.get("property")).get("nestedProperty")));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaGenericObjectTest():void {&lt;br /&gt;    // null&lt;br /&gt;    var nullValue:Object = null;&lt;br /&gt;    &lt;br /&gt;    // simple object&lt;br /&gt;    var simpleObject:Object = new Object();&lt;br /&gt;    &lt;br /&gt;    // has null property&lt;br /&gt;    var hasNullProperty:Object = new Object();&lt;br /&gt;    hasNullProperty.property = null;&lt;br /&gt;    &lt;br /&gt;    // has String object&lt;br /&gt;    var hasStringProperty:Object = new Object();&lt;br /&gt;    hasStringProperty.property = "foo"&lt;br /&gt;        &lt;br /&gt;    // has Data object&lt;br /&gt;    var hasDateProperty:Object = new Object();&lt;br /&gt;    hasDateProperty.property = new Date();&lt;br /&gt;    &lt;br /&gt;    // has nested property&lt;br /&gt;    var hasNestedProperty:Object = new Object();&lt;br /&gt;    hasNestedProperty.property = new Object();&lt;br /&gt;    hasNestedProperty.property.nestedProperty = new Date();&lt;br /&gt;    &lt;br /&gt;    remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;ネストされても、特に問題なく動作するようです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : typed Object to typed Object&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;private コンストラクタのみのJavaクラスを対象にしてみたところ、以下のように怒られてしまいました。&lt;br /&gt;&lt;pre&gt;Unable to create a new instance of type 'experiment.SimpleObject'. &lt;br /&gt;Types must have a public, no arguments constructor.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ObjectFanatics 的方針としては、public のデフォルトコンストラクタの強制など容認できるはずもありません。&lt;br /&gt;ということで、ソースに&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html#Patch_for_Private_Constructor"&gt;パッチ&lt;/a&gt;を当てて対応しました。&lt;br /&gt;&lt;br /&gt;引数無しの private コンストラクタが必要になってしまうのと、そのために final の変数の利用がほぼ絶望的になるという点がかなり厳しいのですが、とりあえずは妥協することにしましょう。将来的には、引数のある private コンストラクタに対応しようと思います。（TODO: 引数なしのプライベートコンストラクタを new してから値を格納する方法ではなく、private コンストラクタの引数にシリアライズされたオブジェクトを復元していく方法を実装する。）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;お次は、java 側で private field に値を入れることを期待していたのですが、以下のように怒られてしまいました。&lt;br /&gt;&lt;pre&gt;Cannot create class of type 'experiment.WithPrivateFileds'&lt;br /&gt;&lt;/pre&gt;ObjectFanatics 的方針としては、private field が使えない制約など容認できるはずもありません。&lt;br /&gt;&lt;br /&gt;ちょっと調べてみると、こんな issue がありました。&lt;br /&gt;&lt;a href="http://bugs.adobe.com/jira/browse/BLZ-427"&gt;BLZ-427&lt;/a&gt; - Add configuration option for BeanProxy#includeReadOnly property.これか！？&lt;br /&gt;とおもいきや、これは Java から ActionScript 側への変換に関してだけみたいですね。&lt;br /&gt;しかし、BeanProxyのフィールドに対する判断基準になる設定なので、必要です。&lt;br /&gt;&lt;br /&gt;ということで、services-config.xml ファイルのチャネル定義に serialization の設定として以下のように &lt;i&gt;include-read-only&lt;/i&gt; オプションを追加します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;channels&amp;gt;&lt;br /&gt;  &amp;lt;channel-definition id="amf" class="mx.messaging.channels.AMFChannel"&amp;gt;&lt;br /&gt;    &amp;lt;endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint" /&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;      &amp;lt;serialization&amp;gt;&lt;br /&gt;        &amp;lt;include-read-only&amp;gt;true&amp;lt;/include-read-only&amp;gt;&lt;br /&gt;      &amp;lt;/serialization&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;/channel-definition&amp;gt;&lt;br /&gt;&amp;lt;/channels&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;また、ActionScript 側から渡された値を Java 側の private フィールドに格納する処理も必要です。&lt;br /&gt;&lt;br /&gt;ということで、ソースに&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html#Patch_for_Private_Field"&gt;パッチ&lt;/a&gt;を当てて対応しました。&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaTypedObjectTest(SimpleObject nullValue, SimpleObject simpleObject, SimpleObjectWithPrivateConstructor simpleObjectWithPrivateConstructor, SimpleObjectWithProperties simpleObjectWithProperties, NestableObject nestableObject, WithPrivateFiled withPrivateFiled) {&lt;br /&gt;    return&lt;br /&gt;        (nullValue                               == null) &amp;&amp;&lt;br /&gt;        (simpleObject                            != null) &amp;&amp;&lt;br /&gt;        (simpleObjectWithPrivateConstructor      != null) &amp;&amp;&lt;br /&gt;        (simpleObjectWithProperties.intValue     == 10 ) &amp;&amp;&lt;br /&gt;        (simpleObjectWithProperties.stringValue.equals("foo")) &amp;&amp;&lt;br /&gt;        (simpleObjectWithProperties.simpleObject != null) &amp;&amp;&lt;br /&gt;        (nestableObject.nestableObject.nestableObject.nestableObject == null) &amp;&amp;&lt;br /&gt;        (withPrivateFiled.getStringValue().equals("foo"));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaTypedObjectTest():void {&lt;br /&gt;    // null&lt;br /&gt;    var nullValue:Object = null;&lt;br /&gt;    &lt;br /&gt;    // simple object&lt;br /&gt;    var simpleObject:Object = new SimpleObject();&lt;br /&gt;    &lt;br /&gt;    // simple object with private constructor&lt;br /&gt;    var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();&lt;br /&gt;    &lt;br /&gt;    // simple object with properties&lt;br /&gt;    var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());&lt;br /&gt;    &lt;br /&gt;    // nested properties&lt;br /&gt;    var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));&lt;br /&gt;    &lt;br /&gt;    // java object has private fields&lt;br /&gt;    var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");&lt;br /&gt;    &lt;br /&gt;    // enum&lt;br /&gt;    var enumObject:EnumObject = EnumObject.KUMA_SAN;&lt;br /&gt;&lt;br /&gt;    remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActonScript to Java : Object to enum&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;基本方針は、&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaactionscript.html#Enums_in_Java_to_Enum_Like_Objects_in_ActionScript"&gt;Enums in Java to Enum Like Objects in ActionScript&lt;/a&gt;と同じです。&lt;br /&gt;&lt;br /&gt;ActionScript側ではpublicなプロパティを１つだけ持ったオブジェクトをEnumとして扱い、明示的に java 側のEnumにマッピングしないようにします。プロパティの値は java 側の Enum の name と同じにしておきます。&lt;br /&gt;&lt;br /&gt;Java side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public boolean asToJavaEnumTest(EnumObject enumValue) {&lt;br /&gt;    return&lt;br /&gt;        (enumValue.equals(EnumObject.KUMA_SAN));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Flex side test code.&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static function asToJavaEnumTest():void {&lt;br /&gt;    var enumValue:EnumObject = EnumObject.KUMA_SAN;&lt;br /&gt;    remoteObjectWrapper.invoke(enumValue);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;以下、未検証&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Array (dense) to java.util.List&lt;/li&gt;&lt;li&gt;Array (sparse) to java.util.Map&lt;/li&gt;&lt;li&gt;XML to org.w3c.dom.Document&lt;/li&gt;&lt;li&gt;XMLDocument(legacy XML type)&amp;nbsp; to org.w3c.dom.Document&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="" name="Patch_for_Private_Constructor"&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Patch for Private Constructor&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;変更前&lt;br /&gt;&lt;pre class="prettyprint"&gt;110: Object instance = cls.newInstance();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;変更後&lt;br /&gt;&lt;pre class="prettyprint"&gt;try {&lt;br /&gt;    instance = cls.newInstance();&lt;br /&gt;} catch (IllegalAccessException e){&lt;br /&gt;    for (Constructor&amp;lt;? extends Object&amp;gt; constructor : cls.getDeclaredConstructors()) {&lt;br /&gt;        if (constructor.getParameterTypes().length != 0) continue;&lt;br /&gt;        constructor.setAccessible(true);&lt;br /&gt;        instance = constructor.newInstance();&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    if (instance == null) throw e;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="" name="Patch_for_Private_Field"&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Patch for Private Field Serialization&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;flex.messaging.io.BeanProxy#setValue(Object instance, String propertyName, Object value)&lt;br /&gt;&lt;pre class="prettyprint"&gt;public void setValue(Object instance, String propertyName, Object value)&lt;br /&gt;    {&lt;br /&gt;        BeanProperty bp = getBeanProperty(instance, propertyName);&lt;br /&gt;&lt;br /&gt;        if (bp != null)&lt;br /&gt;        {&lt;br /&gt;// patch for private field.&lt;br /&gt;//            if (bp.isWrite())&lt;br /&gt;//            {&lt;br /&gt;                try&lt;br /&gt;                {&lt;br /&gt;                    Class desiredPropClass = bp.getType();&lt;br /&gt;                    TypeMarshaller marshaller = TypeMarshallingContext.getTypeMarshaller();&lt;br /&gt;                    value = marshaller.convert(value, desiredPropClass);&lt;br /&gt;                    ClassUtil.validateAssignment(instance, propertyName, value);&lt;br /&gt;                    bp.set(instance, value);&lt;br /&gt;                }&lt;br /&gt;                catch (Exception e)&lt;br /&gt;                {&lt;br /&gt;                    SerializationContext context = getSerializationContext();&lt;br /&gt;&lt;br /&gt;                    // Log ignore failed property set errors&lt;br /&gt;                    if (Log.isWarn() &amp;amp;&amp;amp; logPropertyErrors(context))&lt;br /&gt;                    {&lt;br /&gt;                        Logger log = Log.getLogger(LOG_CATEGORY);&lt;br /&gt;                        log.warn("Failed to set property {0} on type {1}.",&lt;br /&gt;                                new Object[] {propertyName, getAlias(instance)}, e);&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    if (!ignorePropertyErrors(context))&lt;br /&gt;                    {&lt;br /&gt;                        // Failed to get property '{propertyName}' on type '{className}'.&lt;br /&gt;                        MessageException ex = new MessageException();&lt;br /&gt;                        ex.setMessage(FAILED_PROPERTY_WRITE_ERROR, new Object[] {propertyName, getAlias(instance)});&lt;br /&gt;                        ex.setRootCause(e);&lt;br /&gt;                        throw ex;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;// patch for private field.&lt;br /&gt;//            }&lt;br /&gt;//            else&lt;br /&gt;//            {&lt;br /&gt;//                SerializationContext context = getSerializationContext();&lt;br /&gt;//&lt;br /&gt;//                if (Log.isWarn() &amp;amp;&amp;amp; logPropertyErrors(context))&lt;br /&gt;//                {&lt;br /&gt;//                    Logger log = Log.getLogger(LOG_CATEGORY);&lt;br /&gt;//                    log.warn("Property {0} not writable on class {1}",&lt;br /&gt;//                            new Object[] {propertyName, getAlias(instance)});&lt;br /&gt;//                }&lt;br /&gt;//&lt;br /&gt;//                if (!ignorePropertyErrors(context))&lt;br /&gt;//                {&lt;br /&gt;//                    //Property '{propertyName}' not writable on class '{alias}'.&lt;br /&gt;//                    MessageException ex = new MessageException();&lt;br /&gt;//                    ex.setMessage(NON_WRITABLE_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});&lt;br /&gt;//                    throw ex;&lt;br /&gt;//                }&lt;br /&gt;//            }&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            SerializationContext context = getSerializationContext();&lt;br /&gt;&lt;br /&gt;            if (Log.isWarn() &amp;amp;&amp;amp; logPropertyErrors(context))&lt;br /&gt;            {&lt;br /&gt;                Logger log = Log.getLogger(LOG_CATEGORY);&lt;br /&gt;                log.warn("Ignoring set property {0} for type {1} as a setter could not be found.",&lt;br /&gt;                            new Object[] {propertyName, getAlias(instance)});&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (!ignorePropertyErrors(context))&lt;br /&gt;            {&lt;br /&gt;                // Property '{propertyName}' not found on class '{alias}'.&lt;br /&gt;                MessageException ex = new MessageException();&lt;br /&gt;                ex.setMessage(UNKNOWN_PROPERTY_ERROR, new Object[] {propertyName, getAlias(instance)});&lt;br /&gt;                throw ex;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Test source code(Java)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;experiment/EnumObject.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public enum EnumObject {&lt;br /&gt;    KUMA_SAN("くまさん"),&lt;br /&gt;    TANUKI_SAN("たぬきさん");&lt;br /&gt;    private final String string;&lt;br /&gt;    private EnumObject(String string) {&lt;br /&gt;        this.string = string;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/NestableObject.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public class NestableObject {&lt;br /&gt;    public NestableObject nestableObject;&lt;br /&gt;    private NestableObject(){}&lt;br /&gt;    public NestableObject(NestableObject nestableObject) {&lt;br /&gt;        this.nestableObject = nestableObject;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/SerializationTestService.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {    &lt;br /&gt;    import flash.utils.ByteArray;&lt;br /&gt;    &lt;br /&gt;    import mx.controls.Alert;&lt;br /&gt;&lt;br /&gt;    public final class SerializationTestService {&lt;br /&gt;        private static var remoteObjectWrapper:RemoteObjectWrapper = new RemoteObjectWrapper("SerializationTestService");&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaBooleanTest():void {&lt;br /&gt;            remoteObjectWrapper.invoke(true, false, "true", "false");&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaByteArrayTest():void {&lt;br /&gt;            var byteArray:ByteArray = new ByteArray();&lt;br /&gt;            byteArray.writeByte(0);&lt;br /&gt;            byteArray.writeByte(1);&lt;br /&gt;            byteArray.writeByte(2);&lt;br /&gt;            remoteObjectWrapper.invoke(byteArray);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaDateTest():void {&lt;br /&gt;            var date:Date = new Date();&lt;br /&gt;            date.time = 1271699264375;&lt;br /&gt;            remoteObjectWrapper.invoke(date);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaIntTest():void {&lt;br /&gt;            var intValue:int = -1;&lt;br /&gt;            // java: Integer.MAX_VALUE = 2147483647.&lt;br /&gt;            var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!&lt;br /&gt;            var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!&lt;br /&gt;            remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaNumberTest():void {&lt;br /&gt;            remoteObjectWrapper.invoke(new Number(-1.5));&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaStringTest():void {&lt;br /&gt;            var stringValue1:String = "";&lt;br /&gt;            var stringValue2:String = "foo";&lt;br /&gt;            var undefinedValue:String;   // Note: undefined is converted to null.&lt;br /&gt;            var nullValue:String = null; // Note: null is converted to null.&lt;br /&gt;            remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaGenericObjectTest():void {&lt;br /&gt;            // null&lt;br /&gt;            var nullValue:Object = null;&lt;br /&gt;            &lt;br /&gt;            // simple object&lt;br /&gt;            var simpleObject:Object = new Object();&lt;br /&gt;            &lt;br /&gt;            // has null property&lt;br /&gt;            var hasNullProperty:Object = new Object();&lt;br /&gt;            hasNullProperty.property = null;&lt;br /&gt;            &lt;br /&gt;            // has String object&lt;br /&gt;            var hasStringProperty:Object = new Object();&lt;br /&gt;            hasStringProperty.property = "foo"&lt;br /&gt;                &lt;br /&gt;            // has Data object&lt;br /&gt;            var hasDateProperty:Object = new Object();&lt;br /&gt;            hasDateProperty.property = new Date();&lt;br /&gt;            &lt;br /&gt;            // has nested property&lt;br /&gt;            var hasNestedProperty:Object = new Object();&lt;br /&gt;            hasNestedProperty.property = new Object();&lt;br /&gt;            hasNestedProperty.property.nestedProperty = new Date();&lt;br /&gt;            &lt;br /&gt;            remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaTypedObjectTest():void {&lt;br /&gt;            // null&lt;br /&gt;            var nullValue:Object = null;&lt;br /&gt;            &lt;br /&gt;            // simple object&lt;br /&gt;            var simpleObject:Object = new SimpleObject();&lt;br /&gt;            &lt;br /&gt;            // simple object with private constructor&lt;br /&gt;            var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();&lt;br /&gt;            &lt;br /&gt;            // simple object with properties&lt;br /&gt;            var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());&lt;br /&gt;            &lt;br /&gt;            // nested properties&lt;br /&gt;            var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));&lt;br /&gt;            &lt;br /&gt;            // java object has private fields&lt;br /&gt;            var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");&lt;br /&gt;            &lt;br /&gt;            // enum&lt;br /&gt;            var enumObject:EnumObject = EnumObject.KUMA_SAN;&lt;br /&gt;&lt;br /&gt;            remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaEnumTest():void {&lt;br /&gt;            var enumValue:EnumObject = EnumObject.KUMA_SAN;&lt;br /&gt;            remoteObjectWrapper.invoke(enumValue);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        private static function createResultHandler(methodName:String):Function {&lt;br /&gt;            return function(result:Boolean):void{Alert.show("methodName : " + (result ? "passed" : "failed"))}&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/SimpleObject.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public class SimpleObject {&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/SimpleObjectWithPrivateConstructor.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public class SimpleObjectWithPrivateConstructor {&lt;br /&gt;    private SimpleObjectWithPrivateConstructor(){};&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/SimpleObjectWithProperties.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public class SimpleObjectWithProperties {&lt;br /&gt;    public int intValue;&lt;br /&gt;    public String stringValue;&lt;br /&gt;    public SimpleObject simpleObject;&lt;br /&gt;    private SimpleObjectWithProperties(){}&lt;br /&gt;    public SimpleObjectWithProperties(int intValue, String stringValue, SimpleObject simpleObject) {&lt;br /&gt;        this.intValue = intValue;&lt;br /&gt;        this.stringValue = stringValue;&lt;br /&gt;        this.simpleObject = simpleObject;&lt;br /&gt;    }    &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;experiment/WithPrivateFiled.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package experiment;&lt;br /&gt;&lt;br /&gt;public class WithPrivateFiled {&lt;br /&gt;    private String stringValue;&lt;br /&gt;    private WithPrivateFiled(){}&lt;br /&gt;    public WithPrivateFiled(String stringValue) { this.stringValue = stringValue; }&lt;br /&gt;    public String getStringValue() { return stringValue; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Test source code(Flex)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;test/EnumObject.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    &lt;br /&gt;    [RemoteClass(alias="experiment.EnumObject")]&lt;br /&gt;    public class EnumObject {&lt;br /&gt;        &lt;br /&gt;        // Enum constants&lt;br /&gt;        public static const KUMA_SAN:EnumObject = new EnumObject("KUMA_SAN", "くまさん");&lt;br /&gt;        public static const TANUKI_SAN:EnumObject = new EnumObject("TANUKI_SAN", "たぬきさん");&lt;br /&gt;        &lt;br /&gt;        // Enum name. This must be public and not static valiable.&lt;br /&gt;        public var val:String;&lt;br /&gt;        &lt;br /&gt;        [Transient]&lt;br /&gt;        public var string:String;&lt;br /&gt;        &lt;br /&gt;        // Constructor&lt;br /&gt;        public function EnumObject(name:String, string:String) {&lt;br /&gt;            this.val = name;&lt;br /&gt;            this.string = string;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // for displaying.&lt;br /&gt;        public function toString():String {&lt;br /&gt;            return string;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // use equality instead of identity because of the limitation of ActionScript.&lt;br /&gt;        public function equals(object:Object):Boolean {&lt;br /&gt;            return this.toString() == object.toString();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/NestableObject.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    &lt;br /&gt;    [RemoteClass(alias="experiment.NestableObject")]&lt;br /&gt;    public class NestableObject {&lt;br /&gt;        &lt;br /&gt;        // nested value&lt;br /&gt;        public var nestableObject:NestableObject;&lt;br /&gt;        &lt;br /&gt;        // constructor&lt;br /&gt;        public function NestableObject(nestableObject:NestableObject) {&lt;br /&gt;            this.nestableObject = nestableObject;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/RemoteObjectWrapper.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    import mx.controls.Alert;&lt;br /&gt;    import mx.rpc.events.FaultEvent;&lt;br /&gt;    import mx.rpc.events.ResultEvent;&lt;br /&gt;    import mx.rpc.remoting.Operation;&lt;br /&gt;    import mx.rpc.remoting.RemoteObject;&lt;br /&gt;&lt;br /&gt;    public class RemoteObjectWrapper {&lt;br /&gt;        private var remoteObject:RemoteObject;&lt;br /&gt;        public function RemoteObjectWrapper(destination:String):void {&lt;br /&gt;            this.remoteObject = new RemoteObject(destination);&lt;br /&gt;        }&lt;br /&gt;        public function invoke(...args):void {&lt;br /&gt;            var mathodName:String = getCallerSimpleName();&lt;br /&gt;            remoteObject[mathodName].addEventListener("result", function (event:ResultEvent):void{Alert.show(mathodName + " : " + (event.result ? "passed" : "failed"))});&lt;br /&gt;            remoteObject.addEventListener(FaultEvent.FAULT, function(faultEvent:FaultEvent):void{Alert.show("Fault : " + faultEvent)});&lt;br /&gt;            var operation:Operation = remoteObject[mathodName];&lt;br /&gt;            operation.arguments = args;&lt;br /&gt;            operation.send();&lt;br /&gt;        }&lt;br /&gt;        private function getCallerSimpleName():String {&lt;br /&gt;            var block:String = new Error().getStackTrace().split("at ")[3];&lt;br /&gt;            var startIndex:int = block.indexOf("at ");// start of first line&lt;br /&gt;            var endIndex:int = block.indexOf("()");   // end of function name&lt;br /&gt;            var fullName:String = block.substring(startIndex + 3, endIndex);&lt;br /&gt;            var callerSimpleName:String = fullName.substring(fullName.indexOf("/") + 1, endIndex);&lt;br /&gt;            return callerSimpleName; // this is caller's caller.&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/SerializationTestService.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {    &lt;br /&gt;    import flash.utils.ByteArray;&lt;br /&gt;    &lt;br /&gt;    import mx.controls.Alert;&lt;br /&gt;&lt;br /&gt;    public final class SerializationTestService {&lt;br /&gt;        private static var remoteObjectWrapper:RemoteObjectWrapper = new RemoteObjectWrapper("SerializationTestService");&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaBooleanTest():void {&lt;br /&gt;            remoteObjectWrapper.invoke(true, false, "true", "false");&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaByteArrayTest():void {&lt;br /&gt;            var byteArray:ByteArray = new ByteArray();&lt;br /&gt;            byteArray.writeByte(0);&lt;br /&gt;            byteArray.writeByte(1);&lt;br /&gt;            byteArray.writeByte(2);&lt;br /&gt;            remoteObjectWrapper.invoke(byteArray);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaDateTest():void {&lt;br /&gt;            var date:Date = new Date();&lt;br /&gt;            date.time = 1271699264375;&lt;br /&gt;            remoteObjectWrapper.invoke(date);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaIntTest():void {&lt;br /&gt;            var intValue:int = -1;&lt;br /&gt;            // java: Integer.MAX_VALUE = 2147483647.&lt;br /&gt;            var uintValue1:uint = 2147483648; // this will be rounded to 2147483647!&lt;br /&gt;            var uintValue2:uint = 2147483649; // this will be rounded to 2147483647!&lt;br /&gt;            remoteObjectWrapper.invoke(intValue, uintValue1, uintValue2);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaNumberTest():void {&lt;br /&gt;            remoteObjectWrapper.invoke(new Number(-1.5));&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaStringTest():void {&lt;br /&gt;            var stringValue1:String = "";&lt;br /&gt;            var stringValue2:String = "foo";&lt;br /&gt;            var undefinedValue:String;   // Note: undefined is converted to null.&lt;br /&gt;            var nullValue:String = null; // Note: null is converted to null.&lt;br /&gt;            remoteObjectWrapper.invoke(stringValue1, stringValue2, undefinedValue, nullValue);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaGenericObjectTest():void {&lt;br /&gt;            // null&lt;br /&gt;            var nullValue:Object = null;&lt;br /&gt;            &lt;br /&gt;            // simple object&lt;br /&gt;            var simpleObject:Object = new Object();&lt;br /&gt;            &lt;br /&gt;            // has null property&lt;br /&gt;            var hasNullProperty:Object = new Object();&lt;br /&gt;            hasNullProperty.property = null;&lt;br /&gt;            &lt;br /&gt;            // has String object&lt;br /&gt;            var hasStringProperty:Object = new Object();&lt;br /&gt;            hasStringProperty.property = "foo"&lt;br /&gt;                &lt;br /&gt;            // has Data object&lt;br /&gt;            var hasDateProperty:Object = new Object();&lt;br /&gt;            hasDateProperty.property = new Date();&lt;br /&gt;            &lt;br /&gt;            // has nested property&lt;br /&gt;            var hasNestedProperty:Object = new Object();&lt;br /&gt;            hasNestedProperty.property = new Object();&lt;br /&gt;            hasNestedProperty.property.nestedProperty = new Date();&lt;br /&gt;            &lt;br /&gt;            remoteObjectWrapper.invoke(nullValue, simpleObject, hasNullProperty, hasStringProperty, hasDateProperty, hasNestedProperty);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaTypedObjectTest():void {&lt;br /&gt;            // null&lt;br /&gt;            var nullValue:Object = null;&lt;br /&gt;            &lt;br /&gt;            // simple object&lt;br /&gt;            var simpleObject:Object = new SimpleObject();&lt;br /&gt;            &lt;br /&gt;            // simple object with private constructor&lt;br /&gt;            var simpleObjectWithPrivateConstructor:SimpleObjectWithPrivateConstructor = new SimpleObjectWithPrivateConstructor();&lt;br /&gt;            &lt;br /&gt;            // simple object with properties&lt;br /&gt;            var simpleObjectWithProperties:SimpleObjectWithProperties = new SimpleObjectWithProperties(10, "foo", new SimpleObject());&lt;br /&gt;            &lt;br /&gt;            // nested properties&lt;br /&gt;            var nestableObject:NestableObject = new NestableObject(new NestableObject(new NestableObject(null)));&lt;br /&gt;            &lt;br /&gt;            // java object has private fields&lt;br /&gt;            var withPrivateFiled:WithPrivateFiled = new WithPrivateFiled("foo");&lt;br /&gt;            &lt;br /&gt;            // enum&lt;br /&gt;            var enumObject:EnumObject = new EnumObject("");&lt;br /&gt;&lt;br /&gt;            remoteObjectWrapper.invoke(nullValue, simpleObject, simpleObjectWithPrivateConstructor, simpleObjectWithProperties, nestableObject, withPrivateFiled);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        public static function asToJavaEnumTest():void {&lt;br /&gt;            var enumValue:EnumObject = EnumObject.KUMA_SAN;&lt;br /&gt;            remoteObjectWrapper.invoke(enumValue);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        private static function createResultHandler(methodName:String):Function {&lt;br /&gt;            return function(result:Boolean):void{Alert.show("methodName : " + (result ? "passed" : "failed"))}&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/SerializationTestServiceApp.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;!-- Application to invoke serialization tests. --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;               xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;               xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt;    &amp;lt;s:layout&amp;gt;&lt;br /&gt;        &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt;    &amp;lt;/s:layout&amp;gt;&lt;br /&gt;    &amp;lt;fx:Script&amp;gt;&lt;br /&gt;        &amp;lt;![CDATA[&lt;br /&gt;            import test.SerializationTestService;&lt;br /&gt;            protected function test():void {&lt;br /&gt;                SerializationTestService.asToJavaBooleanTest();&lt;br /&gt;                SerializationTestService.asToJavaByteArrayTest();&lt;br /&gt;                SerializationTestService.asToJavaDateTest();&lt;br /&gt;                SerializationTestService.asToJavaIntTest();&lt;br /&gt;                SerializationTestService.asToJavaNumberTest();&lt;br /&gt;                SerializationTestService.asToJavaStringTest();&lt;br /&gt;                SerializationTestService.asToJavaGenericObjectTest();&lt;br /&gt;                SerializationTestService.asToJavaTypedObjectTest();&lt;br /&gt;                SerializationTestService.asToJavaEnumTest();&lt;br /&gt;            }&lt;br /&gt;        ]]&amp;gt;&lt;br /&gt;    &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;    &amp;lt;s:Button id="testButton" label="Test" click="test()"/&amp;gt;&lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/SimpleObject.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    [RemoteClass(alias="experiment.SimpleObject")]&lt;br /&gt;    public class SimpleObject {&lt;br /&gt;        public function SimpleObject() {}&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/SimpleObjectWithPrivateConstructor.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    [RemoteClass(alias="experiment.SimpleObjectWithPrivateConstructor")]&lt;br /&gt;    public class SimpleObjectWithPrivateConstructor {&lt;br /&gt;        public function SimpleObjectWithPrivateConstructor() {&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/SimpleObjectWithProperties.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt; [RemoteClass(alias="experiment.SimpleObjectWithProperties")]&lt;br /&gt; public class SimpleObjectWithProperties {&lt;br /&gt;  &lt;br /&gt;  // properties&lt;br /&gt;  public var intValue:int;&lt;br /&gt;  public var stringValue:String;&lt;br /&gt;  public var simpleObject:SimpleObject;&lt;br /&gt;  &lt;br /&gt;  // constructor&lt;br /&gt;  public function SimpleObjectWithProperties(intValue:int, stringValue:String, simpleObject:SimpleObject):void {&lt;br /&gt;   this.intValue = intValue;&lt;br /&gt;   this.stringValue = stringValue;&lt;br /&gt;   this.simpleObject = simpleObject;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;test/WithPrivateFiled.as&lt;br /&gt;&lt;pre class="prettyprint"&gt;package test {&lt;br /&gt;    [RemoteClass(alias="experiment.WithPrivateFiled")]&lt;br /&gt;    public class WithPrivateFiled {&lt;br /&gt;        &lt;br /&gt;        // The field of ActionSide is public. Java side of that is private.&lt;br /&gt;        public var stringValue:String;&lt;br /&gt;        &lt;br /&gt;        // constructor&lt;br /&gt;        public function WithPrivateFiled(stringValue:String) {&lt;br /&gt;            this.stringValue = stringValue;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3148942906191083255?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3148942906191083255/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3148942906191083255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3148942906191083255'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flexremotingjavaflex.html' title='作業メモ：FlexのRemotingでActionScriptからjavaに型をマッピングする方法'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1199759981467495965</id><published>2010-04-19T14:32:00.017+09:00</published><updated>2010-04-21T17:25:40.393+09:00</updated><title type='text'>作業ログ：BlazeDSのRemotingServiceでJavaのenumを扱う方法</title><content type='html'>ActionScrip側からAMFで送られた文字列をBlazeDS4側でenumに変換しようとしたところ、&lt;br /&gt;&lt;pre&gt;No enum const class &lt;br /&gt;&lt;/pre&gt;と怒られてしまい、うまくいきませんでした。&lt;br /&gt;&lt;br /&gt;flex 側で IExternalizable を実装して String を投げるようにしてみたのですが、そうすると今度は BlazeDS 側で配列に変更しようとしてエラーで落ちました。&lt;br /&gt;&lt;br /&gt;方法が間違っていたのかもしれませんが、どうも解決法が見つけられなかったので、とりあえずはワークアラウンドで対応することにしました。&lt;br /&gt;&lt;br /&gt;(´・ω・`) 正規の方法を教えてください、、、&lt;br /&gt;&lt;br /&gt;&lt;div style="color: red;"&gt;4.21.2010追記：正規の方法がありました。詳細は&lt;a href="http://kcw-diary.blogspot.com/2010/04/flexremotingjavaactionscript.html#Enums_in_Java_to_Enum_Like_Objects_in_ActionScript"&gt;こちら&lt;/a&gt;を参照のこと。&lt;/div&gt;&lt;br /&gt;&lt;strike&gt;&lt;br /&gt;&lt;b&gt;workaround&lt;/b&gt;&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strike&gt;ActionScript 側の Enum (のような)実装では、内部に必ず Enum.valueOf() メソッドの第二引数に対応する文字列を持つpublicなインスタンス変数(or getter/setter)を配置する。&lt;/strike&gt;&lt;/li&gt;&lt;li&gt;&lt;strike&gt;ActionScript 側の  Enum (のような)実装では、必ず public var name:String を定義し、java 側の Enum#getName() と対応させる。&lt;br /&gt;&lt;/strike&gt;&lt;/li&gt;&lt;li&gt;&lt;strike&gt;それ以外の変数(or getter/setter)を配置してもよいが、すべてメタタグ [Transient] をつける。&lt;/strike&gt;&lt;/li&gt;&lt;li&gt;&lt;strike&gt;BlazeDS4のソースにパッチを当てる。 &lt;/strike&gt;&lt;/li&gt;&lt;/ul&gt;&lt;strike&gt;AMFから受け取った情報が、値がString型のエントリを一つだけ持つASObjectになればOKです。&lt;br /&gt;この方法だと、副作用として flex 側で IExternalizable を実装する必要がないのでラクチンです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;パッチ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;対象のソースコードは、flex.messaging.io.amf.translator.decoder.EnumDecoder クラスです。&lt;br /&gt;&lt;br /&gt;元のコードは以下のようになっています。&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;strike&gt;55: Enum value = Enum.valueOf(desiredClass, encodedObject.toString());&lt;br /&gt;&lt;/strike&gt;&lt;/pre&gt;&lt;strike&gt;&lt;br /&gt;encodedObject の型が flex.messaging.io.amf.ASObject 型なので、encodedObject.toString() の値は以下のようなフォーマットの文字列に変換されます。&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;strike&gt;ASObject(33469162){name=HOGE}&lt;br /&gt;&lt;/strike&gt;&lt;/pre&gt;&lt;strike&gt;&lt;br /&gt;上記のワークアラウンドを適用すると、ASObjectはひとつだけエントリを持つマップとなるはずなので、そのエントリの値を使えば Enum が復元できます。&lt;br /&gt;&lt;br /&gt;以下が変更内容です。ASObject以外が来る場合もあるかもしれないので（まだそこまでソースを追ってません）一応、オリジナルのコードも残しておきます。&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;strike&gt;final Enum value;&lt;br /&gt;if (ASObject.class.isInstance(encodedObject)) {&lt;br /&gt; // patch for workaround&lt;br /&gt; value = Enum.valueOf(desiredClass, ASObject.class.cast(encodedObject).values().iterator().next().toString());&lt;br /&gt;} else {&lt;br /&gt; // original&lt;br /&gt; value = Enum.valueOf(desiredClass, encodedObject.toString());&lt;br /&gt;}&lt;br /&gt;&lt;/strike&gt;&lt;/pre&gt;&lt;strike&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ActionScript 側のEnum（のようなもの）の例&lt;/b&gt;&lt;br /&gt;&lt;/strike&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;strike&gt;public final class Hoge {&lt;br /&gt; public var name:String;&lt;br /&gt; public function Hoge(name:String) { this.name = name; }&lt;br /&gt; public static const HOGETAROU:Hoge = new Hoge("HOGETAROU");&lt;br /&gt; public static const HOGEJIROU:Hoge = new Hoge("HOGEJIROU");&lt;br /&gt; public static const HOGENOSUKE:Hoge = new Hoge("HOGENOSUKE");&lt;br /&gt;}&lt;br /&gt;&lt;/strike&gt;&lt;/pre&gt;&lt;strike&gt;&lt;/strike&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1199759981467495965?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1199759981467495965/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsremotingservicejavaenum.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1199759981467495965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1199759981467495965'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsremotingservicejavaenum.html' title='作業ログ：BlazeDSのRemotingServiceでJavaのenumを扱う方法'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5085614883880180405</id><published>2010-04-19T04:23:00.004+09:00</published><updated>2010-04-19T04:39:28.964+09:00</updated><title type='text'>ActionScriptファイル内でXMLファイルのembed設定をするサンプル</title><content type='html'>ActionScript ファイル内で XML ファイルの embed 設定をする方法のサンプルです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;構成&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;sample.xml&lt;br /&gt;サンプルのXMLファイル。&lt;/li&gt;&lt;li&gt;XmlService.as&lt;br /&gt;サンプルのXMLファイルへのアクセスを提供する ActionScript ファイル。&lt;/li&gt;&lt;li&gt;EmbeddedXmlTest.mxml&lt;br /&gt;上記の利用するサンプルアプリケーション。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;各ファイルを sample パッケージ直下に配置すれば動きます。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;見た目はこんな感じです。&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_IYJOWXQH1bw/S8tfJz2OwCI/AAAAAAAAABk/D-DvFDw5hJA/s1600/sample.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_IYJOWXQH1bw/S8tfJz2OwCI/AAAAAAAAABk/D-DvFDw5hJA/s320/sample.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;sample.xml&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;words&amp;gt;&lt;br /&gt; &amp;lt;word id="1" value="cat" /&amp;gt;&lt;br /&gt; &amp;lt;word id="2" value="dog" /&amp;gt;&lt;br /&gt; &amp;lt;word id="3" value="cow" /&amp;gt;&lt;br /&gt; &amp;lt;word id="4" value="lion" /&amp;gt;&lt;br /&gt; &amp;lt;word id="5" value="monkey" /&amp;gt;&lt;br /&gt; &amp;lt;word id="6" value="squirrel" /&amp;gt;&lt;br /&gt; &amp;lt;word id="7" value="elephant" /&amp;gt;&lt;br /&gt; &amp;lt;word id="8" value="hippopotamus" /&amp;gt;&lt;br /&gt; &amp;lt;word id="9" value="rabbit" /&amp;gt;&lt;br /&gt;&amp;lt;/words&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;XmlService.as&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package sample  {&lt;br /&gt; &lt;br /&gt; // 埋め込まれた xml ファイルを取得するサービス&lt;br /&gt; public class XmlService {&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 埋め込まれた xml ファイル&lt;br /&gt;   */&lt;br /&gt;  [Embed(source="sample.xml")]&lt;br /&gt;  private static const _xml:Class;&lt;br /&gt;    &lt;br /&gt;  /**&lt;br /&gt;   * xml ファイルの内容を表す XML 型の変数&lt;br /&gt;   */&lt;br /&gt;  public static const xml:XML = _xml.data;&lt;br /&gt;  &lt;br /&gt;  /**&lt;br /&gt;   * 指定されたインデックスの word 要素を返します。&lt;br /&gt;   */&lt;br /&gt;  public static function getWord(index:uint):XML {&lt;br /&gt;   return xml.word.(@id==index)[0];&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;EmbeddedXmlTest.mxml&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- XMLファイルの内容を TextArea と DataGrid に表示するサンプル --&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout verticalAlign="middle" horizontalAlign="center"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt; &amp;lt;mx:HBox width="200" borderVisible="true" verticalAlign="middle" borderColor="black" borderStyle="solid"&amp;gt;&lt;br /&gt;  &amp;lt;mx:Label text="id : {idNs.value}"/&amp;gt;&lt;br /&gt;  &amp;lt;mx:NumericStepper id="idNs" width="20" change="wordLabel.text = XmlService.getWord(idNs.value).@value" minimum="1" maximum="{XmlService.xml.word.length()}"/&amp;gt;&lt;br /&gt;  &amp;lt;mx:Label id="wordLabel" width="100%"/&amp;gt;&lt;br /&gt; &amp;lt;/mx:HBox&amp;gt;&lt;br /&gt; &amp;lt;mx:DataGrid id="grid" x="200" y="200" dataProvider="{XmlService.xml.word}" selectedIndex="{idNs.value-1}"&amp;gt;&lt;br /&gt;  &amp;lt;mx:columns&amp;gt;&lt;br /&gt;   &amp;lt;mx:DataGridColumn headerText="id" dataField="@id"/&amp;gt;&lt;br /&gt;   &amp;lt;mx:DataGridColumn headerText="value" dataField="@value"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:columns&amp;gt;&lt;br /&gt; &amp;lt;/mx:DataGrid&amp;gt;&lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;しかし、この手のネタって検索エンジンで引っ掛けるのが難しいですよね。flex, embed, XML, ActionScript など、どの検索ワードも一般的すぎる、、、。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5085614883880180405?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5085614883880180405/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/actionscriptxmlembed.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5085614883880180405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5085614883880180405'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/actionscriptxmlembed.html' title='ActionScriptファイル内でXMLファイルのembed設定をするサンプル'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_IYJOWXQH1bw/S8tfJz2OwCI/AAAAAAAAABk/D-DvFDw5hJA/s72-c/sample.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-943228571079297311</id><published>2010-04-18T08:22:00.055+09:00</published><updated>2010-04-19T00:34:12.195+09:00</updated><title type='text'>作業ログ：login機能使用時の SessionDuplicate 問題</title><content type='html'>&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4_17.html"&gt;作業ログ：GAE/J + BlazeDS 4 環境について考えてみた。&lt;/a&gt;にて、同じ session id を持つ異なる FlexSession のインスタンスを同一とみなすパッチを当てることにより、セッション重複の誤検出をしないように変更しました。&lt;br /&gt;&lt;br /&gt;しかし、 login / logout 機能周りでもセッション重複の誤検出が行われるようです。&lt;br /&gt;&lt;br /&gt;以下、状況を確認するために仕込んだログ。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 最初のアクセス(login)&lt;br /&gt;04-17 05:50AM 29.350 MessageBrokerServlet#service() : begin&lt;br /&gt;04-17 05:50AM 29.350 FlexContext#setThreadLocalObjects(): null is set.&lt;br /&gt;04-17 05:50AM 29.350 FlexContext#setThreadLocalSession(): flex.messaging.HttpFlexSession@c1b161 is set. sessionId = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 29.350 HttpFlexSessionProvider#getOrCreateSession() : HttpFlexSession is retrieved from thread local. id = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 29.352 flexClient is retrieved from in-memory flexClients repository.&lt;br /&gt;04-17 05:50AM 29.352 AbstractEndpoint#setupFlexClient(C4DB9840-340F-6FC7-5604-28ADF310987A) : flex.messaging.HttpFlexSession@1d952cdf&lt;br /&gt;04-17 05:50AM 29.352 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@d210ab, sessionId = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 29.359 doAuthentication&lt;br /&gt;04-17 05:50AM 31.199 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// 二回目のアクセス(logout)&lt;br /&gt;04-17 05:50AM 33.584 MessageBrokerServlet#service() : begin&lt;br /&gt;04-17 05:50AM 33.584 FlexContext#setThreadLocalObjects(): null is set.&lt;br /&gt;04-17 05:50AM 33.584 FlexContext#setThreadLocalSession(): flex.messaging.HttpFlexSession@1601a4f is set. sessionId = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 33.584 HttpFlexSessionProvider#getOrCreateSession() : HttpFlexSession is retrieved from thread local. id = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 33.585 flexClient is retrieved from in-memory flexClients repository.&lt;br /&gt;04-17 05:50AM 33.585 AbstractEndpoint#setupFlexClient(C4DB9840-340F-6FC7-5604-28ADF310987A) : flex.messaging.HttpFlexSession@1d952cdf&lt;br /&gt;04-17 05:50AM 33.585 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@d210ab, sessionId = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 33.586 logout&lt;br /&gt;04-17 05:50AM 33.620 sessionDestroyed : id = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 33.620 attributeRemoved : name = __flexSession, value = flex.messaging.HttpFlexSession@1d952cdf&lt;br /&gt;04-17 05:50AM 33.702 sessionDestroyed : id = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 33.758 FlexContext#setThreadLocalObjects(): null is set.&lt;br /&gt;04-17 05:50AM 33.760 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// 三回目のアクセス(?)&lt;br /&gt;04-17 05:50AM 34.276 MessageBrokerServlet#service() : begin&lt;br /&gt;04-17 05:50AM 34.276 FlexContext#setThreadLocalObjects(): null is set.&lt;br /&gt;04-17 05:50AM 34.374 sessionCreated : id = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.374 FlexContext#setThreadLocalSession(): flex.messaging.HttpFlexSession@e7b3cf is set. sessionId = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.374 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@e7b3cf&lt;br /&gt;04-17 05:50AM 34.374 HttpFlexSessionProvider#getOrCreateSession() : HttpFlexSession is created. id = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.375 flexClient is retrieved from in-memory flexClients repository.&lt;br /&gt;04-17 05:50AM 34.375 AbstractEndpoint#setupFlexClient(C4DB9840-340F-6FC7-5604-28ADF310987A) : flex.messaging.HttpFlexSession@b89a50a6&lt;br /&gt;04-17 05:50AM 34.375 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@d210ab, sessionId = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.376 sessions.size() = 2&lt;br /&gt;04-17 05:50AM 34.376 sessionId = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 34.376 sessionId = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.376 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@d210ab, sessionId = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.406 sessionDestroyed : id = BwbsdybycCfB7kDRSLErnw&lt;br /&gt;04-17 05:50AM 34.420 sessionDestroyed : id = KHeEJ_L9FBgQol3Hj15rlw&lt;br /&gt;04-17 05:50AM 34.420 attributeRemoved : name = __flexSession, value = flex.messaging.HttpFlexSession@b89a50a6&lt;br /&gt;04-17 05:50AM 34.603 sessionCreated : id = tcnt9ZwRj6jAnqib-C9o0A&lt;br /&gt;04-17 05:50AM 34.604 FlexContext#setThreadLocalSession(): flex.messaging.HttpFlexSession@1912a56 is set. sessionId = tcnt9ZwRj6jAnqib-C9o0A&lt;br /&gt;04-17 05:50AM 34.604 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@1912a56&lt;br /&gt;04-17 05:50AM 34.604 HttpFlexSessionProvider#getOrCreateSession() : HttpFlexSession is created. id = tcnt9ZwRj6jAnqib-C9o0A&lt;br /&gt;04-17 05:50AM 34.604 FlexContext#setThreadLocalObjects(): flex.messaging.HttpFlexSession@b8b7ad0d is set.&lt;br /&gt;04-17 05:50AM 34.627 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;一回目のアクセス&lt;/li&gt;&lt;ul&gt;&lt;li&gt;問題なく普通にログインできてる感じです。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;二回目のアクセス&lt;/li&gt;&lt;ul&gt;&lt;li&gt;sessionDestroyed が二回呼ばれてますね。実害はなさそうですが。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;三回目のアクセス&lt;/li&gt;&lt;ul&gt;&lt;li&gt;FlexClientに古いsessionが残ってますね。それで、新規のsessionが追加されることによって重複が検出されているみたいです。&lt;/li&gt;&lt;li&gt;二回目のアクセスで削除されたはずの BwbsdybycCfB7kDRSLErnw に sessionDestroyed が呼ばれてますね。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;何気に、全アクセスのパスが /messagebroker/amf;jsessionid=BwbsdybycCfB7kDRSLErnw になってるなぁ。これが原因？ ということで、そうならない形で再実験。cookie 削除して、flashも新規にロードして、ついでに flash 側でもすべてのハンドラにログ仕込んで、さぁ、どうなるか？&lt;br /&gt;&lt;br /&gt;logout 後にもう一度アクセスしに行って、そのときにエラーが返されてますね。上記の３回目のアクセスと同様と思われます。それが原因か？&lt;br /&gt;&lt;br /&gt;いくつか気持ち悪い問題がありますね。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;二回目のアクセスで削除されたはずの BwbsdybycCfB7kDRSLErnw に対して sessionDestroyed が発行されるという問題。&lt;/li&gt;&lt;li&gt;二回目のアクセスで BwbsdybycCfB7kDRSLErnw のセッションを削除したのに、オンメモリ上の FlexClient からは情報が削除されていない。&lt;/li&gt;&lt;li&gt;開発環境では発生せずGAE環境だけで発生する。&lt;/li&gt;&lt;/ul&gt;ひとまず、一つ目の問題について、専用のテストプログラムを作成し、開発環境とGAE環境で動作させて見ることにします。&lt;br /&gt;&lt;br /&gt;ローカルだと IllegalStateException で落ちますが、sessionDestroyedのハンドラは呼ばれました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;結局&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;振り返ってみると、調査開始時にはずいぶん勘違いがあったなぁ。&lt;br /&gt;インメモリのリポジトリって何だよｗｗｗ&lt;br /&gt;&lt;br /&gt;という感じで、上記からけっこう激しく試行錯誤した挙句、以下に落ち着きました。&lt;br /&gt;&lt;br /&gt;flex.messaging.client.FlexClient クラスの registerFlexSession(FlexSession) メソッドについて、以下のように修正します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public void registerFlexSession(FlexSession session)&lt;br /&gt;{&lt;br /&gt;    if (sessions.addIfAbsent(session))&lt;br /&gt;    {&lt;br /&gt;        session.addSessionDestroyedListener(this);&lt;br /&gt;        session.registerFlexClient(this);&lt;br /&gt;    }&lt;br /&gt;    // for session serialization&lt;br /&gt;    else if (session.getFlexClients().isEmpty())&lt;br /&gt;    {&lt;br /&gt;        session.addSessionDestroyedListener(this);&lt;br /&gt;        session.registerFlexClient(this);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(´・ω・`) しかし、稀に重複検出の例外が起きるのです。&lt;br /&gt;&lt;br /&gt;ログを見る限り、サーバ上では、logout メッセージ でセッションを破棄し、, disconnect メッセージで再度セッションを生成しするのですが、次のログイン前の ping で HTTP レベルのセッションが取得できないことがあるようです。&lt;br /&gt;&lt;br /&gt;2,3秒間隔で行うとこの問題は発生しません。&lt;br /&gt;&lt;br /&gt;GAEではセッション情報を必ずデータストアから取得するようなので、データストア側で遅延があるのであれば、セッションを取得できないのは納得できます（TODO:要調査）。しかし、それだけでは問題にはなりません。なぜ以前のセッション情報として格納されていた FlexClient の情報が復活しているかということです。FlexClient は実際にはシリアライズされるわけではなく毎回復元されるものなので、以前の情報が残っていることはありえません。となると、この仮定が間違っているのか、ほかに見落としている点があるかのどちらかということになります（TODO:要調査）。&lt;br /&gt;&lt;br /&gt;まぁ、今のところはログアウト後に速攻でログインしない限り発生しないので、しばらくは放置しようかと思います。&lt;br /&gt;&lt;br /&gt;(´・ω・`) GAE環境は調査に時間がかかりすぎるのねん、、、。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-943228571079297311?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/943228571079297311/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/login-sessionduplicate.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/943228571079297311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/943228571079297311'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/login-sessionduplicate.html' title='作業ログ：login機能使用時の SessionDuplicate 問題'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5303399703114327689</id><published>2010-04-17T02:27:00.000+09:00</published><updated>2010-04-17T02:27:47.109+09:00</updated><title type='text'>GAE 環境につないだ Flex クライアントを FlexBuilder からデバッグする方法</title><content type='html'>Flash のクライアントを持つアプリケーションを Google App Engine 上で開発する場合、FlashBuilder 上でデバッグモードで動作するクライアントと GAE をつなぎたくなります。&lt;br /&gt;&lt;br /&gt;そのような場合は、以下の手順で対応可能です。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;FlashBuilder のプロジェクト側で、GAE のパスを Root URL に設定する。&lt;/li&gt;&lt;li&gt;デバッグモードでクライアントアプリを起動する。 &lt;/li&gt;&lt;/ul&gt;以上。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5303399703114327689?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5303399703114327689/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gae-flex-flexbuilder.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5303399703114327689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5303399703114327689'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gae-flex-flexbuilder.html' title='GAE 環境につないだ Flex クライアントを FlexBuilder からデバッグする方法'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2135761644645818510</id><published>2010-04-17T01:47:00.004+09:00</published><updated>2010-04-17T02:19:00.445+09:00</updated><title type='text'>作業ログ：GAE/J + BlazeDS 4 環境について考えてみた。</title><content type='html'>以下、GAE/J + BlazeDS 4 環境について考えてみた作業ログ。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;方針&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;以前、GAE 上で普通に remoting や messaging をしようと思ったところ&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-duplicatesessiondetected.html"&gt;GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題&lt;/a&gt;に突き当たりました。また、security 機能を利用しようとした際には&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds3-httpsessionlistener.html"&gt;後GAE/J + BlazeDS3 環境の HttpSessionListener 問題&lt;/a&gt;に突き当たりました。&lt;br /&gt;&lt;br /&gt;これらの経緯を考えると、今後も多くの問題に突き当たることが考えられます。これより先に進むのであれば、それなりの覚悟が必要になります。しかし、オープンソースのソフトウェアである限り、手詰まりに可能性が低く、最終的に詰むというリスクは低く抑えられています。これはやるしかないでしょう。&lt;br /&gt;&lt;br /&gt;となると、どこまでやるかという問題がありますが、自分たちが必要な機能についてはすべて自分たちで理解したうえでコントロールするというところが落としどころかとおもいます。具体的には、GAE 上で動作すればよく、まずはロールなしのセッションレベルの認証ができればいいし、通常の AMF で remoting ができればOKです。今後メッセージングも必要になるかもしれないとか、GAE上なのでストリーミングが必要になることは当面ありえないだろうとか。そんな感じです。少なくともその時点で必要な機能かつ問題のあるソースはすべて把握しておく必要があり、そのためには全体の構成と主要なクラスについては、ソースレベルで完全に把握する必要があります。&lt;br /&gt;&lt;br /&gt;(｀・ω・´) さて、どこから手をつけようか？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;まずは環境整理&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;これから作業をする上で、クリーンな環境を維持することは重要になります。そのため、環境整備の手順を整理しておく必要があります。&lt;br /&gt;&lt;br /&gt;ということで、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4.html"&gt;GAE/J + BlazeDS 4 環境の構築&lt;/a&gt;に内容をまとめました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題を再び追いながら情報収集&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Servletのバージョン&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS は Servlet2.3以上（TODO:出典明記）&lt;br /&gt;GAE は Servlet2.4（TODO:出典明記）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Application Lifecycle Event&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS 4 では web.xml で以下のように flex.messaging.HttpFlexSession を Application Lifecycle Event のリスナーとして設定しています。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;!-- Http Flex Session attribute and binding listener support --&amp;gt;&lt;br /&gt;&amp;lt;listener&amp;gt;&lt;br /&gt;  &amp;lt;listener-class&amp;gt;flex.messaging.HttpFlexSession&amp;lt;/listener-class&amp;gt;&lt;br /&gt;&amp;lt;/listener&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;このクラスは以下のインタフェースを実装しています。&lt;br /&gt;&lt;pre class="prettyprint"&gt;javax.servlet.http.HttpSessionAttributeListener&lt;br /&gt;javax.servlet.http.HttpSessionBindingListener&lt;br /&gt;javax.servlet.http.HttpSessionListener&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;HttpFlexSession が実装するリスナーのメソッドと、実行内容の概要を以下に示します。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;void valueBound(HttpSessionBindingEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;何もしません。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;void valueUnbound(HttpSessionBindingEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;HttpSessionの属性が削除された場合に flexSession.superInvalidate() を呼びます。。&lt;/li&gt;&lt;li&gt;isHttpSessionListener が true の場合、つまり通常は何もしません。&lt;/li&gt;&lt;li&gt;&lt;strike&gt;GAE 環境では、呼ばれたら実行されるはずです。&lt;/strike&gt;（追記：GAE環境でも実行されません）&lt;/li&gt;&lt;li&gt;属性が削除されただけでなぜ flexSession.superInvalidate() を呼ぶ必要があるのか？&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;void sessionCreated(HttpSessionEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;isHttpSessionListener フラグを true にします。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;void sessionDestroyed(HttpSessionEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;HttpSessionが削除されたらFlexSessionも削除されるようにします。&lt;/li&gt;&lt;li&gt;attributeRemovedイベントよりよりこちらが先に行われる場合の対策として、attributeRemovedこちらからもattributeRemovedを呼びに行っています。&lt;/li&gt;&lt;li&gt;void attributeAdded(HttpSessionBindingEvent event)&lt;/li&gt;&lt;li&gt;属性変更イベント名が"__flexSession"の場合のみ、flexSession.notifyAttributeBound(name, value)とnotifyAttributeAdded(name, value)を呼びに行く。&lt;/li&gt;&lt;li&gt;必要な属性だけコピーするということですね。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;void attributeRemoved(HttpSessionBindingEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;属性変更イベント名が"__flexSession"の場合のみ、flexSession.notifyAttributeUnbound(name, value) と flexSession.notifyAttributeRemoved(name, value) を呼びに行く。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;void attributeReplaced(HttpSessionBindingEvent event)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;属性変更イベント名が"__flexSession"の場合のみ、flexSession.notifyAttributeUnbound(name, value) と flexSession.notifyAttributeReplaced(name, value) と flexSession.notifyAttributeBound(name, newValue) を呼びに行く。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;ログを仕込んで、ローカル環境で実行してみました。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 初回&lt;br /&gt;MessageBrokerServlet#service() : begin&lt;br /&gt;HttpFlexSession#sessionCreated() : sessionId = 13x3l8s1hg56a&lt;br /&gt;HttpFlexSession#valueBound() : name = __flexSession : sessionId = 13x3l8s1hg56a&lt;br /&gt;HttpFlexSession#attributeAdded() : name = __flexSession : sessionId = 13x3l8s1hg56a&lt;br /&gt;MessageBrokerServlet#service() : end&lt;br /&gt;MessageBrokerServlet#service() : begin&lt;br /&gt;EchoService#echo() : sessionId = 13x3l8s1hg56a&lt;br /&gt;MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;// 二回目&lt;br /&gt;MessageBrokerServlet#service() : begin&lt;br /&gt;EchoService#echo() : sessionId = 1l72bdhrrlfvy&lt;br /&gt;MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/pre&gt;デバッガでも追ったところ、Sevletコンテナ側から正しく呼び出されていました。（正しく動作するということが、GAE的にはバグなんですね。）&lt;br /&gt;&lt;br /&gt;初回は２回serviceが呼ばれてますね。TODO：要調査&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;今度はサーバ側にデプロイして同様のことをしてみます。&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 一回目のアクセス（例のセッション重複で失敗）&lt;br /&gt;04-15 02:56PM 55.052 MessageBrokerServlet#service() : begin&lt;br /&gt;04-15 02:56PM 55.283 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;04-15 02:56PM 55.555 MessageBrokerServlet#service() : begin&lt;br /&gt;04-15 02:56PM 55.587 HttpFlexSession#sessionDestroyed() : sessionId = CRls4b-kT7-DCbJSV6yFbw&lt;br /&gt;04-15 02:56PM 55.587 FlexSession#invalidate()&lt;br /&gt;04-15 02:56PM 55.870 HttpFlexSession#sessionDestroyed() : sessionId = CRls4b-kT7-DCbJSV6yFbw&lt;br /&gt;04-15 02:56PM 55.961 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;// 二回目のアクセス（成功）&lt;br /&gt;04-15 03:17PM 18.307 MessageBrokerServlet#service() : begin&lt;br /&gt;04-15 03:17PM 18.526 HttpFlexSession#sessionCreated() : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 18.527 HttpFlexSession#valueBound() : name = __flexSession : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 18.527 HttpFlexSession#attributeAdded() : name = __flexSession : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 19.251 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;04-15 03:17PM 19.719 MessageBrokerServlet#service() : begin&lt;br /&gt;04-15 03:17PM 19.790 HttpFlexSession#sessionDestroyed() : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 19.790 FlexSession#invalidate()&lt;br /&gt;04-15 03:17PM 19.790 HttpFlexSession#valueUnbound() : NOP : name = __flexSession : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 19.790 HttpFlexSession#attributeRemoved() : name = __flexSession : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 19.889 HttpFlexSession#sessionDestroyed() : sessionId = V1pWQsjzwKuDKYUS5IlpZg&lt;br /&gt;04-15 03:17PM 19.976 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;04-15 03:20PM 00.169 MessageBrokerServlet#service() : begin&lt;br /&gt;04-15 03:20PM 00.465 HttpFlexSession#sessionCreated() : sessionId = 0Gqlzdy3J_I2n281ANfQmQ&lt;br /&gt;04-15 03:20PM 00.466 HttpFlexSession#valueBound() : name = __flexSession : sessionId = 0Gqlzdy3J_I2n281ANfQmQ&lt;br /&gt;04-15 03:20PM 00.466 HttpFlexSession#attributeAdded() : name = __flexSession : sessionId = 0Gqlzdy3J_I2n281ANfQmQ&lt;br /&gt;04-15 03:20PM 02.255 EchoService#echo() : sessionId = 0Gqlzdy3J_I2n281ANfQmQ&lt;br /&gt;04-15 03:20PM 02.375 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;おや？&lt;br /&gt;&lt;br /&gt;HttpFlexSession#sessionCreated() は、Servletコンテナのライフサイクルイベントとして以外には絶対に呼ばれないということはソースから確認できます。なのに呼ばれているということは、GAE上でもライフサイクルイベントが呼ばれるということですね。&lt;br /&gt;&lt;br /&gt;ということで、GAE/J 環境の Application Lifecycle Listener の実験をしてみたところ、やはり GAE 上でも&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-application-lifecycle-listener.html"&gt;ライフサイクルイベント&lt;/a&gt;は呼ばれるようです。&lt;br /&gt;&lt;br /&gt;ということで、今度は上記テストのリスナーをコンテナに配備して、埋め込んだデバッグ情報を一度ほぼクリアにしてから、再度動作検証をしていくことにします。ブラウザのcookieは事前に削除しておきます。念のため、_ah_SESSION 情報も削除しておきます。関係ないと思いつつも&lt;a href="http://www.macromedia.com/support/documentation/jp/flashplayer/help/settings_manager06.html"&gt;Web サイトのプライバシー設定パネル&lt;/a&gt;から flash のローカルクッキーも削除します。&lt;br /&gt;&lt;br /&gt;開発サーバでの実行&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 一回目のアクセス&lt;br /&gt;sessionCreated : id = 1snep0z5nb1pd&lt;br /&gt;attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@14a18d&lt;br /&gt;EchoService#echo() : sessionId = 1snep0z5nb1pd&lt;br /&gt;&lt;br /&gt;// 二回目のアクセス&lt;br /&gt;EchoService#echo() : sessionId = 1snep0z5nb1pd&lt;br /&gt;&lt;br /&gt;// 三回目のアクセス&lt;br /&gt;EchoService#echo() : sessionId = 1snep0z5nb1pd&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;本番サーバでの実行&lt;br /&gt;&lt;pre class="prettyprint"&gt;// UIから一回目のアクセス /messagebroker/amf&lt;br /&gt;04-16 05:16AM 04.683 sessionCreated : id = EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;04-16 05:16AM 04.690 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@165547d&lt;br /&gt;// UIから一回しかアクセスしていないけどなぜか二回目のアクセスが行われている。/messagebroker/amf;jsessionid=EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;04-16 05:16AM 05.584 sessionDestroyed : id = EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;04-16 05:16AM 05.584 attributeRemoved : name = __flexSession, value = flex.messaging.HttpFlexSession@165547d&lt;br /&gt;04-16 05:16AM 05.861 sessionDestroyed : id = EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;【結果】Detected duplicate HTTP-based FlexSessions で失敗&lt;br /&gt;&lt;br /&gt;// UIから二回目のアクセス /messagebroker/amf;jsessionid=EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;04-16 05:18AM 19.795 sessionCreated : id = uqSuxURP-RXL1hsdcp2c0A&lt;br /&gt;04-16 05:18AM 19.795 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@34a1c8&lt;br /&gt;04-16 05:18AM 19.830 sessionDestroyed : id = EmVdv905Ogr0kGuoKMfVHA&lt;br /&gt;04-16 05:18AM 19.850 sessionDestroyed : id = uqSuxURP-RXL1hsdcp2c0A&lt;br /&gt;04-16 05:18AM 19.850 attributeRemoved : name = __flexSession, value = flex.messaging.HttpFlexSession@34a1c8&lt;br /&gt;04-16 05:18AM 20.008 sessionCreated : id = SaKtj72k_5tVABGvK7vOAg&lt;br /&gt;04-16 05:18AM 20.008 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@1e514a9&lt;br /&gt;【結果】Detected duplicate HTTP-based FlexSessions で失敗）&lt;br /&gt;&lt;br /&gt;// 三回目のアクセス /messagebroker/amf;jsessionid=SaKtj72k_5tVABGvK7vOAg&lt;br /&gt;04-16 05:20AM 34.078 EchoService#echo() : sessionId = SaKtj72k_5tVABGvK7vOAg &lt;br /&gt;【結果】成功&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;現状のデータからの考察&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;開発環境上の動作は、意図したとおりのものです。しかし、本番環境上の動作は、意図とはかなり異なる動きをしています。&lt;br /&gt;&lt;br /&gt;まず flash クライアントからの初回のアクセスが2回に分けて行われています。これ自体理由が分からないので調査したいところですが、何回アクセスがきたところで、セッション管理に影響するというのは問題です。まずは最初のアクセスからソースを追いつつ、仮定を立ててみます。&lt;br /&gt;&lt;br /&gt;・仮定１：初回アクセスの２回目のHTTP呼び出しにて、BaseHTTPEndpoint#setupFlexClient() の432行で DuplicateSessionException が throw されている。&lt;br /&gt;・仮定２：上記は同クラス400行にてflexClient.getFlexSessions()のサイズを2として受け取っている。&lt;br /&gt;・仮定３：仮定２の直接の原因は、FlexClient の 1119 行目で複数の FlexSession が登録されてしまうこと。&lt;br /&gt;&lt;br /&gt;とりあえず、ここまでを確認してみたところ、仮定１，２は正解。仮定３は可能性ありです。二回目のアクセスで、一回目で生成された FlexClient を使用しているのであれば、仮定３はほぼクロです。&lt;br /&gt;&lt;br /&gt;ということで、ログを仕込んで再実行。&lt;br /&gt;&lt;br /&gt;開発環境&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 初回（成功）&lt;br /&gt;04-16 08:52AM 37.279 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: MessagingConfiguration#createFlexClientManager() : FlexClientManager is created with problem!&lt;br /&gt;04-16 08:52AM 38.068 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: MessageBrokerServlet#service() : begin&lt;br /&gt;04-16 08:52AM 38.322 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: sessionCreated : id = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:52AM 38.325 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@187e184&lt;br /&gt;04-16 08:52AM 38.644 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:52AM 38.644 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:52AM 38.659 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: EchoService#echo() : sessionId = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:52AM 38.705 [beyondseeker-mixi-01/1.341297705342737136].&lt;stderr&gt;: MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/stderr&gt;&lt;/pre&gt;&lt;br /&gt;本番環境&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 初回（成功）&lt;br /&gt;04-16 08:52AM 37.279 MessagingConfiguration#createFlexClientManager() : FlexClientManager is created with problem!&lt;br /&gt;04-16 08:52AM 38.068 MessageBrokerServlet#service() : begin&lt;br /&gt;04-16 08:52AM 38.322 sessionCreated : id = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:52AM 38.325 attributeAdded : name = __flexSession, value = flex.messaging.HttpFlexSession@187e184&lt;br /&gt;04-16 08:52AM 38.644 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:52AM 38.644 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:52AM 38.659 EchoService#echo() : sessionId = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:52AM 38.705 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;// 二回目（失敗）&lt;br /&gt;04-16 08:53AM 39.110 MessageBrokerServlet#service() : begin&lt;br /&gt;04-16 08:53AM 39.112 flexClient is retrieved from in-memory flexClients repository.&lt;br /&gt;04-16 08:53AM 39.112 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:53AM 39.112 sessions.size() = 2&lt;br /&gt;04-16 08:53AM 39.112 sessionId = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:53AM 39.112 sessionId = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:53AM 39.112 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@92de02&lt;br /&gt;04-16 08:53AM 39.128 sessionDestroyed : id = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:53AM 39.129 attributeRemoved : name = __flexSession, value = flex.messaging.HttpFlexSession@187e184&lt;br /&gt;04-16 08:53AM 39.250 sessionDestroyed : id = zpE2j7OXspDhdA1-960ZCg&lt;br /&gt;04-16 08:53AM 39.343 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;開発環境、本番環境に関わらず、二回目のアクセスはオンメモリの情報を取得しています。&lt;br /&gt;&lt;br /&gt;FlexClientManager では、取得できればオンメモリのものを使用し、できなければサーバ上のものを使用するので、GAE 環境でも問題なさそうです。&lt;br /&gt;&lt;br /&gt;そして、問題なのは、同じ sessionId を二箇所登録している部分です。これは以前&lt;br /&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-duplicatesessiondetected.html"&gt;GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題&lt;/a&gt;で調べたとおりなので、同様に対処します。&lt;br /&gt;&lt;br /&gt;本番環境&lt;br /&gt;&lt;pre class="prettyprint"&gt;// 初回（成功）&lt;br /&gt;04-16 09:38AM 51.550 MessagingConfiguration#createFlexClientManager() : FlexClientManager is created with problem!&lt;br /&gt;04-16 09:38AM 52.813 MessageBrokerServlet#service() : begin&lt;br /&gt;04-16 09:38AM 53.228 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@1bb60ad&lt;br /&gt;04-16 09:38AM 53.228 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@1bb60ad&lt;br /&gt;04-16 09:38AM 53.250 EchoService#echo() : sessionId = IHEyAtViGH3J9Et5RT48mg&lt;br /&gt;04-16 09:38AM 53.300 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;br /&gt;// 二回目（成功）&lt;br /&gt;04-16 09:39AM 49.765 MessageBrokerServlet#service() : begin&lt;br /&gt;04-16 09:39AM 49.767 flexClient is retrieved from in-memory flexClients repository.&lt;br /&gt;04-16 09:39AM 49.767 FlexClient#registerFlexSession() : httpClient = flex.messaging.client.FlexClient@1bb60ad&lt;br /&gt;04-16 09:39AM 49.767 EchoService#echo() : sessionId = IHEyAtViGH3J9Et5RT48mg&lt;br /&gt;04-16 09:39AM 49.769 MessageBrokerServlet#service() : end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;という感じで、GAE/J 上でも最低限使える環境になったかなと思います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2135761644645818510?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2135761644645818510/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4_17.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2135761644645818510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2135761644645818510'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4_17.html' title='作業ログ：GAE/J + BlazeDS 4 環境について考えてみた。'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-138347451849196726</id><published>2010-04-16T08:55:00.003+09:00</published><updated>2010-04-16T09:03:33.262+09:00</updated><title type='text'>GAE/J 環境の Application Lifecycle Listener の実験</title><content type='html'>最近、GAE/J が Application Lifecycle Listener に対応していないという話を聞きました。現在 GAE 上で BlazeDS を動かそうとしている身としては、これはぜひともはっきりさせておきたいネタです。 &lt;br /&gt;&lt;br /&gt;ということで、ひとまず BlazeDS が使用している下記の３つのイベントリスナインタフェースを対象に実験してみました。&lt;br /&gt;&lt;pre class="prettyprint"&gt;import javax.servlet.http.HttpSessionAttributeListener;&lt;br /&gt;import javax.servlet.http.HttpSessionBindingListener;&lt;br /&gt;import javax.servlet.http.HttpSessionListener;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;開発環境上での実行結果&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;sessionCreated : id = 16es70wx6934m&lt;br /&gt;attributeAdded : name = foo, value = bar&lt;br /&gt;attributeReplaced : name = foo, value = bar&lt;br /&gt;attributeRemoved : name = foo, value = hoge&lt;br /&gt;valueBound : name = fumyo, value = null&lt;br /&gt;attributeAdded : name = fumyo, value = listenertest.ApplicationLifecycleListener@1977b9b&lt;br /&gt;valueUnbound : name = fumyo, value = null&lt;br /&gt;attributeRemoved : name = fumyo, value = listenertest.ApplicationLifecycleListener@1977b9b&lt;br /&gt;sessionDestroyed : id = 16es70wx6934m&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;本番環境での実行結果&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;sessionCreated : id = 8xj_3ZWLJhJRl4nrVAzsCw&lt;br /&gt;attributeAdded : name = foo, value = bar&lt;br /&gt;attributeReplaced : name = foo, value = bar&lt;br /&gt;attributeRemoved : name = foo, value = hoge&lt;br /&gt;valueBound : name = fumyo, value = null&lt;br /&gt;attributeAdded : name = fumyo, value = listenertest.ApplicationLifecycleListener@13b625b&lt;br /&gt;valueUnbound : name = fumyo, value = null&lt;br /&gt;attributeRemoved : name = fumyo, value = listenertest.ApplicationLifecycleListener@13b625b&lt;br /&gt;sessionDestroyed : id = 8xj_3ZWLJhJRl4nrVAzsCw&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;なんと、GAE/J 上で、上記のリスナーは完全に動作しているようです。(｀・ω・´)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;テスト用サーブレットのソース&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package listenertest;&lt;br /&gt;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;&lt;br /&gt;import javax.servlet.http.HttpServlet;&lt;br /&gt;import javax.servlet.http.HttpServletRequest;&lt;br /&gt;import javax.servlet.http.HttpServletResponse;&lt;br /&gt;import javax.servlet.http.HttpSession;&lt;br /&gt;&lt;br /&gt;@SuppressWarnings("serial")&lt;br /&gt;public class ListenertestServlet extends HttpServlet {&lt;br /&gt; public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {&lt;br /&gt;  HttpSession session = req.getSession(true);&lt;br /&gt;  session.setAttribute("foo", "bar");&lt;br /&gt;  session.setAttribute("foo", "hoge");&lt;br /&gt;  session.removeAttribute("foo");&lt;br /&gt;  session.setAttribute("fumyo", new ApplicationLifecycleListener());&lt;br /&gt;  session.removeAttribute("fumyo");&lt;br /&gt;  session.invalidate();&lt;br /&gt;  resp.setContentType("text/plain");&lt;br /&gt;  resp.getWriter().println("Test complete!");&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;テスト用リスナーのソース&lt;/b&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;package listenertest;&lt;br /&gt;&lt;br /&gt;import javax.servlet.http.HttpSessionAttributeListener;&lt;br /&gt;import javax.servlet.http.HttpSessionBindingEvent;&lt;br /&gt;import javax.servlet.http.HttpSessionBindingListener;&lt;br /&gt;import javax.servlet.http.HttpSessionEvent;&lt;br /&gt;import javax.servlet.http.HttpSessionListener;&lt;br /&gt;&lt;br /&gt;public class ApplicationLifecycleListener implements HttpSessionListener, HttpSessionAttributeListener, HttpSessionBindingListener {&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void sessionCreated(HttpSessionEvent event) {&lt;br /&gt;  System.err.println("sessionCreated : id = " + event.getSession().getId());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void sessionDestroyed(HttpSessionEvent event) {&lt;br /&gt;  System.err.println("sessionDestroyed : id = " + event.getSession().getId());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void attributeAdded(HttpSessionBindingEvent event) {&lt;br /&gt;  System.err.println("attributeAdded : name = " + event.getName() + ", value = " + event.getValue());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void attributeRemoved(HttpSessionBindingEvent event) {&lt;br /&gt;  System.err.println("attributeRemoved : name = " + event.getName() + ", value = " + event.getValue());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void attributeReplaced(HttpSessionBindingEvent event) {&lt;br /&gt;  System.err.println("attributeReplaced : name = " + event.getName() + ", value = " + event.getValue());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void valueBound(HttpSessionBindingEvent event) {&lt;br /&gt;  System.err.println("valueBound : name = " + event.getName() + ", value = " + event.getValue());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public void valueUnbound(HttpSessionBindingEvent event) {&lt;br /&gt;  System.err.println("valueUnbound : name = " + event.getName() + ", value = " + event.getValue());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-138347451849196726?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/138347451849196726/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-application-lifecycle-listener.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/138347451849196726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/138347451849196726'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-application-lifecycle-listener.html' title='GAE/J 環境の Application Lifecycle Listener の実験'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1664070569915004804</id><published>2010-04-16T03:51:00.006+09:00</published><updated>2010-04-17T03:16:03.035+09:00</updated><title type='text'>GAE/J + BlazeDS 4 環境の構築</title><content type='html'>今回は GAE/J(Google App Engine Java) と BlazeDS 4 環境の構築方法についてまとめたいと思います。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;BlazeDS 3 と同様の環境を構築&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;基本的な環境は BlazeDS 3 の時とほぼ同じです。そのため、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-flash-builder.html"&gt;GAE/J + BlazeDS + Flash Builder 環境の構築&lt;/a&gt;と同様の手順で作業を行います。&lt;br /&gt;&lt;br /&gt;BlazeDS の jar ファイルを持ってくる箇所は行わなくてもかまいません。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;BlazeDS 4 のビルド&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソースのチェックアウト&lt;/li&gt;&lt;ul&gt;&lt;li&gt;BlazeDS4系は trunk 以下に配置されています。（4.16.2010現在）&lt;/li&gt;&lt;li&gt;ソースは http://opensource.adobe.com/svn/opensource/blazeds/trunk からチェックアウトします。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;必要なツール&lt;/li&gt;&lt;ul&gt;&lt;li&gt;JDK と ant をそろえましょう。&lt;/li&gt;&lt;li&gt;ant には Ant-Contrib が必要になるため、http://ant-contrib.sourceforge.net/ から取得します（現在の最新は ant-contrib-1.0b2-bin.zip 等）。それを展開後、ant-contrib.jar を ant の lib フォルダ以下にコピーします。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;ビルド&lt;/li&gt;&lt;ul&gt;&lt;li&gt;trunk 直下で ant main を実行するとビルドが開始されます。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;BlazeDS 4 の jar ファイルの取得&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS 4 のビルドが完了したら、冒頭で準備した Web アプリケーションの WEB-INF/lib 以下に、以下のファイルをコピーします。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;trunk/lib/flex-messaging-core.jar&lt;/li&gt;&lt;li&gt;trunk/lib/flex-messaging-common.jar&lt;/li&gt;&lt;li&gt;trunk/lib/flex-messaging-remoting.jar&lt;/li&gt;&lt;li&gt;trunk/lib/flex-rds-server.jar&lt;/li&gt;&lt;li&gt;trunk/lib/xalan.jar&lt;/li&gt;&lt;li&gt;trunk/lib/xercesImpl.jar&lt;/li&gt;&lt;/ul&gt;※必要に応じて必要なファイルをコピーしましょう。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RDS環境の設定&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;web.xml に以下の設定を追加します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;  &amp;lt;display-name&amp;gt;RDSDispatchServlet&amp;lt;/display-name&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;RDSDispatchServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;servlet-class&amp;gt;flex.rds.server.servlet.FrontEndServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;  &amp;lt;init-param&amp;gt;&lt;br /&gt;    &amp;lt;param-name&amp;gt;useAppserverSecurity&amp;lt;/param-name&amp;gt;&lt;br /&gt;    &amp;lt;param-value&amp;gt;false&amp;lt;/param-value&amp;gt;&lt;br /&gt;  &amp;lt;/init-param&amp;gt;&lt;br /&gt;  &amp;lt;load-on-startup&amp;gt;10&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet-mapping id="RDS_DISPATCH_MAPPING"&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;RDSDispatchServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;url-pattern&amp;gt;/CFIDE/main/ide.cfm&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;これで、GAE開発環境では正しく動作し、GAE本番環境では 1/3 の確率で動作するアプリが完成（のはず）。この問題は、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-flash-builder.html"&gt;GAE/J + BlazeDS + Flash Builder 環境の構築&lt;/a&gt;に書かれているような感じで FlexSession に equals()メソッドと hashCode() メソッドをつけると回避できます。 &lt;br /&gt;&lt;br /&gt;以上。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1664070569915004804?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1664070569915004804/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1664070569915004804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1664070569915004804'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-4.html' title='GAE/J + BlazeDS 4 環境の構築'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1749735241855651571</id><published>2010-04-16T00:04:00.049+09:00</published><updated>2010-04-16T01:33:32.323+09:00</updated><title type='text'>作業ログ：BlazeDS4調査</title><content type='html'>以下、BlazeDS4調査の作業ログです。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;これまで&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS系について、今まで以下のような作業を行ってきました。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-flash-builder.html"&gt;GAE/J + BlazeDS + Flash Builder 環境の構築&amp;nbsp; &lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-security.html"&gt;GAE/J + BlazeDS 環境の Security 設定&amp;nbsp; &lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-duplicatesessiondetected.html"&gt;GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題&amp;nbsp; &lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds3-httpsessionlistener.html"&gt;GAE/J + BlazeDS3 環境の HttpSessionListener 問題 &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;ここまでわかってきたことは、以下のようなことです。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BlazeDS3 を GAE 上で運用するにはいろいろと痛い問題がある。&lt;/li&gt;&lt;li&gt;独自に解決したとしても &lt;a href="http://bugs.adobe.com/jira/browse/BLZ-444"&gt;BLZ-444&lt;/a&gt; により、BlazeDS 3系 にバックポートできる可能性はほぼ無い。&lt;/li&gt;&lt;li&gt;逆に、&lt;a href="http://bugs.adobe.com/jira/browse/BLZ-444"&gt;BLZ-444&lt;/a&gt; により、次世代以降の BlazeDS にて GAE をサポートする意思はあると考えられる。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;上記からの考察。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BlazeDS3系と今後付き合うメリットは低い。&lt;/li&gt;&lt;li&gt;BlazeDS4系は未知数だが、BlazeDS3だって現状でソースをほとんど読んでるんだから、大差ない。&lt;/li&gt;&lt;li&gt;BlazeDS4系は、開発中なだけに、こちらでの要望が通る可能性が高い。&lt;/li&gt;&lt;li&gt;BlazeDS4系は、データ中心開発系でにぎわい始めてきているので、タイミング的にも悪くない。&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;結論&lt;br /&gt;&lt;ul&gt;&lt;li&gt;将来的な選択肢は、BlazeDS4で行くか、BlazeDSを捨てるか。&lt;/li&gt;&lt;li&gt;BlazeDS4系は、&lt;a href="http://bugs.adobe.com/jira/browse/BLZ-444"&gt;BLZ-444&lt;/a&gt; があることと、現在開発中なのでこちらの意見が通りやすいという点から、これに賭けてみることにする。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;BlazeDS4系調査&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BlazeDS4系のドキュメントは&lt;a href="http://opensource.adobe.com/wiki/display/blazeds/Developer+Documentation"&gt;ここ&lt;/a&gt;からたどれる。&lt;/li&gt;&lt;li&gt;&lt;a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS+4.0+Release+Notes"&gt;BlazeDS 4.0 Release Notes&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;data-centric development features of Flash Builder 4 というのが、LCDSを用いた開発を指しているんですね。確かに&lt;a href="http://coenraets.org/blog/2010/03/video-using-the-flash-builder-4-data-wizards-with-blazeds-4/"&gt;こんな感じ&lt;/a&gt;で便利だ。&lt;/li&gt;&lt;li&gt;&lt;a href="http://coenraets.org/blog/2010/03/new-spring-blazeds-test-drive-available-flex-4-blazeds-4-and-spring-blazeds-integration-1-0-3/"&gt;New Spring / BlazeDS Test Drive Available: Flex 4, BlazeDS 4, and Spring / BlazeDS Integration 1.0.3&lt;/a&gt; も役に立ちそう。後でチェックしよう。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS+4.0+Installation+Guide"&gt;BlazeDS 4.0 Installation Guide&lt;/a&gt;&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;ぱっと見たところ、BlazeDS3とあまり変わらなそう。ということで試してみることにした。&lt;/li&gt;&lt;li&gt;source tree は &lt;a href="http://opensource.adobe.com/svn/opensource/blazeds/"&gt;http://opensource.adobe.com/svn/opensource/blazeds/&lt;/a&gt; から見れる。&lt;/li&gt;&lt;li&gt;基本的に、既存の3.2のプロジェクトに対して、&lt;a href="http://opensource.adobe.com/wiki/display/blazeds/BlazeDS+4.0+Installation+Guide#BlazeDS4.0InstallationGuide-UpgradingBlazeDS3.2toversion4.0"&gt;Upgrading BlazeDS 3.2 to version 4.0&lt;/a&gt; の方法を適用すればよさそうだ。&lt;/li&gt;&lt;li&gt;&lt;a href="http://forums.adobe.com/community/opensource/blazeds/commits"&gt;コ ミット情報のフォーラム&lt;/a&gt;があるんですね。便利だ。 &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;BlazeDS4のコンパイル &lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ソースは、&lt;a href="http://opensource.adobe.com/svn/opensource/blazeds/trunk"&gt;http://opensource.adobe.com/svn/opensource/blazeds/trunk&lt;/a&gt; からチェックアウト。300MB以上あるので結構時間がかかります。&lt;/li&gt;&lt;li&gt;ビルド用のツールは ant っぽいですが、どのバージョンか不明。ということで、とりあえず 1.8.0 で試してみる。&lt;/li&gt;&lt;li&gt;build.xml をかるく見たところ、main というターゲットが全体的なビルドらしいので、実行してみた。見事に失敗。&lt;pre class="prettyprint"&gt;[taskdef] Could not load definitions from resource net/sf/antcontrib/antcontrib.properties. It could not be found.&lt;/pre&gt;ということで、antcontrib 入れなきゃだめっぽい。&lt;/li&gt;&lt;li&gt;http://ant-contrib.sourceforge.net/ に行って ant-contrib-1.0b2-bin.zip をダウンロードして、ant-contrib.jar を ant の lib フォルダ以下にコピーして、再チャレンジ。今度は成功。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;BlazeDS 3.2 のアプリを BlazeDS 4 に対応させる&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BlazeDS3.2のころの自分のプロジェクトファイルのバックアップを取り、変更を開始。&lt;/li&gt;&lt;li&gt;まず、BlazeDS3.2用に追加した jar ファイルをすべて削除。&lt;/li&gt;&lt;li&gt;BlazeDS3.2のソースにパッチを当てたものもすべて削除。&lt;/li&gt;&lt;li&gt;具体的にどの jar を追加すればよいかわからないので、とりあえず設定ファイルから先に手をつける。既存の WEB-INF/flex 以下の設定ファイルの名前に.oldをつけ、新規にBlazeDS4のサンプルの定義ファイルをコピー。両者を見比べながら変更しようとおもったが、特に変更する必要はなさそうなので、もとに戻す。&lt;/li&gt;&lt;li&gt;カスタム login command のコンパイルのため（AppServerLoginCommand クラス等が必要なため） flex-messaging-core.jar をコピーし、パスを通す。&lt;/li&gt;&lt;li&gt;flex.messaging.LocalizedException が無いため flex-messaging-common.jar  をコピーする。&lt;/li&gt;&lt;li&gt;flex.messaging.services.RemotingService が無いため flex-messaging-remoting.jar をコピーする。&lt;/li&gt;&lt;li&gt;これで、ローカルではあっさり動きました。&lt;/li&gt;&lt;li&gt;今度はGAE上にデプロイして試してみる。&lt;/li&gt;&lt;li&gt;見かけ上、BlazeDS 3.2 上で 起きた session の duplication 問題と、logoutをする際の Session 破棄時に HttpSessionListener が働かない問題とほぼ同様の動きをします。&lt;/li&gt;&lt;li&gt;ひとまず、基本的なインストールの作業はこれで終了とします。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;RDSを試してみる。&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://help.adobe.com/en_US/LiveCycleDataServicesES/3.1/Developing/WSc3ff6d0ea77859461172e0811f00f6e48e-8000Update.html"&gt;Using Adobe LiveCycle Data Services&lt;/a&gt; を読んでみた。&lt;/li&gt;&lt;li&gt;LiveCycle Data Services JAR files と 関連 JAR ファイルを WEB-INF/lib ディレクトリに入れる必要があるらしい。取り合えず flex-rds-server.jar が怪しいのでコピーしておく。&lt;/li&gt;&lt;li&gt;WEB-INF/flex 以下の設定ファイルの設定を書くらしい。&lt;br /&gt;MessageBrokerServlet の設定と session listener の設定を WEB-INF/web.xml に書くらしい。って、GAE だと session listener 使えないんだけど、、、。既にダメポな予感 (´・ω・`)&lt;/li&gt;&lt;li&gt;ここまで読んで、これは LiveCycle Data Services 全般の説明だということに気づく。BlazeDS3.2用のドキュメントを一通り読んでいるので、読まなくてもよさそう。ということで、data-centric development にのみフォーカスして情報を収集することにする。&lt;/li&gt;&lt;li&gt;&lt;a href="http://coenraets.org/blog/2010/03/flex-4-sample-application-using-a-java-back-end-blazeds-4-and-flash-builder-4-data-wizards/"&gt;Flex 4 Sample Application using a Java Back-End, BlazeDS 4 and Flash Builder 4 Data Wizards&lt;/a&gt; の &lt;a href="http://coenraets.org/downloads/flex-java-testdrive/flex-java-testdrive.zip"&gt;flex-java-testdrive.zip&lt;/a&gt; をダウンロードし、設定をパクることにする。&lt;/li&gt;&lt;li&gt;services-config.xmlの services 要素には&lt;pre class="prettyprint"&gt;&amp;lt;service class="flex.samples.util.DatabaseService" id="db" /&amp;gt;&lt;/pre&gt;を追加。&lt;/li&gt;&lt;li&gt;web.xml には次のような設定を追加。&lt;pre class="prettyprint"&gt;&amp;lt;servlet&amp;gt;&lt;br /&gt;  &amp;lt;display-name&amp;gt;RDSDispatchServlet&amp;lt;/display-name&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;RDSDispatchServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;servlet-class&amp;gt;flex.rds.server.servlet.FrontEndServlet&amp;lt;/servlet-class&amp;gt;&lt;br /&gt;  &amp;lt;init-param&amp;gt;&lt;br /&gt;    &amp;lt;param-name&amp;gt;useAppserverSecurity&amp;lt;/param-name&amp;gt;&lt;br /&gt;    &amp;lt;param-value&amp;gt;false&amp;lt;/param-value&amp;gt;&lt;br /&gt;  &amp;lt;/init-param&amp;gt;&lt;br /&gt;  &amp;lt;load-on-startup&amp;gt;10&amp;lt;/load-on-startup&amp;gt;&lt;br /&gt;&amp;lt;/servlet&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;servlet-mapping id="RDS_DISPATCH_MAPPING"&amp;gt;&lt;br /&gt;  &amp;lt;servlet-name&amp;gt;RDSDispatchServlet&amp;lt;/servlet-name&amp;gt;&lt;br /&gt;  &amp;lt;url-pattern&amp;gt;/CFIDE/main/ide.cfm&amp;lt;/url-pattern&amp;gt;&lt;br /&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;これでコンテナを実行。Flex Builder 4 の Connect to Data/Service のところから接続しに行ってみる。あっさりつなぎこめました。&lt;/li&gt;&lt;li&gt;これでいろいろ実験しようとおもった矢先、Flush Builder 4 が突然不調に。デザインモードを開こうとおもうといきなり VM が落ちる状況に(´・ω・`)&lt;/li&gt;&lt;li&gt;この件は、FlashBuilder4の再インストールで解決。&lt;/li&gt;&lt;/ul&gt;これでやっと、BlazeDS4のGAE対応作業の前準備ができました。&lt;br /&gt;&lt;ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1749735241855651571?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1749735241855651571/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds4.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1749735241855651571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1749735241855651571'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds4.html' title='作業ログ：BlazeDS4調査'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4919012929761154827</id><published>2010-04-15T10:01:00.005+09:00</published><updated>2010-04-16T08:55:38.275+09:00</updated><title type='text'>GAE/J + BlazeDS3 環境の HttpSessionListener 問題</title><content type='html'>最近、GAE/J 環境では HttpSessionListener は効かないらしいという話を聞きました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.google.com/group/google-appengine-java/browse_thread/thread/672879dd9a3ba137"&gt;http://groups.google.com/group/google-appengine-java/browse_thread/thread/672879dd9a3ba137&lt;/a&gt;の下記の発言から、ローカルの環境で動くのがバグであることがわかります。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Hi Erum. App Engine doesn't support this callback, so when sessionDestroyed&lt;br /&gt;is triggered by the development server, it's not within an active request&lt;br /&gt;and hence the exception that you're seeing. In the production environment,&lt;br /&gt;you would see a similar result if the callback is even triggered at all.&lt;br /&gt;&lt;br /&gt;The fact that the development server does trigger sessionDestroyed is a bug&lt;br /&gt;in the SDK. Please file a new report in our public tracker, and I'm sorry&lt;br /&gt;for the bad news.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これがもし本当なら、GAE 上で BlazeDS を使うのは結構厳しそうな気がします。&lt;br /&gt;&lt;br /&gt;一例ですが、BlazeDS 3.2  のHttpFlexSession では、以下のようにライフサイクルイベントを前提としたコードがそれなりにあります。どうしたものか (´・ω・`)&lt;br /&gt;&lt;pre class="prettyprint"&gt;/**&lt;br /&gt; * Implements HttpSessionListener.&lt;br /&gt; * When an HttpSession is destroyed, the associated HttpFlexSession is also destroyed.&lt;br /&gt; * NOTE: This method is not invoked against an HttpFlexSession associated with a request&lt;br /&gt; * handling thread.&lt;br /&gt; */&lt;br /&gt;public void sessionDestroyed(HttpSessionEvent event)&lt;br /&gt;{&lt;br /&gt;    HttpSession session = event.getSession();&lt;br /&gt;    Map httpSessionToFlexSessionMap = getHttpSessionToFlexSessionMap(session);&lt;br /&gt;    HttpFlexSession flexSession = (HttpFlexSession)httpSessionToFlexSessionMap.remove(session.getId());&lt;br /&gt;    if (flexSession != null)&lt;br /&gt;    {&lt;br /&gt;        // invalidate the flex session&lt;br /&gt;        flexSession.superInvalidate();&lt;br /&gt;&lt;br /&gt;        // Send notifications to attribute listeners if needed&lt;br /&gt;        // This may send extra notifications if attributeRemoved is called first by the server,&lt;br /&gt;        // but Java servlet 2.4 says session destroy is first, then attributes.&lt;br /&gt;        for (Enumeration e = session.getAttributeNames(); e.hasMoreElements(); )&lt;br /&gt;        {&lt;br /&gt;            String name = (String) e.nextElement();&lt;br /&gt;            if (name.equals(SESSION_ATTRIBUTE))&lt;br /&gt;                continue;&lt;br /&gt;            Object value = session.getAttribute(name);&lt;br /&gt;            if (value != null)&lt;br /&gt;            {&lt;br /&gt;                flexSession.notifyAttributeUnbound(name, value);&lt;br /&gt;                flexSession.notifyAttributeRemoved(name, value);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;しかし、本当にそうなのか？&lt;br /&gt;&lt;br /&gt;ということで、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-application-lifecycle-listener.html"&gt;GAE/J 環境の Application Lifecycle Listener の実験&lt;/a&gt;をしてみました。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4919012929761154827?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4919012929761154827/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds3-httpsessionlistener.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4919012929761154827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4919012929761154827'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds3-httpsessionlistener.html' title='GAE/J + BlazeDS3 環境の HttpSessionListener 問題'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3424203911624921772</id><published>2010-04-15T03:17:00.001+09:00</published><updated>2010-04-15T03:20:52.262+09:00</updated><title type='text'>JDO の Query を Generics に対応させてみた。</title><content type='html'>javax.jdo.Query interface の execute() メソッドは戻り値が java.lang.Object 型なので、以下のようにキャストする必要があります。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;Collection&amp;lt;User&amp;gt; users = (Collection&amp;lt;User&amp;gt;)query.execute();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;でも、めんどくさいです。(´・ω・`)&lt;br /&gt;&lt;br /&gt;しかも、キャストのところでコンパイラが警告を出します。&lt;br /&gt;&lt;br /&gt;@SuppressWarning("unchecked") とか書けば警告は消えますが。&lt;br /&gt;&lt;br /&gt;でも、めんどくさいです。(´・ω・`)&lt;br /&gt;&lt;br /&gt;ということで、execute系メソッドの引数として型変数を渡せるようなクラスを作成してみました。&lt;br /&gt;&lt;br /&gt;PersistenceManagerExt.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.gae.datastore;&lt;br /&gt;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.Date;&lt;br /&gt;import java.util.EnumSet;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;import javax.jdo.Extent;&lt;br /&gt;import javax.jdo.FetchGroup;&lt;br /&gt;import javax.jdo.FetchPlan;&lt;br /&gt;import javax.jdo.JDOException;&lt;br /&gt;import javax.jdo.ObjectState;&lt;br /&gt;import javax.jdo.PersistenceManager;&lt;br /&gt;import javax.jdo.PersistenceManagerFactory;&lt;br /&gt;import javax.jdo.Transaction;&lt;br /&gt;import javax.jdo.datastore.JDOConnection;&lt;br /&gt;import javax.jdo.datastore.Sequence;&lt;br /&gt;import javax.jdo.listener.InstanceLifecycleListener;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * PersistenceManager for QueryExt.&lt;br /&gt; */&lt;br /&gt;public class PersistenceManagerExt implements PersistenceManager {&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * PersistenceManager instance to be delegated.&lt;br /&gt;  */&lt;br /&gt; private final PersistenceManager instance;&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Constructor.&lt;br /&gt;  * &lt;br /&gt;  * @param instance instance to be delegated&lt;br /&gt;  */&lt;br /&gt; public PersistenceManagerExt(PersistenceManager instance) {&lt;br /&gt;  this.instance = instance;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; // for generics&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newNamedQuery(Class cls, String filter) {&lt;br /&gt;  return new QueryExt(instance.newNamedQuery(cls, filter));&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery() {&lt;br /&gt;  return new QueryExt(instance.newQuery());&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Class cls, Collection cln, String filter) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cls, cln, filter));&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Class cls, Collection cln) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cls, cln));&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Class cls, String filter) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cls, filter));&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Class cls) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cls));&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Extent cln, String filter) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cln, filter));&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Extent cln) {&lt;br /&gt;  return new QueryExt(instance.newQuery(cln));&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(Object compiled) {&lt;br /&gt;  return new QueryExt(instance.newQuery(compiled));&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(String language, Object query) {&lt;br /&gt;  return new QueryExt(instance.newQuery(language, query));&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public QueryExt newQuery(String query) {&lt;br /&gt;  return new QueryExt(instance.newQuery(query));&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; // delegate methods.&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void addInstanceLifecycleListener(InstanceLifecycleListener listener, Class... classes) {&lt;br /&gt;  instance.addInstanceLifecycleListener(listener, classes);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void checkConsistency() {&lt;br /&gt;  instance.checkConsistency();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void close() {&lt;br /&gt;  instance.close();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Transaction currentTransaction() {&lt;br /&gt;  return instance.currentTransaction();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void deletePersistent(Object pc) {&lt;br /&gt;  instance.deletePersistent(pc);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void deletePersistentAll(Collection pcs) {&lt;br /&gt;  instance.deletePersistentAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void deletePersistentAll(Object... pcs) {&lt;br /&gt;  instance.deletePersistentAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T detachCopy(T pc) {&lt;br /&gt;  return instance.detachCopy(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; detachCopyAll(Collection&amp;lt;T&amp;gt; pcs) {&lt;br /&gt;  return instance.detachCopyAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T[] detachCopyAll(T... pcs) {&lt;br /&gt;  return instance.detachCopyAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void evict(Object pc) {&lt;br /&gt;  instance.evict(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void evictAll() {&lt;br /&gt;  instance.evictAll();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void evictAll(boolean subclasses, Class pcClass) {&lt;br /&gt;  instance.evictAll(subclasses, pcClass);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void evictAll(Collection pcs) {&lt;br /&gt;  instance.evictAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void evictAll(Object... pcs) {&lt;br /&gt;  instance.evictAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void flush() {&lt;br /&gt;  instance.flush();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean getCopyOnAttach() {&lt;br /&gt;  return instance.getCopyOnAttach();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public JDOConnection getDataStoreConnection() {&lt;br /&gt;  return instance.getDataStoreConnection();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean getDetachAllOnCommit() {&lt;br /&gt;  return instance.getDetachAllOnCommit();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; Extent&amp;lt;T&amp;gt; getExtent(Class&amp;lt;T&amp;gt; persistenceCapableClass, boolean subclasses) {&lt;br /&gt;  return instance.getExtent(persistenceCapableClass, subclasses);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; Extent&amp;lt;T&amp;gt; getExtent(Class&amp;lt;T&amp;gt; persistenceCapableClass) {&lt;br /&gt;  return instance.getExtent(persistenceCapableClass);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public FetchGroup getFetchGroup(Class cls, String name) {&lt;br /&gt;  return instance.getFetchGroup(cls, name);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public FetchPlan getFetchPlan() {&lt;br /&gt;  return instance.getFetchPlan();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean getIgnoreCache() {&lt;br /&gt;  return instance.getIgnoreCache();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Set getManagedObjects() {&lt;br /&gt;  return instance.getManagedObjects();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Set getManagedObjects(Class... classes) {&lt;br /&gt;  return instance.getManagedObjects(classes);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Set getManagedObjects(EnumSet&amp;lt;ObjectState&amp;gt; states, Class... classes) {&lt;br /&gt;  return instance.getManagedObjects(states, classes);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Set getManagedObjects(EnumSet&amp;lt;ObjectState&amp;gt; states) {&lt;br /&gt;  return instance.getManagedObjects(states);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean getMultithreaded() {&lt;br /&gt;  return instance.getMultithreaded();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T getObjectById(Class&amp;lt;T&amp;gt; cls, Object key) {&lt;br /&gt;  return instance.getObjectById(cls, key);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getObjectById(Object oid, boolean validate) {&lt;br /&gt;  return instance.getObjectById(oid, validate);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getObjectById(Object oid) {&lt;br /&gt;  return instance.getObjectById(oid);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getObjectId(Object pc) {&lt;br /&gt;  return instance.getObjectId(pc);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Class getObjectIdClass(Class cls) {&lt;br /&gt;  return instance.getObjectIdClass(cls);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object[] getObjectsById(boolean validate, Object... oids) {&lt;br /&gt;  return instance.getObjectsById(validate, oids);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Collection getObjectsById(Collection oids, boolean validate) {&lt;br /&gt;  return instance.getObjectsById(oids, validate);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Collection getObjectsById(Collection oids) {&lt;br /&gt;  return instance.getObjectsById(oids);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object[] getObjectsById(Object... oids) {&lt;br /&gt;  return instance.getObjectsById(oids);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("deprecation")&lt;br /&gt; @Override&lt;br /&gt; public Object[] getObjectsById(Object[] oids, boolean validate) {&lt;br /&gt;  return instance.getObjectsById(oids, validate);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public PersistenceManagerFactory getPersistenceManagerFactory() {&lt;br /&gt;  return instance.getPersistenceManagerFactory();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Integer getQueryTimeoutMillis() {&lt;br /&gt;  return instance.getQueryTimeoutMillis();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Sequence getSequence(String name) {&lt;br /&gt;  return instance.getSequence(name);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Date getServerDate() {&lt;br /&gt;  return instance.getServerDate();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getTransactionalObjectId(Object pc) {&lt;br /&gt;  return instance.getTransactionalObjectId(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getUserObject() {&lt;br /&gt;  return instance.getUserObject();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object getUserObject(Object key) {&lt;br /&gt;  return instance.getUserObject(key);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean isClosed() {&lt;br /&gt;  return instance.isClosed();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeNontransactional(Object pc) {&lt;br /&gt;  instance.makeNontransactional(pc);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void makeNontransactionalAll(Collection pcs) {&lt;br /&gt;  instance.makeNontransactionalAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeNontransactionalAll(Object... pcs) {&lt;br /&gt;  instance.makeNontransactionalAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T makePersistent(T pc) {&lt;br /&gt;  return instance.makePersistent(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; makePersistentAll(Collection&amp;lt;T&amp;gt; pcs) {&lt;br /&gt;  return instance.makePersistentAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T[] makePersistentAll(T... pcs) {&lt;br /&gt;  return instance.makePersistentAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransactional(Object pc) {&lt;br /&gt;  instance.makeTransactional(pc);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void makeTransactionalAll(Collection pcs) {&lt;br /&gt;  instance.makeTransactionalAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransactionalAll(Object... pcs) {&lt;br /&gt;  instance.makeTransactionalAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransient(Object pc, boolean useFetchPlan) {&lt;br /&gt;  instance.makeTransient(pc, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransient(Object pc) {&lt;br /&gt;  instance.makeTransient(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransientAll(boolean useFetchPlan, Object... pcs) {&lt;br /&gt;  instance.makeTransientAll(useFetchPlan, pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void makeTransientAll(Collection pcs, boolean useFetchPlan) {&lt;br /&gt;  instance.makeTransientAll(pcs, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void makeTransientAll(Collection pcs) {&lt;br /&gt;  instance.makeTransientAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void makeTransientAll(Object... pcs) {&lt;br /&gt;  instance.makeTransientAll(pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("deprecation")&lt;br /&gt; @Override&lt;br /&gt; public void makeTransientAll(Object[] pcs, boolean useFetchPlan) {&lt;br /&gt;  instance.makeTransientAll(pcs, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public &amp;lt;T&amp;gt; T newInstance(Class&amp;lt;T&amp;gt; pcClass) {&lt;br /&gt;  return instance.newInstance(pcClass);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Object newObjectIdInstance(Class pcClass, Object key) {&lt;br /&gt;  return instance.newObjectIdInstance(pcClass, key);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object putUserObject(Object key, Object val) {&lt;br /&gt;  return instance.putUserObject(key, val);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void refresh(Object pc) {&lt;br /&gt;  instance.refresh(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void refreshAll() {&lt;br /&gt;  instance.refreshAll();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void refreshAll(Collection pcs) {&lt;br /&gt;  instance.refreshAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void refreshAll(JDOException jdoe) {&lt;br /&gt;  instance.refreshAll(jdoe);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void refreshAll(Object... pcs) {&lt;br /&gt;  instance.refreshAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void removeInstanceLifecycleListener(InstanceLifecycleListener listener) {&lt;br /&gt;  instance.removeInstanceLifecycleListener(listener);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object removeUserObject(Object key) {&lt;br /&gt;  return instance.removeUserObject(key);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void retrieve(Object pc, boolean useFetchPlan) {&lt;br /&gt;  instance.retrieve(pc, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void retrieve(Object pc) {&lt;br /&gt;  instance.retrieve(pc);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void retrieveAll(boolean useFetchPlan, Object... pcs) {&lt;br /&gt;  instance.retrieveAll(useFetchPlan, pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void retrieveAll(Collection pcs, boolean useFetchPlan) {&lt;br /&gt;  instance.retrieveAll(pcs, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void retrieveAll(Collection pcs) {&lt;br /&gt;  instance.retrieveAll(pcs);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void retrieveAll(Object... pcs) {&lt;br /&gt;  instance.retrieveAll(pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("deprecation")&lt;br /&gt; @Override&lt;br /&gt; public void retrieveAll(Object[] pcs, boolean useFetchPlan) {&lt;br /&gt;  instance.retrieveAll(pcs, useFetchPlan);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setCopyOnAttach(boolean flag) {&lt;br /&gt;  instance.setCopyOnAttach(flag);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setDetachAllOnCommit(boolean flag) {&lt;br /&gt;  instance.setDetachAllOnCommit(flag);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setIgnoreCache(boolean flag) {&lt;br /&gt;  instance.setIgnoreCache(flag);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setMultithreaded(boolean flag) {&lt;br /&gt;  instance.setMultithreaded(flag);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setQueryTimeoutMillis(Integer interval) {&lt;br /&gt;  instance.setQueryTimeoutMillis(interval);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setUserObject(Object o) {&lt;br /&gt;  instance.setUserObject(o);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;QueryExt.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package com.objectfanatics.gae.datastore;&lt;br /&gt;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;import javax.jdo.Extent;&lt;br /&gt;import javax.jdo.FetchPlan;&lt;br /&gt;import javax.jdo.PersistenceManager;&lt;br /&gt;import javax.jdo.Query;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Generics enabled Query extension.&lt;br /&gt; */&lt;br /&gt;public class QueryExt implements Query {&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Query instance to be delegated.&lt;br /&gt;  */&lt;br /&gt; private final Query instanceToBeDelegated;&lt;br /&gt; &lt;br /&gt; /**&lt;br /&gt;  * Constructor.&lt;br /&gt;  * @param instanceToBeDelegated Query instance to be delegated&lt;br /&gt;  */&lt;br /&gt; public QueryExt(Query instanceToBeDelegated) {&lt;br /&gt;  if (instanceToBeDelegated == null) throw new IllegalArgumentException("instanceToBeDelegated must not be null.");&lt;br /&gt;  this.instanceToBeDelegated = instanceToBeDelegated;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; // for generics.&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeExt(Class&amp;lt;T&amp;gt; t) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.execute();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeExt(Class&amp;lt;T&amp;gt; t, Object p1, Object p2, Object p3) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.execute(p1, p2, p3);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeExt(Class&amp;lt;T&amp;gt; t, Object p1, Object p2) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.execute(p1, p2);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeExt(Class&amp;lt;T&amp;gt; t, Object p1) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.execute(p1);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeWithArrayExt(Class&amp;lt;T&amp;gt; t, Object... parameters) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.executeWithArray(parameters);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; public &amp;lt;T&amp;gt; Collection&amp;lt;T&amp;gt; executeWithMapExt(Class&amp;lt;T&amp;gt; t, Map parameters) {&lt;br /&gt;  return (Collection&amp;lt;T&amp;gt;)instanceToBeDelegated.executeWithMap(parameters);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; // delegate methods.&lt;br /&gt; @Override&lt;br /&gt; public void addExtension(String key, Object value) {&lt;br /&gt;  instanceToBeDelegated.addExtension(key, value);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void addSubquery(Query sub, String variableDeclaration, String candidateCollectionExpression, Map parameters) {&lt;br /&gt;  instanceToBeDelegated.addSubquery(sub, variableDeclaration, candidateCollectionExpression, parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void addSubquery(Query sub, String variableDeclaration, String candidateCollectionExpression, String... parameters) {&lt;br /&gt;  instanceToBeDelegated.addSubquery(sub, variableDeclaration, candidateCollectionExpression, parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void addSubquery(Query sub, String variableDeclaration, String candidateCollectionExpression, String parameter) {&lt;br /&gt;  instanceToBeDelegated.addSubquery(sub, variableDeclaration, candidateCollectionExpression, parameter);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void addSubquery(Query sub, String variableDeclaration, String candidateCollectionExpression) {&lt;br /&gt;  instanceToBeDelegated.addSubquery(sub, variableDeclaration, candidateCollectionExpression);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void cancel(Thread thread) {&lt;br /&gt;  instanceToBeDelegated.cancel(thread);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void cancelAll() {&lt;br /&gt;  instanceToBeDelegated.cancelAll();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void close(Object queryResult) {&lt;br /&gt;  instanceToBeDelegated.close(queryResult);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void closeAll() {&lt;br /&gt;  instanceToBeDelegated.closeAll();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void compile() {&lt;br /&gt;  instanceToBeDelegated.compile();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void declareImports(String imports) {&lt;br /&gt;  instanceToBeDelegated.declareImports(imports);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void declareParameters(String parameters) {&lt;br /&gt;  instanceToBeDelegated.declareParameters(parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void declareVariables(String variables) {&lt;br /&gt;  instanceToBeDelegated.declareVariables(variables);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public long deletePersistentAll() {&lt;br /&gt;  return instanceToBeDelegated.deletePersistentAll();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public long deletePersistentAll(Map parameters) {&lt;br /&gt;  return instanceToBeDelegated.deletePersistentAll(parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public long deletePersistentAll(Object... parameters) {&lt;br /&gt;  return instanceToBeDelegated.deletePersistentAll(parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object execute() {&lt;br /&gt;  return instanceToBeDelegated.execute();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object execute(Object p1, Object p2, Object p3) {&lt;br /&gt;  return instanceToBeDelegated.execute(p1, p2, p3);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object execute(Object p1, Object p2) {&lt;br /&gt;  return instanceToBeDelegated.execute(p1, p2);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object execute(Object p1) {&lt;br /&gt;  return instanceToBeDelegated.execute(p1);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Object executeWithArray(Object... parameters) {&lt;br /&gt;  return instanceToBeDelegated.executeWithArray(parameters);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public Object executeWithMap(Map parameters) {&lt;br /&gt;  return instanceToBeDelegated.executeWithMap(parameters);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public FetchPlan getFetchPlan() {&lt;br /&gt;  return instanceToBeDelegated.getFetchPlan();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean getIgnoreCache() {&lt;br /&gt;  return instanceToBeDelegated.getIgnoreCache();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public PersistenceManager getPersistenceManager() {&lt;br /&gt;  return instanceToBeDelegated.getPersistenceManager();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Boolean getSerializeRead() {&lt;br /&gt;  return instanceToBeDelegated.getSerializeRead();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public Integer getTimeoutMillis() {&lt;br /&gt;  return instanceToBeDelegated.getTimeoutMillis();&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public boolean isUnmodifiable() {&lt;br /&gt;  return instanceToBeDelegated.isUnmodifiable();&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void setCandidates(Collection pcs) {&lt;br /&gt;  instanceToBeDelegated.setCandidates(pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void setCandidates(Extent pcs) {&lt;br /&gt;  instanceToBeDelegated.setCandidates(pcs);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void setClass(Class cls) {&lt;br /&gt;  instanceToBeDelegated.setClass(cls);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void setExtensions(Map extensions) {&lt;br /&gt;  instanceToBeDelegated.setExtensions(extensions);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setFilter(String filter) {&lt;br /&gt;  instanceToBeDelegated.setFilter(filter);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setGrouping(String group) {&lt;br /&gt;  instanceToBeDelegated.setGrouping(group);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setIgnoreCache(boolean ignoreCache) {&lt;br /&gt;  instanceToBeDelegated.setIgnoreCache(ignoreCache);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setOrdering(String ordering) {&lt;br /&gt;  instanceToBeDelegated.setOrdering(ordering);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setRange(long fromIncl, long toExcl) {&lt;br /&gt;  instanceToBeDelegated.setRange(fromIncl, toExcl);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setRange(String fromInclToExcl) {&lt;br /&gt;  instanceToBeDelegated.setRange(fromInclToExcl);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setResult(String data) {&lt;br /&gt;  instanceToBeDelegated.setResult(data);&lt;br /&gt; }&lt;br /&gt; @SuppressWarnings("unchecked")&lt;br /&gt; @Override&lt;br /&gt; public void setResultClass(Class cls) {&lt;br /&gt;  instanceToBeDelegated.setResultClass(cls);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setSerializeRead(Boolean serialize) {&lt;br /&gt;  instanceToBeDelegated.setSerializeRead(serialize);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setTimeoutMillis(Integer interval) {&lt;br /&gt;  instanceToBeDelegated.setTimeoutMillis(interval);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setUnique(boolean unique) {&lt;br /&gt;  instanceToBeDelegated.setUnique(unique);&lt;br /&gt; }&lt;br /&gt; @Override&lt;br /&gt; public void setUnmodifiable() {&lt;br /&gt;  instanceToBeDelegated.setUnmodifiable();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PersistenceManager のいくつかの newQuery() 系のメソッドは引数でエンティティの型を受け取っているので、それを利用すれば QueryExt&amp;lt;T&amp;gt; のような形でエンティティの型を渡すこともできそうですね。要検討ということで。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3424203911624921772?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3424203911624921772/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/jdo-query-generics.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3424203911624921772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3424203911624921772'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/jdo-query-generics.html' title='JDO の Query を Generics に対応させてみた。'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-556593337808420603</id><published>2010-04-13T08:23:00.008+09:00</published><updated>2010-04-13T19:49:37.588+09:00</updated><title type='text'>Flex でカスタムコンポーネントを作成してみた</title><content type='html'>Flex でカスタムコンポーネントを作ってみました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;お題&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;今回は、ありがちな感じのログイン用の画面を題材に選んでみました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;オブジェクト指向っぽく考えてみた。&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;まずば、カスタムコンポーネントをブラックボックスと考えてみたときに、外部にどのような機能を公開すべきか考えてみました。&lt;br /&gt;&lt;br /&gt;とりあえず、サンプルとしては以下の機能があればいいかな。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;userName:String&lt;br /&gt;ユーザー名入力用コンポーネントとの双方向バインドされた bindable な変数&lt;/li&gt;&lt;li&gt;password:String&lt;br /&gt;パスワード入力用コンポーネントとの双方向バインドされた bindable な変数&lt;/li&gt;&lt;li&gt;loginBtn_clickHandler:Function&lt;br /&gt;ログインボタンをクリックしたときに呼び出される関数を外部からセットするための変数。&lt;/li&gt;&lt;li&gt;clear()&lt;br /&gt;ユーザー名入力用コンポーネントとパスワード入力用コンポーネントのクリア用関数&lt;/li&gt;&lt;li&gt;showErrorMessage(message:String) &lt;br /&gt;エラーメッセージ表示用関数&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;公開する変数については、変数自体が bindable でありながら、その変数自体もコンポーネントのテキストと双方向にバインドされているというのがミソですね。&lt;br /&gt;&lt;br /&gt;関数のハンドラについては、Function 型の変数としました。本当は関数のシグニチャをインタフェースのように定義して厳密な型指定をしたかったのですが、できなさそうなので、、、。できるのかな？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;サンプルコンポーネント（LoginBox）&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;ユーザー名とパスワードの入力フィールドとログインボタンを持つシンプルなログイン画面です。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_IYJOWXQH1bw/S8OtuIQStcI/AAAAAAAAABU/yd7lQ3Np84M/s1600/LoginBox.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_IYJOWXQH1bw/S8OtuIQStcI/AAAAAAAAABU/yd7lQ3Np84M/s320/LoginBox.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;LoginBox.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;   xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;   xmlns:mx="library://ns.adobe.com/flex/mx"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   import mx.effects.Effect;&lt;br /&gt;   import mx.effects.Fade;&lt;br /&gt;   [Bindable]&lt;br /&gt;   /**&lt;br /&gt;    * user name.&lt;br /&gt;    */&lt;br /&gt;   public var userName:String;&lt;br /&gt;   &lt;br /&gt;   [Bindable]&lt;br /&gt;   /**&lt;br /&gt;    * password.&lt;br /&gt;    */&lt;br /&gt;   public var password:String;&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Login handler.&lt;br /&gt;    * &lt;br /&gt;    * This handler is invoked when login button is clicked.&lt;br /&gt;    */&lt;br /&gt;   public var loginBtn_clickHandler:Function;&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Clear user name, password and error message.&lt;br /&gt;    */&lt;br /&gt;   public function clear():void {&lt;br /&gt;    userNameTextInput.text = "";&lt;br /&gt;    passwordTextInput.text = "";&lt;br /&gt;    errorMessageLabel.visible = false;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   /**&lt;br /&gt;    * Show error message.// TODO: エラー失敗時のハンドラという名前のほうが正解？要検討。&lt;br /&gt;    */&lt;br /&gt;   public function showErrorMessage(message:String):void {&lt;br /&gt;    errorMessageLabel.visible = true;&lt;br /&gt;    errorMessageLabel.text = message;&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;!-- Bi-directional Bindings --&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="userNameTextInput.text" destination="userName"/&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="userName" destination="userNameTextInput.text"/&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="passwordTextInput.text" destination="password"/&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="password" destination="passwordTextInput.text"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- Visual Components --&amp;gt;&lt;br /&gt; &amp;lt;mx:Form fontFamily="Courier New" defaultButton="{loginBtn}"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="username"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput id="userNameTextInput" focusIn="IME.enabled = false;userNameTextInput.setSelection(0,userNameTextInput.text.length)"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="password"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput displayAsPassword="true" id="passwordTextInput" focusIn="IME.enabled = false;passwordTextInput.setSelection(0,passwordTextInput.text.length)" keyDown="IME.enabled = false"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Label id="errorMessageLabel" text="Login failed" color="red" visible="false" hideEffect="{Fade}"/&amp;gt;&lt;br /&gt; &amp;lt;s:HGroup&amp;gt;&lt;br /&gt;  &amp;lt;s:Button label="Login" id="loginBtn" click="loginBtn_clickHandler(event)"/&amp;gt;&lt;br /&gt;  &amp;lt;s:Button label="Clear" id="clearBtn" click="clear()"/&amp;gt;&lt;br /&gt; &amp;lt;/s:HGroup&amp;gt;&lt;br /&gt;&amp;lt;/s:Group&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;サンプル用コンポーネントのテスト用アプリ（LoginBoxTest）&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;LoginBox コンポーネントを試すためのアプリです。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_IYJOWXQH1bw/S8Ot8cZeapI/AAAAAAAAABc/IEnp4syGnjg/s1600/LoginBoxTest.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_IYJOWXQH1bw/S8Ot8cZeapI/AAAAAAAAABc/IEnp4syGnjg/s320/LoginBoxTest.PNG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;username = foo, password = bar の時以外はログイン失敗メソッドを呼び出すハンドラを設定しています。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;LoginBoxTest.mxml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" &lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark" &lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:component="component.*" width="100%" height="100%" creationComplete="init()"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[   &lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   &lt;br /&gt;   // test for loginBox.loginBtn_clickHandler&lt;br /&gt;   private function init():void {&lt;br /&gt;    loginBox.loginBtn_clickHandler = function(event:MouseEvent):void {&lt;br /&gt;     Alert.show("Login button clicked.\nusername = "+loginBox.userName+"\npassword = "+loginBox.password+"\nPos = ("+event.localX+", "+event.localY+")", "Assigned Method from Outer Component");&lt;br /&gt;     if (loginBox.userName != "foo" || loginBox.password != "bar") loginBox.showErrorMessage("Login Failed");&lt;br /&gt;    };&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // test for loginBox.clear()&lt;br /&gt;   protected function button1_clickHandler(event:MouseEvent):void {&lt;br /&gt;    loginBox.clear();&lt;br /&gt;   }&lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- bi-directional bind test for userName valiable. --&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="userNameTextInput.text" destination="loginBox.userName"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;!-- bi-directional bind test for password valiable. --&amp;gt;&lt;br /&gt; &amp;lt;fx:Binding source="passwordTextInput.text" destination="loginBox.password"/&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;s:Label text="Test for LoginBox" fontSize="24"/&amp;gt;&lt;br /&gt; &amp;lt;mx:Form&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- bi-directional bind test for userName valiable. --&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="bi-directional bind test for userName valiable"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput id="userNameTextInput" focusIn="IME.enabled = false" text="{loginBox.userName}"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- bi-directional bind test for password valiable. --&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="bi-directional bind test for password valiable"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput id="passwordTextInput" focusIn="IME.enabled = false" text="{loginBox.password}"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;!-- clear method test --&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="clear method test"&amp;gt;&lt;br /&gt;   &amp;lt;s:Button label="Clear" click="button1_clickHandler(event)"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &lt;br /&gt; &amp;lt;component:LoginBox id="loginBox"/&amp;gt;&lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-556593337808420603?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/556593337808420603/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flex.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/556593337808420603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/556593337808420603'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/flex.html' title='Flex でカスタムコンポーネントを作成してみた'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_IYJOWXQH1bw/S8OtuIQStcI/AAAAAAAAABU/yd7lQ3Np84M/s72-c/LoginBox.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4821478203864043583</id><published>2010-04-12T00:46:00.001+09:00</published><updated>2010-04-12T00:48:27.661+09:00</updated><title type='text'>作業ログ : BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ</title><content type='html'>BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ&lt;br /&gt;&lt;br /&gt;&lt;b&gt;経緯&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-security.html"&gt;GAE/J + BlazeDS 環境の Security 設定&lt;/a&gt;を書いているときにハマった時のログ。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;とりあえずのゴール&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;何が分からないのかも分からない状態なので、とりあえずいろいろ調べてみることにしよう。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Integrating Spring Security with BlazeDS and Flex RIAsを読んでみた&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.redredred.com.au/integrating-spring-security-with-blazeds-and-flex-rias/"&gt;Integrating Spring Security with BlazeDS and Flex RIAs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;とりあえず、&lt;a href="http://www.redredred.com.au/integrating-spring-security-with-blazeds-and-flex-rias/"&gt;Integrating Spring Security with BlazeDS and Flex RIAs&lt;/a&gt;を見て、実際に security 系の機能を利用する側の雰囲気をつかんでみる。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;この記事は spring-flex が正式にリリースされる前に書かれた Spring Security + BlazeDS + Flex 環境についてのまとめ記事。&lt;/li&gt;&lt;li&gt;環境は以下を前提としている。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Spring 2.5.5&lt;/li&gt;&lt;li&gt;Spring-Security 2.0.4 (core &amp;amp; tiger)&lt;/li&gt;&lt;li&gt;BlazeDS 3.2&lt;/li&gt;&lt;li&gt;Flex3&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;この記事は、end-point に対してセキュリティをかける目的は持っておらず、メソッド呼び出しレベルでセキュリティをかけることを目的としている。&lt;/li&gt;&lt;li&gt;BlazeDS は user の credential を request から取得し、それを SpingSecurity に渡して SecureContext が作成され、認証され、 ThreadLocal 中の SecureContext に認証情報が格納される。その後、普通に SpringSecurity が普通にメソッドを保護する。→ 実際に接続の受諾や拒否を行う部分を SpringSecurity にやらせてしまうわけですね。&lt;/li&gt;&lt;li&gt;BlazeDS の持つサーバ側の session 管理機能を一切使わず、自分で実装しようとしてるのかな？&lt;/li&gt;&lt;li&gt;Step1:maven の pom.xml を設定して jar を取得する。&lt;/li&gt;&lt;li&gt;Step2:amf のアクセスを org.springframework.web.filter.DelegatingFilterProxy で受けるように web.xml を設定する。&lt;/li&gt;&lt;li&gt;Step3:Spring Security の設定をする。&lt;/li&gt;&lt;li&gt;Step4:Spring Security に対応した flex.messaging.security.LoginCommand を実装する。&lt;/li&gt;&lt;li&gt;Step5:services-config.xml に設定する。&lt;/li&gt;&lt;/ul&gt;基本的に、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-security.html"&gt;GAE/J + BlazeDS 環境の Security 設定&lt;/a&gt; でハマった時と同じ方法ですね。今回の件の問題解決には関係なさそう。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;GAE 上でうまくセキュリティが動作しない件の調査&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;spring-flex を使ってみてもいいけど、っていうか使う予定ではいるけど、現状の問題の原因がわからないままというのもなんなので、もうちょっと調べてみた。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ローカル環境にて、セキュリティ関連の動作を追ってみた。とりあえず、printStackTrace() を埋め込んでみました。&lt;/li&gt;&lt;/ul&gt;以下、ログイン時のカスタムLoginCommandまでの流れ。&lt;br /&gt;&lt;pre class="prettyprint"&gt;java.lang.Exception: This is only a test.&lt;br /&gt; at security.CustomLoginCommand.doAuthentication(CustomLoginCommand.java:12)&lt;br /&gt; at flex.messaging.security.LoginManager.login(LoginManager.java:206)&lt;br /&gt; at flex.messaging.services.AuthenticationService.decodeAndLoginWithCharset(AuthenticationService.java:131)&lt;br /&gt; at flex.messaging.services.AuthenticationService.serviceCommand(AuthenticationService.java:81)&lt;br /&gt; at flex.messaging.MessageBroker.routeCommandToService(MessageBroker.java:1605)&lt;br /&gt; at flex.messaging.endpoints.AbstractEndpoint.serviceMessage(AbstractEndpoint.java:861)&lt;br /&gt; at flex.messaging.endpoints.amf.MessageBrokerFilter.invoke(MessageBrokerFilter.java:121)&lt;br /&gt; at flex.messaging.endpoints.amf.LegacyFilter.invoke(LegacyFilter.java:158)&lt;br /&gt; at flex.messaging.endpoints.amf.SessionFilter.invoke(SessionFilter.java:44)&lt;br /&gt; at flex.messaging.endpoints.amf.BatchProcessFilter.invoke(BatchProcessFilter.java:67)&lt;br /&gt; at flex.messaging.endpoints.amf.SerializationFilter.invoke(SerializationFilter.java:146)&lt;br /&gt; at flex.messaging.endpoints.BaseHTTPEndpoint.service(BaseHTTPEndpoint.java:278)&lt;br /&gt; at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:322)&lt;br /&gt; at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)&lt;br /&gt; at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:51)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)&lt;br /&gt; at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)&lt;br /&gt; at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)&lt;br /&gt; at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)&lt;br /&gt; at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)&lt;br /&gt; at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)&lt;br /&gt; at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)&lt;br /&gt; at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)&lt;br /&gt; at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)&lt;br /&gt; at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)&lt;br /&gt; at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)&lt;br /&gt; at org.mortbay.jetty.Server.handle(Server.java:326)&lt;br /&gt; at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)&lt;br /&gt; at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)&lt;br /&gt; at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)&lt;br /&gt; at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)&lt;br /&gt; at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)&lt;br /&gt; at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)&lt;br /&gt; at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;GAE上での動作についてメモ&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;GAE上では、ログイン後の動作にて、LoginManager.getCurrentPrincipal() が null を返している。ということは、ログイン時の CurrentPrincipal の格納に問題があるのか、取得時に問題があるのかのどちらかと考えられる。&lt;/li&gt;&lt;li&gt;ローカル上では、ログイン時には、ログインの認証が成功した後に FlexSession.setUserPrincipal() が呼び出されている。その後普通にセキュリティ制約のあるアクセスしてみたところ、FlexSession.setUserPrincipal() は呼ばれていない。サーバ上でオンメモリで保存されてもシリアライズを介したとしても、この動作は納得。しかし、HttpSessionレベルではどうなっているのだろうか？FlexSessionとSessionの関係ってどうなってるんだろ？&lt;/li&gt;&lt;li&gt;FlexSessionは、HttpSession に "__flexSession" という属性名で格納される。&lt;/li&gt;&lt;li&gt;GAE の Session をいろいろいじってみたのだが、普通に session に属性を set/get するのは問題なく動作するし、FlexSesson が session に保存されていることも確認したし、HttpFlexSession のインスタンスがシリアライズ/デシリアライズされているらしいことも確認(toString()の@以下の番号が変化することで確認)した。となると、FlexSession か Principal のシリアライズ/デシリアライズが問題？&lt;/li&gt;&lt;li&gt;ローカルで普通に FlexSession をシリアライズ/デシリアライズしたら、getUserPrincipal() がnullになりました。ということは、GAEの問題じゃないですね。&lt;/li&gt;&lt;li&gt;調べてみたら、HttpFlexSession#writeObject() メソッドが、例外を握りつぶしていました。例外の内容は、CustomLoginCommand が Serializable でないという内容。Principal が CustomLoginCommand のインナークラスだったので、CustomLoginCommand が Serializable である必要があったんですねぇ。ということで、CustomPrincipal として独自のクラスに切り出して、再度動作確認。&lt;/li&gt;&lt;li&gt;GAE上で動作しましたー！&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4821478203864043583?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4821478203864043583/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-logincommand.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4821478203864043583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4821478203864043583'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-logincommand.html' title='作業ログ : BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2448295871666455469</id><published>2010-04-11T02:47:00.007+09:00</published><updated>2010-04-13T03:37:10.470+09:00</updated><title type='text'>GAE/J + BlazeDS 環境の Security 設定</title><content type='html'>今回は、GAE/J + BlazeDS 環境で Security の設定をしてみようと思います。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;ベースの環境&lt;/b&gt;&lt;br /&gt;以下の作業は、&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-flash-builder.html"&gt;GAE/J + BlazeDS + Flash Builder 環境の構築&lt;/a&gt;で構築した環境をベースとします。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;参考資料&lt;/b&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_1.html"&gt;Administering BlazeDS applications - Security - Configuring security&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;本日のメニュー&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;本日は、以下のメニューを一通りこなしたいと思います。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;custom authentication に対応する。&lt;/li&gt;&lt;li&gt;認証ロジックは、サンプルとして固定のものを使用する。（username = foo, password = bar)&lt;/li&gt;&lt;li&gt;role は使用しない。&lt;/li&gt;&lt;li&gt;Session 単位の認証のみ行い、FlexClient 単位の認証は行わない。&lt;/li&gt;&lt;li&gt;security-constraint は destination 単位ではなく service 単位でかける。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;カスタム LoginCommand の作成&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;login command の実装クラスは、flex.messaging.security.LoginCommand インタフェースを実装している必要があります。&lt;br /&gt;&lt;br /&gt;今回は、flex.messaging.security.LoginCommand インタフェースを implements した抽象クラスである flex.messaging.security.AppServerLoginCommand を継承してカスタムの LoginCommand を作成しようと思います。&lt;br /&gt;&lt;br /&gt;CustomLoginCommand.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package security;&lt;br /&gt;&lt;br /&gt;import java.security.Principal;&lt;br /&gt;&lt;br /&gt;import flex.messaging.security.AppServerLoginCommand;&lt;br /&gt;&lt;br /&gt;public class CustomLoginCommand extends AppServerLoginCommand {&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public Principal doAuthentication(final String username, Object credentials) {&lt;br /&gt;  String password = extractPassword(credentials);&lt;br /&gt;  boolean isValidUser = "foo".equals(username) &amp;&amp; "bar".equals(password);&lt;br /&gt;  return isValidUser ? new CustomPrincipal(username) : null;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public boolean logout(Principal principal) {&lt;br /&gt;  return true;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;CustomPrincipal.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package security;&lt;br /&gt;&lt;br /&gt;import java.io.Serializable;&lt;br /&gt;import java.security.Principal;&lt;br /&gt;&lt;br /&gt;class CustomPrincipal implements Principal, Serializable {&lt;br /&gt; private String name;&lt;br /&gt; public CustomPrincipal(String name) { this.name = name; }&lt;br /&gt; public String getName() { return null; }&lt;br /&gt; public int hashCode() { return name.hashCode(); }&lt;br /&gt; public boolean equals(Object obj) { return name.equals(obj); }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;services-config.xml ファイルの設定&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;services-config.xml ファイルでは、以下の２つの作業を行います。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;login-command の定義&lt;br /&gt;login command の実装として security.CustomLoginCommand クラスを指定します。&lt;br /&gt;&amp;lt;login-command class="security.CustomLoginCommand" server="all"/&amp;gt;&lt;/li&gt;&lt;li&gt;security-constraint の定義&lt;br /&gt;今回は role を使用しないので、security-constraint は id のみの指定となります。&lt;br /&gt;&amp;lt;security-constraint id="security_constraint"/&amp;gt; &lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;services-config.xml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;services-config&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;services&amp;gt;&lt;br /&gt;    &amp;lt;default-channels&amp;gt;&amp;lt;channel ref="amf" /&amp;gt;&amp;lt;/default-channels&amp;gt;&lt;br /&gt;    &amp;lt;service-include file-path="remoting-config.xml" /&amp;gt;&lt;br /&gt;    &amp;lt;service-include file-path="messaging-config.xml" /&amp;gt;&lt;br /&gt;  &amp;lt;/services&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;channels&amp;gt;&lt;br /&gt;    &amp;lt;channel-definition id="amf" class="mx.messaging.channels.AMFChannel"&amp;gt;&lt;br /&gt;      &amp;lt;endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint" /&amp;gt;&lt;br /&gt;      &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;polling-enabled&amp;gt;true&amp;lt;/polling-enabled&amp;gt;&amp;lt;!-- default is true (though the document doesn't say so) --&amp;gt;&lt;br /&gt;      &amp;lt;/properties&amp;gt;&lt;br /&gt;    &amp;lt;/channel-definition&amp;gt;&lt;br /&gt;  &amp;lt;/channels&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;security&amp;gt;&lt;br /&gt;    &amp;lt;login-command class="security.CustomLoginCommand" server="all"/&amp;gt;&lt;br /&gt;    &amp;lt;security-constraint id="security_constraint"/&amp;gt;&lt;br /&gt;  &amp;lt;/security&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;system&amp;gt;&lt;br /&gt;    &amp;lt;!-- Workaround for GAE : java.lang.management.ManagementFactory is a restricted class. --&amp;gt;&lt;br /&gt;    &amp;lt;manageable&amp;gt;false&amp;lt;/manageable&amp;gt;&lt;br /&gt;  &amp;lt;/system&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/services-config&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;各 service に対する security-constraint の設定&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;security-constraint は destination 毎に設定することもできますが、今回は service 単位で設定します。具体的には remoting service と messaging service に設定します。&lt;br /&gt;&lt;br /&gt;設定方法は、各 &amp;lt;service&amp;gt; 要素の直下に以下のようにデフォルトの security-constraint を指定します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;default-security-constraint ref="security_constraint"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;以下、各 service の定義ファイル：&lt;br /&gt;remoting-config.xml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;br /&gt;&amp;lt;service id="remoting-service" class="flex.messaging.services.RemotingService"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;default-security-constraint ref="security_constraint"/&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;adapters&amp;gt;&lt;br /&gt;    &amp;lt;adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true" /&amp;gt;&lt;br /&gt;  &amp;lt;/adapters&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;destination id="echoServiceDestination"&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;      &amp;lt;source&amp;gt;server.EchoService&amp;lt;/source&amp;gt;&lt;br /&gt;      &amp;lt;scope&amp;gt;application&amp;lt;/scope&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;  &amp;lt;/destination&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/service&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;messaging-config.xml&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;service id="message-service" class="flex.messaging.services.MessageService"&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;default-security-constraint ref="security_constraint"/&amp;gt;&lt;br /&gt;  &lt;br /&gt;  &amp;lt;adapters&amp;gt;&lt;br /&gt;    &amp;lt;adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" /&amp;gt;&lt;br /&gt;  &amp;lt;/adapters&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;destination id="messageServiceDestination"&amp;gt;&lt;br /&gt;  &amp;lt;/destination&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/service&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;疎通確認用アプリケーションの開発（クライアント側）&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-flash-builder.html"&gt;GAE/J + BlazeDS + Flash Builder 環境の構築&lt;/a&gt;の Flex プロジェクトに、SecuredClient.mxml ファイルを作成します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;br /&gt;&amp;lt;s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"&lt;br /&gt;      xmlns:s="library://ns.adobe.com/flex/spark"&lt;br /&gt;      xmlns:mx="library://ns.adobe.com/flex/mx" width="100%" height="100%" creationComplete="init()" currentState="BeforeLogin"&amp;gt;&lt;br /&gt; &amp;lt;s:layout&amp;gt;&lt;br /&gt;  &amp;lt;s:VerticalLayout horizontalAlign="center" paddingLeft="24" paddingBottom="24" paddingRight="24" paddingTop="24" /&amp;gt;&lt;br /&gt; &amp;lt;/s:layout&amp;gt;&lt;br /&gt; &amp;lt;s:states&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="BeforeLogin"/&amp;gt;&lt;br /&gt;  &amp;lt;s:State name="AfterLogin"/&amp;gt;&lt;br /&gt; &amp;lt;/s:states&amp;gt;&lt;br /&gt; &amp;lt;fx:Declarations&amp;gt;&lt;br /&gt;  &amp;lt;mx:Producer id="producer" destination="messageServiceDestination" fault="messagingFaultHandler(event);"/&amp;gt;&lt;br /&gt; &amp;lt;/fx:Declarations&amp;gt;&lt;br /&gt; &amp;lt;fx:Script&amp;gt;&lt;br /&gt;  &amp;lt;![CDATA[&lt;br /&gt;   import mx.binding.utils.ChangeWatcher;&lt;br /&gt;   import mx.controls.Alert;&lt;br /&gt;   import mx.messaging.ChannelSet;&lt;br /&gt;   import mx.messaging.config.ServerConfig;&lt;br /&gt;   import mx.messaging.events.MessageAckEvent;&lt;br /&gt;   import mx.messaging.events.MessageEvent;&lt;br /&gt;   import mx.messaging.events.MessageFaultEvent;&lt;br /&gt;   import mx.messaging.messages.AsyncMessage;&lt;br /&gt;   import mx.rpc.AsyncResponder;&lt;br /&gt;   import mx.rpc.AsyncToken;&lt;br /&gt;   import mx.rpc.events.FaultEvent;&lt;br /&gt;   import mx.rpc.events.ResultEvent;&lt;br /&gt;   &lt;br /&gt;   private var cs:ChannelSet;&lt;br /&gt;   &lt;br /&gt;   // Define an AsyncToken object.&lt;br /&gt;   private var token:AsyncToken;&lt;br /&gt;   &lt;br /&gt;   // Initialize component&lt;br /&gt;   private function init():void {&lt;br /&gt;    cs = ServerConfig.getChannelSet("messageServiceDestination");&lt;br /&gt;    if (cs.authenticated == true) {&lt;br /&gt;     currentState = "AfterLogin";&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Login&lt;br /&gt;   private function login(username:String, password:String):void {&lt;br /&gt;    if (cs.authenticated == false) {&lt;br /&gt;     token = cs.login(username, password);&lt;br /&gt;     token.addResponder(new AsyncResponder(LoginResultEvent, LoginFaultEvent));&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Handle successful login.&lt;br /&gt;   private function LoginResultEvent(event:ResultEvent, token:Object=null):void  {&lt;br /&gt;    if (event.result != "success") return;&lt;br /&gt;    currentState="AfterLogin"&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Handle login failure.&lt;br /&gt;   private function LoginFaultEvent(event:FaultEvent, token:Object=null):void {&lt;br /&gt;    if (event.fault.faultCode != "Client.Authentication") return;&lt;br /&gt;    Alert.show("Login Failed!");&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Logout and handle success or failure.&lt;br /&gt;   private function logout():void {&lt;br /&gt;    // Add result and fault handlers.&lt;br /&gt;    token = cs.logout();&lt;br /&gt;    token.addResponder(new AsyncResponder(LogoutResultEvent,LogoutFaultEvent));&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Handle successful login.&lt;br /&gt;   private function LogoutResultEvent(event:ResultEvent, token:Object=null):void  {&lt;br /&gt;    if (event.result != "success") return;&lt;br /&gt;    currentState="BeforeLogin"&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Handle login failure.&lt;br /&gt;   private function LogoutFaultEvent(event:FaultEvent, token:Object=null):void {&lt;br /&gt;    if (event.fault.faultCode != "Client.Authentication") return;&lt;br /&gt;    Alert.show("Logout Failed!");&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Handle a message fault.&lt;br /&gt;   private function messagingFaultHandler(event:MessageFaultEvent):void {&lt;br /&gt;    Alert.show(event.message.faultString);&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   // Send the message in response to a Button click.&lt;br /&gt;   private function sendMessage():void {&lt;br /&gt;    producer.send(new AsyncMessage("This is only a test."));&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;  ]]&amp;gt;&lt;br /&gt; &amp;lt;/fx:Script&amp;gt;&lt;br /&gt; &amp;lt;mx:Form includeIn="BeforeLogin"&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="username"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput id="userNameTi" focusIn="IME.enabled = false"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt;  &amp;lt;mx:FormItem label="password"&amp;gt;&lt;br /&gt;   &amp;lt;mx:TextInput displayAsPassword="true" id="passwordTi" focusIn="IME.enabled = false" keyDown="IME.enabled = false"/&amp;gt;&lt;br /&gt;  &amp;lt;/mx:FormItem&amp;gt;&lt;br /&gt; &amp;lt;/mx:Form&amp;gt;&lt;br /&gt; &amp;lt;s:Label includeIn="AfterLogin" text="Hi, {userNameTi.text}. You have logged in."/&amp;gt;&lt;br /&gt; &amp;lt;s:HGroup includeIn="BeforeLogin,AfterLogin"&amp;gt;&lt;br /&gt;  &amp;lt;s:Button label="Login" id="loginBtn" includeIn="BeforeLogin" click="login(userNameTi.text, passwordTi.text)"/&amp;gt;&lt;br /&gt;  &amp;lt;s:Button includeIn="AfterLogin" label="Logout" id="logoutBtn" click="logout()"/&amp;gt;&lt;br /&gt;  &amp;lt;s:Button includeIn="BeforeLogin,AfterLogin" label="Send Message" id="sendMessageButton" click="sendMessage();"/&amp;gt;&lt;br /&gt; &amp;lt;/s:HGroup&amp;gt;&lt;br /&gt;&amp;lt;/s:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;以上。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;注意点&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;独自の Principal を作成する場合、確実に serialize できるようにしましょう。その際、例外が発生しなかったからといって安心してはいけません。おいらのように、悲しい思いをすることになります。&lt;br /&gt;&lt;br /&gt;下記のように、HttpFlexSession は writeObject() メソッドを独自に持って serialize を制御しています。&lt;br /&gt;&lt;pre class="prettyprint"&gt;/**&lt;br /&gt; * Implements Serializable; only the Principal needs to be serialized as all&lt;br /&gt; * attribute storage is delegated to the associated HttpSession.&lt;br /&gt; *&lt;br /&gt; * @param stream The stream to read instance state from.&lt;br /&gt; */&lt;br /&gt;private void writeObject(ObjectOutputStream stream)&lt;br /&gt;{&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        Principal principal = super.getUserPrincipal();&lt;br /&gt;        if (principal != null &amp;&amp; principal instanceof Serializable)&lt;br /&gt;            stream.writeObject(principal);&lt;br /&gt;    }&lt;br /&gt;    catch (IOException e)&lt;br /&gt;    {&lt;br /&gt;        // Principal was Serializable and non-null; if this happens there's nothing we can do.&lt;br /&gt;        // The user will need to reauthenticate if necessary.&lt;br /&gt;    }&lt;br /&gt;    catch (LocalizedException ignore)&lt;br /&gt;    {&lt;br /&gt;        // This catch block added for bug 194144.&lt;br /&gt;        // On BEA WebLogic, writeObject() is sometimes invoked on invalidated session instances&lt;br /&gt;        // and in this case the checkValid() invocation in super.getUserPrincipal() throws.&lt;br /&gt;        // Ignore this exception.&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そして、writeObject 時に IOException を握りつぶしています。&lt;br /&gt;&lt;br /&gt;ご注意ください。&lt;br /&gt;&lt;br /&gt;参考： &lt;a href="http://kcw-diary.blogspot.com/2010/04/blazeds-logincommand.html"&gt;作業ログ : BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;付録&lt;/b&gt;&lt;br /&gt;login-command 要素に server 属性を追加し忘れた時の例外。&lt;br /&gt;&lt;pre class="prettyprint"&gt;javax.servlet.UnavailableException: Attribute 'server' must be specified for element 'login-command'.&lt;br /&gt; at flex.messaging.MessageBrokerServlet.init(MessageBrokerServlet.java:170)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:440)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:263)&lt;br /&gt; at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)&lt;br /&gt; at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685)&lt;br /&gt; at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)&lt;br /&gt; at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)&lt;br /&gt; at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)&lt;br /&gt; at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)&lt;br /&gt; at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)&lt;br /&gt; at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)&lt;br /&gt; at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)&lt;br /&gt; at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)&lt;br /&gt; at org.mortbay.jetty.Server.doStart(Server.java:224)&lt;br /&gt; at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)&lt;br /&gt; at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:185)&lt;br /&gt; at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:146)&lt;br /&gt; at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:219)&lt;br /&gt; at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(DevAppServerMain.java:162)&lt;br /&gt; at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)&lt;br /&gt; at com.google.appengine.tools.development.DevAppServerMain.&lt;init&gt;(DevAppServerMain.java:113)&lt;br /&gt; at com.google.appengine.tools.development.DevAppServerMain.main(DevAppServerMain.java:89)&lt;br /&gt;&lt;/init&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2448295871666455469?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2448295871666455469/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-security.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2448295871666455469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2448295871666455469'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-security.html' title='GAE/J + BlazeDS 環境の Security 設定'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8173109691613801062</id><published>2010-04-10T09:27:00.016+09:00</published><updated>2010-04-18T08:36:23.910+09:00</updated><title type='text'>GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題</title><content type='html'>GAE/J + BlazeDS 環境では、以下のようなエラーメッセージが出ることがあります。&lt;br /&gt;&lt;pre class="prettyprint"&gt;Detected duplicate HTTP-based FlexSessions, generally due to the remote host disabling session cookies. Session cookies must be enabled to manage the client connection correctly." faultCode="Server.Processing.DuplicateSessionDetected&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;この問題について、&lt;a href="http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html"&gt;AppEngine &amp;amp; Adobe BlazeDS (fix)&lt;/a&gt; では flex.messaging.endpoints.BaseHTTPEndpoint クラスのソースにパッチを当てる方法でエラーを回避しています。&lt;br /&gt;&lt;br /&gt;今回は、この問題を少し掘り下げて考えてみようと思います。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;確かにエラーは出なくなるけど、、、。いいのか？&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;問題箇所をコメントアウトすればエラーは出なくなります。しかし、コメントアウトされた箇所のコードにも意味があるわけで、とりあえずコメントアウトというのはどうも気持ちがわるいです。&lt;br /&gt;&lt;br /&gt;ということで、BaseHTTPEndpoint.java を見てみました。もし GAE 側で session の cookie の扱いに不備があるのであれば、確かに下記のコードで duplicateSessionDetected が true になりそうです。&lt;br /&gt;&lt;pre class="prettyprint"&gt;boolean duplicateSessionDetected = (FlexContext.getHttpRequest().getAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG) != null) ? true : false;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ということで、ログを仕込んで確認してみたところ、結果は false でした。&lt;br /&gt;&lt;br /&gt;ということは、怪しい箇所は以下ということになりますね。&lt;br /&gt;&lt;pre class="prettyprint"&gt;if (!duplicateSessionDetected)&lt;br /&gt;{&lt;br /&gt;    List sessions = flexClient.getFlexSessions();&lt;br /&gt;    int n = sessions.size(); // &amp;lt;- suspicious!&lt;br /&gt;    if (n &amp;gt; 1)&lt;br /&gt;    {&lt;br /&gt;        int count = 0;&lt;br /&gt;        for (int i = 0; i &amp;lt; n; i++)&lt;br /&gt;        {&lt;br /&gt;            if (sessions.get(i) instanceof HttpFlexSession)&lt;br /&gt;                count++;&lt;br /&gt;            if (count &amp;gt; 1)&lt;br /&gt;            {&lt;br /&gt;                FlexContext.getHttpRequest().setAttribute(REQUEST_ATTR_DUPLICATE_SESSION_FLAG, Boolean.TRUE);&lt;br /&gt;                duplicateSessionDetected = true;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ログを仕込んで確認したところ、flexClient.getFlexSessions().size() の値はローカルだと常に 1 ですが、GAE 環境だと 2 度目のアクセスで 2 になることを確認しました。しかし 3 にはなりませんでした。&lt;br /&gt;&lt;br /&gt;これは、2 になった場合に duplicateSessionDetected = true になり、session の invalidate を行う if ブロックが実行されることが影響していると思われます。ということは、その if ブロックをコメントアウトしてしまうと、アクセスされるたびに flexClient.getFlexSessions() が１つずつ増えていくということが考えられます。&lt;br /&gt;&lt;br /&gt;実際にログを仕込んで確認したところ、やはりアクセスのたびに flexClient.getFlexSessions() が 1 つずつ増える現象が確認できました。&lt;br /&gt;&lt;br /&gt;となると、FlexClient に FlexSession を格納するところが怪しいですよね。ということで、session オブジェクトの格納箇所を見てみました。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public void registerFlexClient(FlexClient flexClient)&lt;br /&gt;{&lt;br /&gt;    if (flexClients.addIfAbsent(flexClient))&lt;br /&gt;    {&lt;br /&gt;        flexClient.addClientDestroyedListener(this);&lt;br /&gt;        flexClient.registerFlexSession(this);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;flexClients は java.util.concurrent.CopyOnWriteArrayList 型です。&lt;br /&gt;&lt;br /&gt;flexClients.addIfAbsent(flexClient) によって、既に flexClient が flexClients に含まれている場合は無視するようなプログラムになっています。&lt;br /&gt;&lt;br /&gt;しかし、同一性の判断はどうしているのか気になります。&lt;br /&gt;&lt;br /&gt;予想通り、equals メソッドを適切に実装していませんでした。そのため、同一セッションをあらわすオブジェクトでも、デシリアライズされたインスタンス同士が別物として扱われてしまい、GAE のローカル環境ではうまく動くのに本番環境ではうまく動かなかったというわけです。&lt;br /&gt;&lt;br /&gt;ということで、HttpFlexSession クラスに以下のメソッドを追加して問題解決です。（たぶん）&lt;a name="equals"&gt;&lt;pre class="prettyprint"&gt;@Override&lt;br /&gt;public boolean equals(Object obj) {&lt;br /&gt; if (!FlexSession.class.isInstance(obj)) return false;&lt;br /&gt; return FlexSession.class.cast(obj).getId().equals(getId());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public int hashCode() {&lt;br /&gt; return httpSession != null ? getId().hashCode() : super.hashCode();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;もしくは、FlexSession クラス以下に以下のメソッドとか。&lt;br /&gt;&lt;pre class="prettyprint"&gt;@Override&lt;br /&gt;public boolean equals(Object obj) {&lt;br /&gt; if (!FlexSession.class.isInstance(obj)) return false;&lt;br /&gt; return FlexSession.class.cast(obj).getId().equals(getId());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public int hashCode() {&lt;br /&gt; if (HttpFlexSession.class.isInstance(this) &amp;&amp; HttpFlexSession.class.cast(this).httpSession != null) { // to avoid NPE.&lt;br /&gt;  return getId().hashCode();&lt;br /&gt; } else {&lt;br /&gt;  return super.hashCode();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8173109691613801062?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8173109691613801062/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-duplicatesessiondetected.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8173109691613801062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8173109691613801062'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/gaej-blazeds-duplicatesessiondetected.html' title='GAE/J + BlazeDS 環境の DuplicateSessionDetected 問題'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4222588686518825947</id><published>2010-04-10T04:04:00.000+09:00</published><updated>2010-04-10T04:04:24.734+09:00</updated><title type='text'>BlazeDS 入門記（Measuring message processing performance）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/mpi_1.html"&gt;Additional programming topics / Measuring message processing performance&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/mpi_2.html#167374"&gt;About measuring message processing performance&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;メッセージ処理に関する箇所の時間やサイズ等のパフォーマンスを測定するという話。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;パフォーマンス測定機能はデフォルトでは disabled。&lt;/li&gt;&lt;li&gt;パフォーマンス測定機能を enable にすると、メッセージサイズ、サーバ処理時間、ネットワーク通信時間を測定可能。メッセージをサーバにプッシュしたクライアントや、サーバからプッシュされたメッセージを受信したクライアントや、プッシュしたメッセージの応答を受けたクライアントで測定可能。&lt;/li&gt;&lt;li&gt;部分的な情報はサーバでも確認可能。&lt;/li&gt;&lt;li&gt;BlazeDS のプロキシを使わないで外部サーバとやり取りする場合には、パフォーマンス測定を利用できない。&lt;/li&gt;&lt;li&gt;メッセージ処理のメトリクスは MessagePerformanceUtils で定義される。Producer が ack を受けたときや Consumer がメッセージを受けたときに、このクラスのインスタンスにデータが格納され、そのプロパティを確認することによりパフォーマンスを確認できる。&lt;/li&gt;&lt;li&gt;メッセージを受け取った場合に、メッセージ送信元を特定する情報を得ることはできないらしい。&lt;/li&gt;&lt;li&gt;ポーリングではない本当のリアルタイムメッセージでは、networkRTT、serverPollDelay、totalTime は測定できないので 0 が入る。&lt;/li&gt;&lt;li&gt;以下、一部のメッセージ処理メトリクスの説明&lt;/li&gt;&lt;ul&gt;&lt;li&gt;clientReceiveTime : クライアントが応答メッセージを受け取った時間。UNIX時刻のミリ秒。&lt;/li&gt;&lt;li&gt;messageSize :クライアントのオリジナルメッセージのバイト数で、サーバの endpoint でデシリアライズされたサイズ。&lt;/li&gt;&lt;li&gt;networkRTT : totalTime - serverProcessingTime。メッセージの送信から受信までの時間からサーバ処理時間を抜いたものなので、純粋にネットワーク通信の時間となる。ストリーミングの場合は無意味なので0が入る。&lt;/li&gt;&lt;li&gt;originatingMessageSentTime : クライアントがメッセージを投げた時間。ackは対象外。&lt;/li&gt;&lt;li&gt;originatingMessageSize : 元のメッセージサイズ。ackの場合は対象外。&lt;/li&gt;&lt;li&gt;pushedMessageFlag : ポーリングではない真のプッシュの場合には true になる。ackは対象外。&lt;/li&gt;&lt;li&gt;pushOneWayTime : プッシュされたメッセージの送信から受信までの時間。クライアントとサーバの時計が合っていることが前提。ackは対象外。&lt;/li&gt;&lt;li&gt;responseMessageSize : 応答メッセージのサイズ。サーバ側の endpoint でシリアライズしたときのサイズ。&lt;/li&gt;&lt;li&gt;totalPushTime では Producer と Consumer の時計が合っていなければ値の信頼性が損なわれる。&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;pushOneWayTime ではサーバと Consumer の時計が合っていなければ値の信頼性が損なわれる。&lt;/li&gt;&lt;li&gt;タイミング情報だけを収集するテストと、サイズ情報を収集するテストは別で行い、最後のそれらをあわせたテストをすべき。タイミング収集をするときにサイズ情報を収集すると、誤差が大きくなる。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/mpi_3.html#167711"&gt;Measuring message processing performance&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;機能の enabled / disabled はチャネル定義の record-message-times と record-message-sizes 要素で設定する。&lt;/li&gt;&lt;li&gt;new MessagePerformanceUtils(event.message) みたいな感じでOK。&lt;/li&gt;&lt;li&gt;prettyPrint() メソッドで情報の文字列化をお手軽に行える。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;TODO：実際にやってみたけど、totalTime とか networkRTT がマイナスの巨大な値になる。なぜに？要調査。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4222588686518825947?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4222588686518825947/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-measuring-message-processing.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4222588686518825947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4222588686518825947'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-measuring-message-processing.html' title='BlazeDS 入門記（Measuring message processing performance）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7843904559284635609</id><published>2010-04-10T01:41:00.000+09:00</published><updated>2010-04-10T01:41:40.912+09:00</updated><title type='text'>BlazeDS 入門記（Message delivery with adaptive polling）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/qos_1.html"&gt;Additional programming topics / Message delivery with adaptive polling&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;各クライアントベースでメッセージがどのようにキューイングされるかのカスタムロジックを書くという話。&lt;br /&gt;&lt;br /&gt;当面利用しなさそうなので、一通り読むだけにとどめておこう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7843904559284635609?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7843904559284635609/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-message-delivery-with-adaptive.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7843904559284635609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7843904559284635609'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-message-delivery-with-adaptive.html' title='BlazeDS 入門記（Message delivery with adaptive polling）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1529384348569336964</id><published>2010-04-10T01:32:00.000+09:00</published><updated>2010-04-10T01:32:40.518+09:00</updated><title type='text'>BlazeDS 入門記（Extending applications with factories）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/factory_1.html"&gt;Additional programming topics / Extending applications with factories&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Remoting Service の destination は java のクラスのインスタンスであり、デフォルトでは BlazeDS がこれをインスタンス化する。applicaiton scope の場合は ServletContext に保存され、session scope の場合は FlexSession に保存される。保存時の attribute の名前は destination 名になるが、destination の attribute-id 属性により指定可能。&lt;/li&gt;&lt;li&gt;BlazeDS は、コンポーネントの生成と管理を独自で行うためのプラグインを提供している。&lt;/li&gt;&lt;/ul&gt;ここら辺は、当面使わなそうなので割愛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1529384348569336964?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1529384348569336964/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-extending-applications-with.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1529384348569336964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1529384348569336964'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-extending-applications-with.html' title='BlazeDS 入門記（Extending applications with factories）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3758783018441104377</id><published>2010-04-10T00:53:00.000+09:00</published><updated>2010-04-10T00:53:03.412+09:00</updated><title type='text'>BlazeDS 入門記（The Ajax client library）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/ajaxds_1.html"&gt;Additional programming topics / The Ajax client library&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;JavaScript から BlazeDS サーバと通信するためのライブラリの話。&lt;br /&gt;&lt;br /&gt;当面使う予定が無いので、とりあえず割愛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3758783018441104377?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3758783018441104377/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-ajax-client-library.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3758783018441104377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3758783018441104377'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-ajax-client-library.html' title='BlazeDS 入門記（The Ajax client library）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2094786954874911057</id><published>2010-04-10T00:48:00.000+09:00</published><updated>2010-04-10T00:48:42.701+09:00</updated><title type='text'>BlazeDS 入門記（Run-time configuration）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/runtimeconfig_1.html"&gt;Additional programming topics / Run-time configuration&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;設定ファイルで行うようなことを、プログラムとして実行時に行うという話。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;動的設定は、起動時に MessageBroker でやる方法と、RemoteObject でやる方法がある。&lt;/li&gt;&lt;li&gt;サーバーのスタートアップ時に動的に設定をする場合、flex.messaging.services.AbstractBootstrapService クラスを継承して initialize() メソッドを実装する。start() と stop() メソッドを実装することもできる。そして、services-config.xml ファイルに &amp;lt;service class="dev.service.MyBootstrapService1" id="bootstrap1"/&amp;gt; のように設定する。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2094786954874911057?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2094786954874911057/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-run-time-configuration.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2094786954874911057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2094786954874911057'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-run-time-configuration.html' title='BlazeDS 入門記（Run-time configuration）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2876512394945028395</id><published>2010-04-10T00:32:00.001+09:00</published><updated>2010-04-10T00:32:54.193+09:00</updated><title type='text'>BlazeDS 入門記（Clustering）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_clustering_1.html"&gt;Administering BlazeDS applications / Clustering&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ソフトウェアクラスタリングができるよという話。&lt;br /&gt;&lt;br /&gt;GAE では使えなさそうなので割愛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2876512394945028395?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2876512394945028395/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-security_10.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2876512394945028395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2876512394945028395'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-security_10.html' title='BlazeDS 入門記（Clustering）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-190925929814036475</id><published>2010-04-10T00:28:00.000+09:00</published><updated>2010-04-10T00:28:04.116+09:00</updated><title type='text'>BlazeDS 入門記（Security）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_1.html"&gt;Administering BlazeDS applications / Security&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;サーバ側の destination にセキュリティをかけられるという話。&lt;br /&gt;&lt;br /&gt;J2EE のセキュリティフレームワークや、カスタムのセキュリティ用ロジックを使えるらしい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_2.html#347785"&gt;Securing BlazeDS&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Authentication はユーザーの認証。&lt;/li&gt;&lt;li&gt;Authorization は行動に対する許可。&lt;/li&gt;&lt;li&gt;Authentication を通過しなければ Authorization はできない。&lt;/li&gt;&lt;li&gt;BlazeDS では destination に対してセキュリティ制約をかけることができる。&lt;/li&gt;&lt;li&gt;Basic認証では、credentialが無かったり間違っていたりする場合に HTTP 401 を返すことにより、ブラウザ側でログインダイアログを出す。カスタム認証ではクライアントに失敗を返す。デフォルトはカスタム認証。&lt;/li&gt;&lt;li&gt;BlazeDS では login Command により認証を行う。これはサーバ実装により異なる。Tomcat, JBoss, Oracle Application Server, BEA WebLogic, IBM WebSphere, Adobe JRun 用のものは事前に用意されている。&lt;/li&gt;&lt;li&gt;login command は role を使わない authentication のみも可能。&lt;/li&gt;&lt;li&gt;login command は flex.messaging.security.LoginCommand インタフェースを実装している。これを実装したカスタムの login command を作成することも可能。&lt;/li&gt;&lt;li&gt;channel と endpoint のレベルで https を用いて通信をセキュアにすることも可能。&lt;/li&gt;&lt;li&gt;ベーシックとカスタム認証でセキュリティ制約を作成するステップはほとんど同様。異なるのはクライアントからサーバにどのようにクレデンシャルを渡すか。セキュリティを設定するステップは以下：&lt;/li&gt;&lt;ul&gt;&lt;li&gt;１．services-config.xml ファイル内の security 要素により login command を指定する。&lt;/li&gt;&lt;li&gt;２．services-config.xml ファイル内にセキュリティ制約を定義する。セキュリティ制約はベーシック認証もしくはカスタム認証を設定できる。ひとつか複数のロールの設定もできる。&lt;/li&gt;&lt;li&gt;３．destination 定義からセキュリティ制約を参照させる。&lt;/li&gt;&lt;li&gt;４．カスタム認証を利用する場合、ChannelSet.login() メソッドにてサーバからクレデンシャルを渡す。result event は成功を示し、fault event は失敗を示す。ベーシック認証の場合は、flex アプリケーションでは何もしなくてもOK。ブラウザが勝手に認証ダイアログで対応してくれる。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_3.html#347872"&gt;Configuring security&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;セキュリティ設定は services-config.xml に書いてもいいけど、data-management-config.xml や messaging-config.xml やその他の設定ファイルに書いてもよい。&lt;/li&gt;&lt;li&gt;セキュリティ制約は destination の定義時に参照される。&lt;/li&gt;&lt;li&gt;複数の destination が同一のセキュリティ制約を参照してもかまわない。&lt;/li&gt;&lt;li&gt;デフォルトではセッション毎に認証され、情報は session に格納される。&lt;/li&gt;&lt;li&gt;per-client-authentication プロパティによりクライアント毎に認証をかけることも可能。この場合、データは FlexClient に格納される。&lt;/li&gt;&lt;li&gt;per-client-authentication を true にした場合、ブラウザの状態により認証がリセットされるので、ブラウザのリフレッシュで認証がリフレッシュすることもある。&lt;/li&gt;&lt;li&gt;BlazeDS がデフォルトで用意する login command は session に依存しているので、per-client-authentication を true にする場合はカスタムの　login command を作成し、session が競合しても問題ないようにする必要がある。&lt;/li&gt;&lt;li&gt;単一の destination のみで利用されるセキュリティ制約は、destination 定義中に記述することが可能。&lt;/li&gt;&lt;li&gt;service レベルでデフォルトのセキュリティ制約をかけることもできる。service/default-security-constraint@ref 属性に security-constraint の id を指定すればOK。→ これ便利。&lt;/li&gt;&lt;li&gt;RemoteService の destination の場合、include-methods と exclude-methods にてメソッドレベルの設定が可能。許可されていないメソッドが呼び出された場合は fault イベントが発生する。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_5.html#348164"&gt;Custom authentication&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;カスタム認証の場合、クライアントアプリケーション側で明示的に ChannelSet.login() や ChannelSet.logout() を呼び出す。login にはユーザ名とパスワードが必要。&lt;/li&gt;&lt;li&gt;RemoteObject等のインスタンスに setCredentials() を使うと、呼び出し時に自動的にクレデンシャルをつかってくれるらしい。&lt;/li&gt;&lt;li&gt;useProxy プロパティを true にしておかないと、login(), setCredentials(), setRemoteCredentials() メソッドが機能しないらしい。&lt;/li&gt;&lt;li&gt;per-client-authentication property が false の場合、logout()メソッドは session を invalidate する。&lt;/li&gt;&lt;li&gt;per-client-authentication property が true の場合、logout()メソッドは FlexClient オブジェクトの認証情報をクリアするが、FlexClient や session は破棄しない。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_6.html#348284"&gt;Passing credentials to a proxy service&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;プロキシした先でクレデンシャルが必要な場合のお話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-190925929814036475?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/190925929814036475/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-security.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/190925929814036475'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/190925929814036475'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-security.html' title='BlazeDS 入門記（Security）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4994891718002362960</id><published>2010-04-09T21:07:00.000+09:00</published><updated>2010-04-09T21:07:58.866+09:00</updated><title type='text'>BlazeDS 入門記（Client-side logging）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_logging_1.html"&gt;Administering BlazeDS applications / Logging&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_logging_2.html#342671"&gt;Client-side logging&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;クライアント側でのロギングの話。&lt;br /&gt;&lt;br /&gt;trace() メソッドを使う方法と、Logging API を使う方法がある。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_logging_3.html#352412"&gt;Server-side logging&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;サーバ側でのロギングの話。&lt;br /&gt;&lt;br /&gt;log4j っぽい感じでできますね。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_logging_4.html#343745"&gt;Monitoring and managing services&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;MBeans で実行時のマネジメントができるよという話。&lt;br /&gt;&lt;br /&gt;GAE 環境では不可能なので、割愛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4994891718002362960?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4994891718002362960/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-client-side-logging.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4994891718002362960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4994891718002362960'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-client-side-logging.html' title='BlazeDS 入門記（Client-side logging）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1476569752531704977</id><published>2010-04-09T20:29:00.000+09:00</published><updated>2010-04-09T20:29:20.461+09:00</updated><title type='text'>BlazeDS 入門記（Connecting to the Java Message Service）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/jms_messaging_1.html"&gt;Messaging Service / Connecting to the Java Message Service (JMS)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;JMS をブリッジする場合の話。&lt;br /&gt;&lt;br /&gt;特に使う予定が無いので、目だけ通すにとどめておく。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1476569752531704977?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1476569752531704977/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-connecting-to-java-message.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1476569752531704977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1476569752531704977'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-connecting-to-java-message.html' title='BlazeDS 入門記（Connecting to the Java Message Service）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3416039144420139075</id><published>2010-04-09T17:15:00.002+09:00</published><updated>2010-04-09T20:27:06.454+09:00</updated><title type='text'>BlazeDS 入門記（Using the Messaging Service）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_1.html"&gt;Messaging Service / Using the Messaging Service&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;複数のFlexクライアントとBlazeDSサーバの間で publish-subscribe のメッセージングが可能。&lt;/li&gt;&lt;li&gt;JMSAdapter により JMS の queue や topic にブリッジ可能。&lt;/li&gt;&lt;li&gt;クライアントからのメッセージをサーバ経由で別のクライアントに配送することが可能。&lt;/li&gt;&lt;li&gt;サーバからメッセージをクライアントに配送することも可能。&lt;/li&gt;&lt;li&gt;メッセージは、ユニークID、BlazeDSヘッダ、カスタムヘッダ、ボディ等で構成される。BlazeDSヘッダの先頭はDSという文字列。&lt;/li&gt;&lt;li&gt;クライアントからメッセージを送信するには Producer コンポーネントを使用する。&lt;/li&gt;&lt;li&gt;クライアントでメッセージを受信するには Consumer コンポーネントを使用する。&lt;/li&gt;&lt;li&gt;Consumer は selector expression が使える。&lt;/li&gt;&lt;li&gt;Producer と Consumer は subtopic information を追加可能。&lt;/li&gt;&lt;li&gt;queue-based のメッセージングは、JMSAdapter に JMS Queue をバインディングすることにより可能。&lt;/li&gt;&lt;li&gt;以下、BlazeDS Server Architecture の図&lt;img src="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/images/blazeds_message_arch.png" /&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;チャネルはReal-timeのものを使う。ポーリングでもOK。&lt;/li&gt;&lt;li&gt;Message Service は message destinations のリストと、各 destination にサブスクライブしているクライアント情報を保持する。→ これって Session に持つのかな？&lt;/li&gt;&lt;li&gt;標準的なアダプタとして ActionScriptAdapter と JMSAdapter があり、その他のカスタムアダプタを自作することも可能。&lt;/li&gt;&lt;li&gt;メッセージング系の設定は services-config.xmlにも書けるけど messaging-config.xml に書くのがオススメ。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_3.html#130125"&gt;Working with Producer components&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;クライアント側での Producer の書き方についての説明。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;自動的にリトライする方法もあるが、複数回送信される可能性があるので、副作用のあるメッセージングは注意すること。&lt;/li&gt;&lt;li&gt;配送できたかよくわからんシチュは２つある。それは、Producer.requestTimeout プロパティの値を超えた場合と、応答が帰ってくる前にチャネルの接続が切れた場合。この場合、ErrorMessage.faultCode が ErrorMessage.MESSAGE_DELIVERY_IN_DOUBT になる。&lt;/li&gt;&lt;li&gt;reconnectAttempts は、-1だと無限に再試行して、0だと再試行しない。&lt;/li&gt;&lt;li&gt;reconnectInterval は再試行のインターバル。0だと再試行しない。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_4.html#132296"&gt;Working with Consumer components&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;クライアント側での Consumer の書き方についての説明。&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Consumer.subscribed プロパティは Flex クライアントが destination に subscribe したときに true になる。&lt;/li&gt;&lt;li&gt;Consumer.connected プロパティは Flex クライアントがサーバに接続したときに true になる。&lt;/li&gt;&lt;li&gt;resubscribeAttempts は、subscribe に失敗した際に fault イベントを返す前に何度リトライするかを設定する。-1は無限リトライ、0はリトライしない。→ これって、GAEのような負荷分散環境では必須ですね。まぁ、このような環境でメッセージングが使えるのが前提なんですが、調査してないのでわかりまてん。&lt;/li&gt;&lt;li&gt;resubscribeInterval は リトライ間隔をミリ秒単位で設定する。0の場合はリトライをしない。&lt;/li&gt;&lt;li&gt;AMFChannelのようなリアルタイムでないチャネルに polling-enabled を使用しないで使うこともできる。この場合、クライアント側で Consumer.receive() を自分から呼びに行けばOK。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_5.html#154745"&gt;Using a pair of Producer and Consumer components in an application&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;メッセージを送受信するクライアントアプリケーションの場合、同一の destination をもつ Producer と Consumer のペアができるという話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_6.html#154656"&gt;Message filtering&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;メッセージのフィルタリングの話。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Producer は メッセージヘッダや subtopic information に情報を付加できる。Consumer ではこの情報を元にクライテリアベースのフィルタリングができる。&lt;/li&gt;&lt;li&gt;Consumer コンポーネントは subscribe するときにフィルタリング用のクライテリアをサーバに送信する。このようにして、実際にフィルタリングをする作業はサーバ側で行う。&lt;/li&gt;&lt;li&gt;注意書きとして、フィルタリング用の情報としてメッセージヘッダと subtopic の両方を同時に使用してはいけないと書かれている。→ なんでだろ？&lt;/li&gt;&lt;li&gt;AsyncMessage.headers プロパティにヘッダ情報が格納される。これは連想配列で、キーがヘッダ名で値が文字列か数字となる。&lt;/li&gt;&lt;li&gt;JMS もしくは DS という文字列で始まるヘッダ名は予約されているので使用禁止。&lt;/li&gt;&lt;li&gt;Consumer の selector プロパティにフィルタリングの条件を記述する。これは SQL92 conditional expression syntax をベースにしている。たとえば selector="prop1 &amp;lt; 4" のような書き方ができる。&lt;/li&gt;&lt;li&gt;mx.messaging.MultiTopicConsumer や mx.messaging.MultiTopicProducer を利用すると、複数の topic を単一のイベントハンドラで扱うことができます。&lt;/li&gt;&lt;li&gt;JMSを使用する場合は subtopic は利用不可。→ 基本的に常にヘッダだけ使えば間違いないですね。&lt;/li&gt;&lt;li&gt;subtopic 名は、destination 名にドット区切りでつける。Consumer 側はワイルドカードが使える。ワイルドカードは1つのトークンに閉じて適用される。"foo.*.baz" は "foo.bar.baz" と"foo.aaa.baz" にマッチするが、"foo.bar.cookie" にはマッチしない。&lt;/li&gt;&lt;li&gt;subtopic を有効にするためには、destination の設定で以下のような指定が必要。&lt;/li&gt;&lt;/ul&gt;&lt;pre class="prettyprint"&gt;&amp;lt;allow-subtopics&amp;gt;true&amp;lt;/allow-subtopics&amp;gt;&lt;br /&gt;&amp;lt;subtopic-separator&amp;gt;.&amp;lt;/subtopic-separator&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_7.html#156823"&gt;Configuring the Messaging Service&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;設定の話いろいろ。&lt;br /&gt;&lt;br /&gt;いろいろと設定項目があるので、きちんとおさえておきましょう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3416039144420139075?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3416039144420139075/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-messaging-service.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3416039144420139075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3416039144420139075'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-messaging-service.html' title='BlazeDS 入門記（Using the Messaging Service）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3351551444336847549</id><published>2010-04-08T15:01:00.022+09:00</published><updated>2010-04-08T19:29:13.620+09:00</updated><title type='text'>BlazeDS 入門記（Using the Remoting Service）</title><content type='html'>RPC services / Using the Remoting Service&lt;br /&gt;&lt;br /&gt;以下、特に気になった点&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_2.html#1076189"&gt;RemoteObject component&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Remoting Service destination はデフォルトコンストラクタが必要。&lt;/li&gt;&lt;li&gt;Remoting Service のオブジェクトはステートレスでもステートフルでもOK。&lt;br /&gt;クラウドを意識するならば、アプリケーションスコープの状態は BigTable、セッションレベルの状態なら Session に格納すべきですね。普通にヒープに入れると大変なことに、、、。&lt;/li&gt;&lt;li&gt;RemoteObjectの予約メソッド名に注意しましょう。予約メソッド名にカブった場合、以下のメソッドでワークアラウンド可能。&lt;/li&gt;&lt;/ul&gt;&lt;pre class="prettyprint"&gt;public function getOperation(name:String):Operation&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_3.html#1073403"&gt;Configuring a destination&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;destination のスコープとして、request, application, session の３つの選択肢がある。デフォルトは request スコープ。&lt;br /&gt;ってことは、デフォルト設定だと、毎回インスタンス生成するということか。通常のサービスの場合はきちんとスレッドセーフに作成して application スコープで対応かな。サーバー間レプリケーション不要のキャッシュとか使いたいし。レプリケーションが必要なら memcache 使うべきだけど、その必要のないリードオンリーのキャッシュって結構あるからなぁ。&lt;/li&gt;&lt;li&gt;Remoting Service destination のホワイトリストの作成が可能。その他、メソッドレベルの細かな制約もつけられるらしい。詳細は &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_3.html#347984"&gt;Configuring a destination to use a security constraint&lt;/a&gt; 参照のこと。&lt;br /&gt;この考え方は地味に重要ですね。手動でxmlに指定するのではなく、特定の java インタフェースをホワイトリストとしてくれるような機能があればいいのですが、あるのかな？&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_4.html#1073542"&gt;Calling a service&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;RemoteObject の作成や設定は、ActionScript でも MXML でもOK。&lt;/li&gt;&lt;li&gt;concurrency property の設定が可能。&lt;/li&gt;&lt;ul&gt;&lt;li&gt;multiple : デフォルト。すべての呼び出しが普通に実行される。&lt;/li&gt;&lt;li&gt;single : 既に実行中の場合は、それ以降の呼び出しは瞬時に fault 扱いとなって、サーバ側への呼び出しは行われない。これは連打防止に使えますね。&lt;/li&gt;&lt;li&gt;last : 呼び出しはすべて行われるが、最後の呼び出し結果だけが利用される。長時間かかる処理なので、UI 的には途中で処理を abort して新規に処理を行いたいようなケースで利用できそうですね。利用箇所はかなり慎重に決定する必要がありそうです。&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;RemoteObject のインスタンスは、リモートオブジェクトをあらわしているのではなく、リモートオブジェクトと後処理の組み合わせを表したものという理解でいいのかな？　混乱しやすいポイントかもしれませんね。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_5.html#1076609"&gt;Handling events&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Remote Service の呼び出しが完了すると、result と fault のどちらかのイベントが発生するという話。詳細は &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_08.html#1079290"&gt;Handling service events&lt;/a&gt; 参照のこと。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_6.html#1073555"&gt;&lt;br /&gt;Passing parameters&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;パラメータの渡し方に、明示的に渡す方法と、事前にバインディングしておくものがあるという話。&lt;br /&gt;&lt;br /&gt;何気に showBusyCursor="true" とか設定してますね。&lt;br /&gt;&lt;br /&gt;明示的に渡したほうが分かりやすいような気がしますが、事前にバインディングしたほうがよいケースってどんな場合なんでしょう？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_7.html#1076679"&gt;Handling results&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;リモート呼び出しの結果が、Operation.lastResult か ResultEvent.result から取得するという話。&lt;br /&gt;&lt;br /&gt;その他の話は HttpService や WebService 以外では関係なさそうなので割愛。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_remoteobject_8.html#1078825"&gt;Accessing EJBs and other objects in JNDI&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;EJB や JNDI 経由でオブジェクトにアクセスする場合の話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3351551444336847549?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3351551444336847549/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-remoting-service.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3351551444336847549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3351551444336847549'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-remoting-service.html' title='BlazeDS 入門記（Using the Remoting Service）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8893102026130975307</id><published>2010-04-08T02:23:00.000+09:00</published><updated>2010-04-08T02:23:12.643+09:00</updated><title type='text'>BlazeDS 入門記（Defining and invoking a service component）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_07.html#1073967"&gt;RPC services / Using HTTP and web services / Defining and invoking a service component&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以降、当面 RemotingService 以外使う予定が無いので、RPC services / Using HTTP and web services は割愛。&lt;br /&gt;&lt;br /&gt;TODO：あとでやろう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8893102026130975307?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8893102026130975307/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-defining-and-invoking-service.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8893102026130975307'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8893102026130975307'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-defining-and-invoking-service.html' title='BlazeDS 入門記（Defining and invoking a service component）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5543259416759417751</id><published>2010-04-08T02:17:00.000+09:00</published><updated>2010-04-08T02:17:17.022+09:00</updated><title type='text'>BlazeDS 入門記（Using HTTPService and WebService without a destination）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_04.html#1117729"&gt;RPC services / Using HTTP and web services / Using destinations / Using HTTPService and WebService without a destination&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ProxyServiceを使用しないで HTTPService や WebService を利用する方法の説明。&lt;br /&gt;&lt;br /&gt;基本的に、Flash 側から直接対象のサービスにアクセスする方法や、異なるドメインの場合には crossdomain.xml ファイルが必要とか、そういう話。&lt;br /&gt;&lt;br /&gt;yahoo の場合、http://api.search.yahoo.com/crossdomain.xml とかありますね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5543259416759417751?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5543259416759417751/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-httpservice-and.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5543259416759417751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5543259416759417751'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-httpservice-and.html' title='BlazeDS 入門記（Using HTTPService and WebService without a destination）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8972483007348651285</id><published>2010-04-08T02:08:00.000+09:00</published><updated>2010-04-08T02:08:51.716+09:00</updated><title type='text'>BlazeDS 入門記（Configuring the Proxy Service）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_05.html#1130273"&gt;RPC services / Using HTTP and web services / Using destinations / Configuring the Proxy Service&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Proxy Service のお話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8972483007348651285?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8972483007348651285/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuring-proxy-service.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8972483007348651285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8972483007348651285'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuring-proxy-service.html' title='BlazeDS 入門記（Configuring the Proxy Service）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-227180396629542303</id><published>2010-04-08T02:06:00.000+09:00</published><updated>2010-04-08T02:06:50.608+09:00</updated><title type='text'>BlazeDS 入門記（Using destinations）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_04.html#1073183"&gt;RPC services / Using HTTP and web services / Using destinations&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;主な内容&lt;br /&gt;&lt;ul&gt;&lt;li&gt;destination をサーバ側で集中管理することにより、クライアント側は何も考えずに destination を指定すればサービスを扱うことができる。&lt;/li&gt;&lt;li&gt;destination に認証をかけることができる。&lt;/li&gt;&lt;li&gt;その他、HTTPService と WebService 関連情報いろいろ。 &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-227180396629542303?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/227180396629542303/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-destinations.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/227180396629542303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/227180396629542303'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-destinations.html' title='BlazeDS 入門記（Using destinations）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-9121668860964506174</id><published>2010-04-08T01:56:00.000+09:00</published><updated>2010-04-08T01:56:27.119+09:00</updated><title type='text'>BlazeDS 入門記（RPC components versus other technologies）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_03.html#1077188"&gt;RPC services / Using HTTP and web services / RPC components versus other technologies&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;普通に flash の利点のようなことがかかれてます。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-9121668860964506174?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/9121668860964506174/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-rpc-components-versus-other.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/9121668860964506174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/9121668860964506174'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-rpc-components-versus-other.html' title='BlazeDS 入門記（RPC components versus other technologies）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2077210784520411224</id><published>2010-04-08T01:52:00.001+09:00</published><updated>2010-04-08T01:52:41.294+09:00</updated><title type='text'>BlazeDS 入門記（RPC components）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_02.html#1076957"&gt;RPC services / Using HTTP and web services / RPC components&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;RPC コンポーネントのお話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2077210784520411224?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2077210784520411224/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript_4779.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2077210784520411224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2077210784520411224'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript_4779.html' title='BlazeDS 入門記（RPC components）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-913242488835468313</id><published>2010-04-08T01:41:00.000+09:00</published><updated>2010-04-08T01:41:38.558+09:00</updated><title type='text'>BlazeDS 入門記（Explicitly mapping ActionScript and Java objects）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_4.html#311299"&gt;BlazeDS architecture / Data serialization / Serializing between ActionScript and web services&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ActionScript と web service のシリアライズ規則です。&lt;br /&gt;&lt;br /&gt;気が遠くなりそうです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-913242488835468313?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/913242488835468313/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript_08.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/913242488835468313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/913242488835468313'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript_08.html' title='BlazeDS 入門記（Explicitly mapping ActionScript and Java objects）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3496763402269664944</id><published>2010-04-08T01:37:00.001+09:00</published><updated>2010-04-08T01:38:25.885+09:00</updated><title type='text'>BlazeDS 入門記（Explicitly mapping ActionScript and Java objects）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#296603"&gt;BlazeDS architecture / Data serialization / Serializing between ActionScript and Java / Explicitly mapping ActionScript and Java objects&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Javaオブジェクトの場合、暗黙的に変換されないクラスは setter/getter メソッドと public のプロパティはシリアライズ対象となり、その他はシリアライズされない。&lt;br /&gt;&lt;br /&gt;ActionScriptのオブジェクトの場合もメソッドとかアクセサ等の呼び名が違うだけで内容は同様。&lt;br /&gt;&lt;br /&gt;ActionScript側では [RemoteClass(alias=" ")] メタデータを使うことにより、明示的に Java のクラスにマッピング可能。&lt;br /&gt;&lt;br /&gt;[Transient] も使えるようですね。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#304283"&gt;Converting data from Java to ActionScript&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;変換規則の話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#300626"&gt;Configuring AMF serialization on a channel&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;services-config.xml ファイルに設定可能な serialization 要素の設定項目の話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_3.html#303410"&gt;Using custom serialization between ActionScript and Java&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;java の externalize のようなことができるという話。かなり熱いですね。&lt;br /&gt;&lt;br /&gt;java 側では普通に java.io.Externalizable を実装すればよく、ActionScript 側では flash.utils.IExternalizable を実装すれば OK です。&lt;br /&gt;&lt;br /&gt;いろいろと面白いことができそうですね。オブジェクト毎に最適なフォーマットを適用したり、キャッシュによりシリアライズ・デシリアライズの処理をスキップするとか、デフォルトの方法でシリアライズしつつそのバイナリデータをクライアントとサーバの共通辞書で圧縮して渡すとか。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3496763402269664944?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3496763402269664944/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3496763402269664944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3496763402269664944'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-explicitly-mapping-actionscript.html' title='BlazeDS 入門記（Explicitly mapping ActionScript and Java objects）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-6869030968873922659</id><published>2010-04-08T00:34:00.000+09:00</published><updated>2010-04-08T00:34:25.697+09:00</updated><title type='text'>BlazeDS 入門記（Session life cycle）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/serialize_data_2.html#312520"&gt;BlazeDS architecture / Data serialization / Serializing between ActionScript and Java&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;シリアライズの型変換の話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-6869030968873922659?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/6869030968873922659/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-session-life-cycle_08.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6869030968873922659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6869030968873922659'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-session-life-cycle_08.html' title='BlazeDS 入門記（Session life cycle）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3378533840856823843</id><published>2010-04-07T23:44:00.003+09:00</published><updated>2010-04-08T00:14:54.776+09:00</updated><title type='text'>BlazeDS 入門記（Session life cycle）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconnections_4.html#1076159"&gt;BlazeDS architecture / Managing session data / Session life cycle&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconnections_4.html#1076165"&gt;&lt;br /&gt;Disconnecting from an HTTP-based channel&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;HTTP はステートレスなプロトコルのため、SWF ファイルが切断された時、サーバ上での検出はサーバ上の HTTP セッションタイムアウトのタイミングに依存する。そのため、Flex アプリケーションから BlazeDS サーバに切断を通知させたいのであれば、ChannelSet の disconnectAll() メソッドを JavaScript から呼ばせるようにするとのことらしい。&lt;br /&gt;&lt;br /&gt;流れとしては、以下のように disconnectAll() メソッドを用意し、&lt;br /&gt;&lt;pre class="prettyprint"&gt;private function disconnectAll():void {&lt;br /&gt; remoteObject.channelSet.disconnectAll();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;これを ActionScript メソッドをコンテナから呼び出し可能なものとして登録するための init() メソッドを用意し、&lt;br /&gt;&lt;pre class="prettyprint"&gt;private function init():void {&lt;br /&gt; if (ExternalInterface.available) {&lt;br /&gt;  ExternalInterface.addCallback("disconnectAll", disconnectAll);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;application 要素の creationComplete 属性に init() メソッドを登録します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;creationComplete="init()"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そして JavaScrpt側では&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;    function disconnectAll() {&lt;br /&gt;        document.getElementById("RpcClient").disconnectAll();&lt;br /&gt;    }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;のようにメソッドを用意し、body 要素の onunload 属性を以下のように設定して、unload 時に上記 JavaScrpt の disconnectAll() メソッドが呼ばれるようにします。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;body onunload="disconnectAll()"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;実際にやってみたところ、クライアント側では期待通りの動きをしていることは確認できました。でも、サーバ側でうまくできているのか確認するほうほうがよくわかりません。ひとまず TODO:要確認 として、先に進むことにします。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconnections_4.html#1074309"&gt;Invalidating an HTTP session&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Another complication with using the HTTP protocol is that multiple SWF files share the same HTTP session. When one SWF file disconnects, BlazeDS cannot invalidate the HTTP session. In this scenario, the default behavior on the server is to leave the current session in place for other applications or pages that are using the HTTP session. However, you can use the optional invalidate-session-on-disconnect  configuration property in a channel definition in the services-config.xml file to invalidate the session, as the following example shows: &lt;/blockquote&gt;&lt;pre class="prettyprint"&gt;&amp;lt;channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"&amp;gt;&lt;br /&gt;    &amp;lt;endpoint url="http://servername:port/contextroot/messagebroker/amf"&lt;br /&gt;        class="flex.messaging.endpoints.AMFEndpoint"/&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;invalidate-session-on-disconnect&amp;gt;true&amp;lt;/invalidate-session-on-disconnect&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/channel&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;複数のSWFファイルが接続している状態では、１つのSWFファイルが切断されても HTTP セッションの invalidate をしない。このようなケースで HTTP セッションを invalidate したい場合、services-config.xml ファイルに以下のように invalidate-session-on-disconnect の指定をすると、１つのSWFファイルが切断されると HTTP セッションが invalidate されるようになるという話。&lt;br /&gt;&lt;br /&gt;実験してみましたが、残念ながらサーバ側で invalidation されるのを確認できませんでした。これもひとまず TODO:要確認 として、先に進むことにします。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3378533840856823843?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3378533840856823843/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-session-life-cycle.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3378533840856823843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3378533840856823843'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-session-life-cycle.html' title='BlazeDS 入門記（Session life cycle）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7946796723089194390</id><published>2010-04-07T19:35:00.000+09:00</published><updated>2010-04-07T19:35:57.227+09:00</updated><title type='text'>BlazeDS 入門記（Using the FlexContext class with FlexSession and FlexClient attributes）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconnections_3.html#1076522"&gt;BlazeDS architecture / Managing session data / Using the FlexContext class with FlexSession and FlexClient attributes&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The flex.messaging.FlexContext class is a utility class that exposes the current execution context on the BlazeDS server. It provides access to FlexSession and FlexClient instances associated with the current message being processed. It also provides global context by accessing MessageBroker, ServletContext, and ServletConfig instances. &lt;/blockquote&gt;&lt;br /&gt;FlexContext からは、FlexSession や FlexClient といった BlazeDS 依存の情報から、 ServletContext や ServletConfig など Servlet 系の情報まで。一通り取得することが可能なようですね。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The following example shows a Java class that calls FlexContext.getHttpRequest()  to get an HTTPServletRequest object and calls FlexContext.getFlexSession()  to get a FlexSession object. Exposing this class as a remote object makes it accessible to a Flex client application. Place the compiled class in the WEB_INF/classes directory or your BlazeDS web application.&lt;/blockquote&gt;&lt;pre class="prettyprint"&gt;package myROPackage;&lt;br /&gt;&lt;br /&gt;import flex.messaging.*;&lt;br /&gt;import java.io.*;&lt;br /&gt;import java.util.*;&lt;br /&gt;import javax.servlet.*;&lt;br /&gt;import javax.servlet.http.*;&lt;br /&gt;&lt;br /&gt;public class SessionRO {&lt;br /&gt;&lt;br /&gt;    public HttpServletRequest request;&lt;br /&gt;    public FlexSession session;&lt;br /&gt;&lt;br /&gt;    public SessionRO() {&lt;br /&gt;        request = FlexContext.getHttpRequest();&lt;br /&gt;        session = FlexContext.getFlexSession();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String getSessionId() throws Exception {&lt;br /&gt;        String s = new String();&lt;br /&gt;        s = (String) session.getId();&lt;br /&gt;        return s;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getHeader(String h) throws Exception {&lt;br /&gt;        String s = new String();&lt;br /&gt;        s = (String) request.getHeader(h);&lt;br /&gt;        return h + "=" + s;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;上記、HttpServletRequest と FlexSession の利用例。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7946796723089194390?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7946796723089194390/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-flexcontext-class-with.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7946796723089194390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7946796723089194390'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-flexcontext-class-with.html' title='BlazeDS 入門記（Using the FlexContext class with FlexSession and FlexClient attributes）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2491365760038264224</id><published>2010-04-07T19:09:00.002+09:00</published><updated>2010-04-07T19:11:02.341+09:00</updated><title type='text'>BlazeDS 入門記（FlexClient, MessageClient, and FlexSession objects）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconnections_2.html#1075276"&gt;BlazeDS architecture / Managing session data / FlexClient, MessageClient, and FlexSession objects&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The FlexClient object&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Every Flex application, written in MXML or ActionScript, is eventually compiled into a SWF file. When the SWF file connects to the BlazeDS server, a flex.messaging.client.FlexClient object is created to represent that SWF file on the server. SWF files and FlexClient instances have a one-to-one mapping. In this mapping, every FlexClient instance has a unique identifier named id, which the BlazeDS server generates. An ActionScript singleton class, mx.messaging.FlexClient, is also created for the Flex application to access its unique FlexClient id.&lt;/blockquote&gt;&lt;br /&gt;FlexClient のインスタンスは SWF ファイルに対応するらしいです。&lt;br /&gt;&lt;br /&gt;と言われてもよく分からないので、同一ブラウザで２つのタブを開いてアクセスしてみました。&lt;br /&gt;&lt;br /&gt;アクセスされた側で FlexContext.getFlexClient().getId() を表示するようにしたところ、ブラウザ毎ではなく、クライアント毎に異なるIDが振られることが確認できました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The MessageClient object&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;If a Flex application contains a Consumer component (flex.messaging.Consumer), the server creates a corresponding flex.messaging.MessageClient instance that represents the subscription state of the Consumer component. Every MessageClient has a unique identifier named clientId. The BlazeDS server can automatically generate the clientId value, but the Flex application can also set the value in the Consumer.clientId property before calling the Consumer.subscribe() method.&lt;/blockquote&gt;&lt;br /&gt;Consumer 毎に個別にユニークな ID が自動的に振られるが、自前で振ることも可能という話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The FlexSession object&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;A FlexSession object represents the connection between the Flex application and the BlazeDS server. Its life cycle depends on the underlying protocol, which is determined by the channels and endpoints used on the client and server, respectively.&lt;br /&gt;&lt;br /&gt;If an HTTP-based channel, such as AMFChannel or HTTPChannel, is used in the Flex application, the FlexSession on the BlazeDS server is scoped to the browser and wraps an HTTP session. If the HTTP-based channel connects to a servlet-based endpoint, the underlying HTTP session is a J2EE HttpSession object.&lt;/blockquote&gt;&lt;br /&gt;FlexSession は Flex アプリケーションと BlazeDS 間のコネクションをあらわし、channel と endpoint によって決定されるプロトコルによってライフサイクルが変わるという話。&lt;br /&gt;&lt;br /&gt;AMFChannel や HTTPChannel のような HTTP ベースの channel の場合、FlexSession は HTTP Session のラップになるらしい。&lt;br /&gt;&lt;br /&gt;HttpSession と本当に同じ振る舞いをするか、一応確認してみることにしよう。&lt;br /&gt;&lt;br /&gt;ということで、同一ブラウザで２つのタブや別ウィンドウを開いてアクセスする実験をしてみました。&lt;br /&gt;&lt;br /&gt;アクセスされた側で FlexContext.getFlexSession().getId() を表示するようにしたところ、同一ブラウザでは同一の ID が表示されました。&lt;br /&gt;&lt;br /&gt;別ブラウザではどうなるかということで、IE と FF で試してみたところ、別ブラウザでは異なる ID となりました。&lt;br /&gt;&lt;br /&gt;予想通り、HttpSession と同じ振る舞いになりました。めでたし。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The relationship between FlexClient, MessageClient, and FlexSession classes&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;A FlexClient object can have one or more FlexSession instances associated with it depending on the channels that the Flex application uses. For example, if the Flex application uses one HTTPChannel, one FlexSession represents the HTTP session created for that HTTPChannel on the BlazeDS server.&lt;br /&gt;&lt;br /&gt;A FlexSession can also have one or more FlexClients associated with it. For example, when a SWF file that uses an HTTPChannel is opened in two tabs, two FlexClient instances are created in the BlazeDS server (one for each SWF file), but there is only one FlexSession because two tabs share the same underlying HTTP session.&lt;br /&gt;&lt;br /&gt;In terms of hierarchy, FlexClient and FlexSession are peers whereas there is a parent-child relationship between FlexClient/FlexSession and MessageClient. A MessageClient is created for every Consumer component in the Flex application. A Consumer must be contained in a single SWF file and it must subscribe over a single channel. Therefore, each MessageClient is associated with exactly one FlexClient and one FlexSession.&lt;br /&gt;&lt;br /&gt;If either the FlexClient or the FlexSession is invalidated on the server, it invalidates the MessageClient. This behavior matches the behavior on the client. If you close the SWF file, the client subscription state is invalidated. If you disconnect the channel or it loses connectivity, the Consumer component is unsubscribed.&lt;/blockquote&gt;&lt;br /&gt;FlexSession、FlexClient、MessageClient のインスタンスの関係が、FlexSession 1:* FlexClient 1-* MessageClient という話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Event listeners for FlexClient, MessageClient, and FlexSession&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;いろいろとリスナーがあるとよという話。&lt;br /&gt;&lt;br /&gt;ひとまず、FlexClientListener と FlexSessionListener について実験してみました。&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;FlexClient.addClientCreatedListener(new FlexClientListener() {&lt;br /&gt; public void clientDestroyed(FlexClient flexClient) {&lt;br /&gt;  System.out.println("clientDestroyed : " + flexClient.getId());&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void clientCreated(FlexClient flexClient) {&lt;br /&gt;  System.out.println("clientDestroyed : " + flexClient.getId());&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;FlexSession.addSessionCreatedListener(new FlexSessionListener() {&lt;br /&gt; public void sessionDestroyed(FlexSession flexSession) {&lt;br /&gt;  System.out.println("sessionDestroyed : " + flexSession.getId());&lt;br /&gt; }&lt;br /&gt; public void sessionCreated(FlexSession flexSession) {&lt;br /&gt;  System.out.println("sessionCreated : " + flexSession.getId());&lt;br /&gt; }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;上記のような形でリスナーを登録後、新規にアクセスしてみると、下記のようなメッセージが表示されました。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;clientCreated : 4590A4C9-5A1E-5D26-BE7F-21101AD66C98&lt;br /&gt;sessionCreated : ngskddnnb17q&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;clientDestroyed と sessionDestroyed がどのタイミングで呼び出されるのかは、振る舞いを追う限りはよく分かりませんでした。後でソースを見てみようと思います。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Log categories for FlexClient, MessageClient, and FlexSession classes&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;FlexClient, MessageClient, FlexSession のログカテゴリは以下という話。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Client.FlexClient&lt;/li&gt;&lt;li&gt;Client.MessageClient&lt;/li&gt;&lt;li&gt;Endpoint.FlexSession&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2491365760038264224?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2491365760038264224/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-flexclient-messageclient-and.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2491365760038264224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2491365760038264224'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-flexclient-messageclient-and.html' title='BlazeDS 入門記（FlexClient, MessageClient, and FlexSession objects）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-6015388297232386313</id><published>2010-04-07T16:00:00.001+09:00</published><updated>2010-04-07T16:01:50.605+09:00</updated><title type='text'>BlazeDS 入門記（Using BlazeDS clients and servers behind a firewall）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconfig_5.html#1075415"&gt;BlazeDS architecture / Channels and endpoints / Using BlazeDS clients and servers behind a firewall&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Because servlet-based endpoints use standard HTTP requests, communicating with clients inside firewalls usually works, as long as the client-side firewall has the necessary ports open. Using the standard HTTP port 80 and HTTPS port 443 is recommended because many firewalls block outbound traffic over non-standard ports.&lt;/blockquote&gt;&lt;br /&gt;クライアント側がファイアウォール内にある場合は多くの場合 HTTP と HTTPS のポートしか外に出られないので、標準の80番と443番を使いましょうという話。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The protocols that the various client channels use are hard coded. For example, the AMFChannel always uses HTTP, while the SecureAMFChannel always uses HTTPS. One thing to watch for when using a SecureAMFChannel/SecureAMFEndpoint combination is an issue with Internet Explorer related to no-cache response headers and HTTPS. By default, no-cache response headers are enabled on HTTP-based endpoints. This causes problems for Internet Explorer browsers. You can suppress these response headers by adding the following configuration property to your endpoint:&lt;/blockquote&gt;&lt;pre class="prettyprint"&gt;&amp;lt;add-no-cache-headers&amp;gt;false&amp;lt;/add-no-cache-headers&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;IEだと HTTPS の時に no-cache ヘッダをつけるとうまく動作しないので、HTTPS と IE を併用したいのなら上記の設定をして no-cache ヘッダをつけないようにしましょうという話。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;When you have a firewall/reverse HTTP proxy in your deployment that handles SSL for you, you must mix and match your channel and endpoint. You need the client to use a secure channel and the server to use an insecure endpoint, as the following example shows:&lt;/blockquote&gt;&lt;pre class="prettyprint"&gt;&amp;lt;channel-definition id="secure-amf" class="mx.messaging.channels.SecureAMFChannel"&amp;gt;&lt;br /&gt;   &amp;lt;endpoint url="https://[firewall ip:port]/{context.root}/messagebroker/amf" &lt;br /&gt;   class="flex.messaging.endpoints.AMFEndpoint"/&amp;gt;&lt;br /&gt;   &amp;lt;properties&amp;gt;&lt;br /&gt;   &amp;lt;add-no-cache-headers&amp;gt;false&amp;lt;/add-no-cache-headers&amp;gt;&lt;br /&gt;   ...&lt;br /&gt;&lt;/pre&gt;&lt;blockquote&gt;The channel class uses HTTPS to hit the firewall/proxy, and the endpoint URL must point at the firewall/proxy. Because SSL is handled in the middle, you want the endpoint class used by BlazeDS to be the insecure AMFEndpoint and your firewall/proxy must hand back requests to the HTTP port of the BlazeDS server, not the HTTPS port.&lt;/blockquote&gt;&lt;br /&gt;firewall で HTTPS を受ける場合、endpoint の url 設定を firewall 向けに書きましょうという話。でもって、もし wirewall 側で HTTPS で受けて裏のサーバでは HTTP で受けるのであれば、endpoint のクラスは Secure 無しのものにしましょうねという話。channel と endpoint のクラスの組み合わせが通常と異なるのがポイントですね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-6015388297232386313?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/6015388297232386313/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-blazeds-clients-and.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6015388297232386313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6015388297232386313'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-using-blazeds-clients-and.html' title='BlazeDS 入門記（Using BlazeDS clients and servers behind a firewall）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-6459526506577245697</id><published>2010-04-07T15:23:00.001+09:00</published><updated>2010-04-07T15:24:57.369+09:00</updated><title type='text'>BlazeDS 入門記（Channel and endpoint recommendations）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconfig_4.html#1196763"&gt;BlazeDS architecture / Channels and endpoints / Channel and endpoint recommendations&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下、特に気になった点。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;RPC したいだけなら AMFChannel を使いましょう。&lt;/li&gt;&lt;li&gt;サーバからデータをプッシュしたい場合でも、RPC 用とメッセージング用でチャネルを分ける必要はない。&lt;/li&gt;&lt;li&gt;可能なら、単一の channel set かつ１つの channel しか使わないのがベスト。&lt;/li&gt;&lt;/ul&gt;&amp;nbsp;「3. AMFChannel/Endpoint with simple polling and piggybacking enabled (no fallback needed) 」が GAE 環境で実現できるのかは調査したいなぁ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-6459526506577245697?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/6459526506577245697/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-channel-and-endpoint.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6459526506577245697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6459526506577245697'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-channel-and-endpoint.html' title='BlazeDS 入門記（Channel and endpoint recommendations）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2206982234561639819</id><published>2010-04-07T14:53:00.003+09:00</published><updated>2010-04-10T20:58:16.534+09:00</updated><title type='text'>BlazeDS 入門記（Configuring channels with servlet-based endpoints）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconfig_3.html#1089380"&gt;BlazeDS architecture / Channels and endpoints / Configuring channels with servlet-based endpoints&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下、特に気になった点。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AMFEndpoint と HTTPEndpoint はシンプルな servlet ベースの endpointで、RPC の時はポーリング無しで普通にアクセスし、メッセージングの場合はポーリングがロングポーリングをするのが普通。&lt;/li&gt;&lt;li&gt;polling-enabled はオプション。デフォルトでは false。（ってドキュメントに書かれているけどたぶんウソ。実際にやってみると、未指定でもポーリングされる。明示的に false を指定するとポーリングされなくなる。）&lt;/li&gt;&lt;li&gt;polling-interval-millis はオプション。デフォルトは 3000。0 に設定すると、現在ポーリング中のメッセージを受けると即座に次のポーリングを行う。&lt;/li&gt;&lt;li&gt;wait-interval-millis はオプション。デフォルトは 0。サーバー側がポーリングを受け付けた際に、データが存在しない場合にどれだけ待つかの設定。値が0だとサーバーは一切待たない。値が-1だと次のメッセージが用意できるまでサーバはレスポンスを返さないで待ち続ける。BlazeDS 的には1分を推奨しているが、GAE環境では30秒ルールがあるのでせいぜい20秒程度が妥当か？っていうか、GAE環境でポーリング自体が妥当なのか検証する必要があるが、、、。&lt;/li&gt;&lt;li&gt;client-wait-interval-millis はオプション。デフォルトは 0。クライアント側がポーリングのレスポンスを受けた後にどれだけ休むかを指定する。0を指定すると、polling-interval-millis のみによって次のポーリングのタイミングを決定する。このオプションは polling interval を上書きするので、この値を 1 にすると、ポーリングのメッセージを受け付けるとすぐに次のポーリングを始めるので、リアルタイムストリーミングのようになる。サーバー側で待ち時間を発生させていない環境では、このオプションを使わずに polling-interval-millis を使いましょう。&lt;/li&gt;&lt;li&gt;max-waiting-poll-requests はオプション。デフォルトは 0。サーバー側のポーリング返信待ち状態スレッド数の上限。このスレッド数が上限に達すると、それ以降のポーリングリクエストは即座に返却される（wait-interval-millis のような動きになる）。&lt;/li&gt;&lt;li&gt;piggybacking-enabled はオプション。デフォルトは false。これを true にすると、同一チャネルのあらゆるメッセージのレスポンスをポーリングのレスポンス代わりに使うことができる。&lt;/li&gt;&lt;li&gt;login-after-disconnect はオプション。デフォルトは false。これを true にすると、メッセージがセッション切れで認証できなくなってエラーになっった場合に、自動的に最認証してメッセージも再送してくれる。これは便利かも。クライアント側のコードで、この手のエラーハンドリングをしなくてもよくなるわけですねー。&lt;/li&gt;&lt;li&gt;flex-client-outbound-queue-processor はオプション。pub-subモデルの場合、サーバ側にsubscribeしたクライアントの数だけ外向けのキューのプロセッサのインスタンスができるらしい。そのプロセッサ実装へのプロパティをこのプロパティで指定するとのこと。&lt;/li&gt;&lt;li&gt;serialization はオプションで、endpoint に対する serialization のプロパティ。独自の externalize とかできるっぽい。燃えますね。&lt;/li&gt;&lt;li&gt;connect-timeout-seconds はオプション。クライアント側のチャネルの接続試行のタイムアウト時間設定。&lt;/li&gt;&lt;li&gt;invalidate-session-on-disconnect はオプション。デフォルトでは disabled。enabledにすると、サーバがクライアントチャネルからの disconnect メッセージを受け取ると、対応するセッションを無効にする。同一ブラウザで複数の swf ファイルを起動したときなど、ブラウザレベルでセッションが共有されるわけだが、そのような場合でも１つの disconnect メッセージで問答無用にセッションが切られるということですね。&lt;/li&gt;&lt;li&gt;add-no-cache-headers はオプション。デフォルトでは true。pragma no-cache header をつける。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-2206982234561639819?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/2206982234561639819/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuring-channels-with.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2206982234561639819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/2206982234561639819'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuring-channels-with.html' title='BlazeDS 入門記（Configuring channels with servlet-based endpoints）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-8704199881078206901</id><published>2010-04-06T21:19:00.000+09:00</published><updated>2010-04-06T21:19:21.708+09:00</updated><title type='text'>BlazeDS 入門記（About channels and endpoints）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcconfig_2.html#1073571"&gt;BlazeDS architecture / Channels and endpoints / About channels and endpoints&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下、特に気になった点。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;channel はクライアント側のオブジェクト。&lt;/li&gt;&lt;li&gt;channel は BlazeDS server の endpoint と通信する。&lt;/li&gt;&lt;li&gt;channel の設定は services-config.xml に記述する。&lt;/li&gt;&lt;li&gt;endpoiint のURLの指定方法が気になる。url="http://servername:8400/myapp/messagebroker/amf" のような感じの指定のうち、myapp はコンテキストパスで messagebroker は web.xml  MessageBroker の servlet-mapping から自明ですよね。となると、最後の amf の部分がどのようにして決定されるのか知りたい。何でもいいのかな？ということで、実際に試してみた。結論としては何でもOKでした。サーバ側にデプロイされている設定と、flash がコンパイルされた時点の設定が同一であればOKです。もちろん、全 endpoint でユニークである必要はありますが。&lt;/li&gt;&lt;li&gt;Flex コンポーネントは channel set が使える。&lt;/li&gt;&lt;li&gt;flex のコンパイル時に -services オプションによって services-config.xml を指定する。flash builder でプロジェクトを作成すると、プロジェクト作成時に設定した情報を元に勝手に -services オプションが付与される。compiler のオプション設定で手動で変更可能。&lt;/li&gt;&lt;li&gt;アプリケーションで動的に destination を作成する場合、application-level default channel というのが使えるらしい。&lt;/li&gt;&lt;li&gt;channel set で fallback 用の設定が可能。（でも、正直言って、自社案件ではこの機能をつかってうれしい状況が思い浮かばない。）&lt;/li&gt;&lt;li&gt;HTTPS を使う endpoint は、クラス名の先頭に Secure が付く。&lt;/li&gt;&lt;li&gt;Piggybacking provides lightweight pseudo polling。えせポーリングですねｗ。使いたいけど、ユーザー数が多い場合に topic や queue の管理がどうなるんだろ？要確認ですね。&lt;/li&gt;&lt;li&gt;Piggybacking は、polling enabled になっている channel でも利用可能。インターバルを長めに設定しておいて、アクセスがなければそのインターバルでポーリングして、アクセスがあればそのデータに相乗りするという形。これも便利そうだ。GAEとの親和性の高い JMS のようなサービスがあれば完璧ですね。ないのかな？要調査ですね。&lt;/li&gt;&lt;li&gt;polling と　piggybacking を組み合わせる際、piggyback でデータを取得した際に、そこからポーリング時間がリセットされるのかそうじゃないのかは、要確認ですね。&lt;/li&gt;&lt;li&gt;long polling も使える。これはポーリングをかけたときにデータがなければそのまま待機するという仕組みだが、GAE 環境では不可ですね。残念。&lt;/li&gt;&lt;li&gt;streaming も GAE 環境では不可ですね。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-8704199881078206901?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/8704199881078206901/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-about-channels-and-endpoints.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8704199881078206901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/8704199881078206901'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-about-channels-and-endpoints.html' title='BlazeDS 入門記（About channels and endpoints）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-1062136537980002921</id><published>2010-04-06T14:55:00.001+09:00</published><updated>2010-04-06T15:09:30.641+09:00</updated><title type='text'>BlazeDS 入門記（Configuration elements）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcarch_5.html#1101520"&gt;BlazeDS architecture / BlazeDS architecture / About configuration files/ Configuration elements&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;services-config.xml の説明。&lt;br /&gt;見たまんまなので割愛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-1062136537980002921?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/1062136537980002921/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuration-elements.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1062136537980002921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/1062136537980002921'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-configuration-elements.html' title='BlazeDS 入門記（Configuration elements）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3486479308064179067</id><published>2010-04-06T14:40:00.000+09:00</published><updated>2010-04-06T14:40:21.315+09:00</updated><title type='text'>BlazeDS 入門記（About configuration files）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcarch_4.html#1076247"&gt;BlazeDS architecture / BlazeDS architecture / About configuration files&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下、特に気になった点。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BlazeDS の設定は services-config.xml ファイルに記述する。デフォルトのロケーションは WEB-INF/flex だが、web.xml 内の MessageBrokerServlet の設定により変更することも可能。&lt;/li&gt;&lt;li&gt;service 定義用のファイルを services-config.xml に include することができる（remoting-config.xmlとか）。インラインでも書けるらしい。（でも、やらないほうがいいですよね。）&lt;/li&gt;&lt;li&gt;{server.name}等の token を使うと、環境から動的に情報を決定できる。でも Air アプリでは機能しないので注意。（Webで配布するのが前提でないのだから当然ですよね。）&lt;/li&gt;&lt;li&gt;jvm のオプションでもトークンを渡せるらしい。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3486479308064179067?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3486479308064179067/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-about-configuration-files.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3486479308064179067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3486479308064179067'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-about-configuration-files.html' title='BlazeDS 入門記（About configuration files）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3597224354194942901</id><published>2010-04-06T14:15:00.000+09:00</published><updated>2010-04-06T14:15:41.553+09:00</updated><title type='text'>BlazeDS 入門記（BlazeDS server architecture）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcarch_3.html#1101478"&gt;BlazeDS architecture / BlazeDS architecture / BlazeDS server architecture&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下、アーキテクチャの図&lt;br /&gt;&lt;br /&gt;&lt;img src="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/images/blazeds_server_arch.png" /&gt;&lt;br /&gt;&lt;br /&gt;以下、特に気になるポイント。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;EndPoint は MessageBrokerServlet によって実現されている。&lt;/li&gt;&lt;li&gt;HTTP session listener（flex.messaging.HttpFlexSession）によって BlazeDS は HTTP Session をサポートする。&lt;/li&gt;&lt;li&gt;channel と endpoint は同じフォーマットにする必要がある。&lt;/li&gt;&lt;li&gt;channel の設定は WEB-INF/flex/services-config.xml ファイルで行う。&lt;/li&gt;&lt;li&gt;MessageBroker はメッセージのルーティングを行う。&lt;/li&gt;&lt;li&gt;destination 側にセキュリティ制約がかかっている場合は、MessageBroker が認証を行う。（&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/services_security_1.html"&gt;Security&lt;/a&gt;参照のこと）&lt;/li&gt;&lt;li&gt;RemotingService は remoting-config.xml に、HTTPProxyService は proxy-config.xml に、MessageService は messaging-config.xml に設定する。&lt;/li&gt;&lt;li&gt;RemotingDestination は JavaAdapter を、HTTPProxyDestination は HTTPProxyAdapter か SOAPAdapter を、MessageDestination は ActionScriptAdapter か JMSAdapter を使用する。&lt;/li&gt;&lt;li&gt;カスタムの Adapter の作成も可能。&lt;/li&gt;&lt;li&gt;設定は xml ファイルではなくスタートアップ時にプログラム的に動的に行うこともできる。（個人的には、設定内容が宣言的な性質を持っている限りは、定義ファイル内で定義すべきだと思う。）&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3597224354194942901?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3597224354194942901/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-blazeds-server-architecture.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3597224354194942901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3597224354194942901'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-blazeds-server-architecture.html' title='BlazeDS 入門記（BlazeDS server architecture）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-9148868031027574038</id><published>2010-04-06T12:28:00.000+09:00</published><updated>2010-04-06T12:28:21.400+09:00</updated><title type='text'>BlazeDS 入門記（BlazeDS client architecture）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcarch_2.html#1075116"&gt;BlazeDS architecture / BlazeDS architecture / BlazeDS client architecture&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;クライアントとサーバの通信の低レベルの内容はチャネルが抽象化している。&lt;/li&gt;&lt;li&gt;チャネルは、検出とフェイルオーバーを行う集合にグループ化される。&lt;/li&gt;&lt;li&gt;BlazeDS サーバと通信する RemoteObject、HTTPService、WebService、Producer、Consumer コンポーネントは Flex SDK の rpc.swc コンポーネントライブラリに含まれている。&lt;/li&gt;&lt;li&gt;チャネルに接続できない場合、チャネルセット中の次のチャネルを試行する。&lt;/li&gt;&lt;li&gt;AMFChannel と HTTPChannel を必要に応じて使い分けましょう。&lt;/li&gt;&lt;li&gt;クライアントとサーバ間のやり取りはすべてメッセージを介して行われる。&lt;/li&gt;&lt;li&gt;すべてのメッセージはクライアントサイド（ActionScript）とサーバサイド（java）の実装が存在する。&lt;/li&gt;&lt;li&gt;サーバープッシュ API を使用してサーバからクライアントにメッセージを配信することもできる。&lt;/li&gt;&lt;li&gt;request/reply パターンと publish/subscribe パターンがある。&lt;/li&gt;&lt;/ul&gt;という話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-9148868031027574038?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/9148868031027574038/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-blazeds-client-architecture.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/9148868031027574038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/9148868031027574038'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-blazeds-client-architecture.html' title='BlazeDS 入門記（BlazeDS client architecture）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-3738734329322582569</id><published>2010-04-06T11:37:00.002+09:00</published><updated>2010-04-06T11:44:15.197+09:00</updated><title type='text'>BlazeDS 入門記（Deploying your application）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_7.html#173495"&gt;Getting started with BlazeDS  / Building and deploying BlazeDS applications / Deploying your application&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;本番環境によってデプロイ方法が変わるという話。ひとつめの方法は、アプリと関連ファイルをすべて BlazeDS Web アプリにいれてしまい、単一の war ファイルを作成し、それを本番環境にデプロイするやり方。&lt;br /&gt;&lt;br /&gt;もうひとつの方法は、複数の BlazeDS アプリを１つの Web アプリに入れる方法。この場合、自分の新規のアプリを走らせるために必要なディレクトリを追加した新たな拡張されたBlazeDSアプリを持つことになるらしい。（WEB-INF/flex フォルダのようなものが複数になったり web.xml 内の MessageBroker Servlet の定義が複数になったりする状況のことかな？）&lt;br /&gt;&lt;br /&gt;BlazeDS アプリケーションを本番環境にデプロイするためには、以下を含めたすべての必要なものを入れましょうとのこと。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;クライアントアプリケーションの入ったコンパイル済みの SWF ファイル。&lt;/li&gt;&lt;li&gt;Flex Builder によって作成された HTML ラッパー。mxmlc コンパイラを使った場合は自作のもの。&lt;/li&gt;&lt;li&gt;サーバーサイドアプリの入った jar ファイル。&lt;/li&gt;&lt;li&gt;実行時に必要なもの。&lt;/li&gt;&lt;li&gt;BlazeDS Web アプリ。&lt;/li&gt;&lt;li&gt;BlazeDS 設定ファイル群。&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-3738734329322582569?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/3738734329322582569/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-deploying-your-application.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3738734329322582569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/3738734329322582569'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-deploying-your-application.html' title='BlazeDS 入門記（Deploying your application）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-7462830369788318386</id><published>2010-04-05T23:58:00.003+09:00</published><updated>2010-04-07T19:01:37.586+09:00</updated><title type='text'>BlazeDS 入門記（Debugging your application）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_6.html#175144"&gt;Getting started with BlazeDS  / Building and deploying BlazeDS applications / Debugging your application&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以下のようなデバッグができるらしい。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;コードにブレークポイントがセットできる。&lt;/li&gt;&lt;li&gt;アプリケーションの実行を、一時停止、一時停止からの復帰、停止の制御ができる。&lt;/li&gt;&lt;li&gt;コードのステートメントに深く潜ったり戻ったりできる。&lt;/li&gt;&lt;li&gt;変数の内容を確認できる。&lt;/li&gt;&lt;li&gt;実行中のアプリ内で expression を evaluate できる。&lt;/li&gt;&lt;/ul&gt;Flex アプリケーションのデバッグは、trace() を埋め込むようなシンプルなものから、行レベルのデバッグまでできる。Flex Builder のデバッガやコマンドラインのデバッガ使えるらしい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_6.html#191803"&gt;Using Flash Debug Player&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;コマンドラインデバッガもしくは Flex Builder デバッガを使用するためには、Flash Debug Player のインストールと設定が必要です。&lt;br /&gt;&lt;br /&gt;どうも記事が古いのか私の環境がおかしいのか分かりませんが、ドキュメントに書かれた情報と私の環境が異なるようです。右クリックメニューに Show Redraw Regions（領域の再描画）のような項目が表示されるらしいのですが、、、。&lt;br /&gt;&lt;br /&gt;とりあえず、&lt;a href="http://www.adobe.com/support/flashplayer/downloads.html"&gt;http://www.adobe.com/support/flashplayer/downloads.html&lt;/a&gt; から Adobe Flash Player 10 — Debugger Versions をインストールしてみました。&lt;br /&gt;&lt;br /&gt;FlexBuilder 上のデバッガからアプリを起動すると、trace()メソッドによるデバッグ情報の出力や、ブレークポイントの利用やステップ実行や変数の内容確認などができました。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_6.html#192051"&gt;Using logging to debug your application&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Client-side logging &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;クライアントサイドでは、直接ログファイルにメッセージを書き出す方法と、Flex から生成されたメッセージをログファイルに書き出すように設定する方法があるらしい。前者は trace() で、後者が Logging API らしい。後者はログレベルとかを log4j のように設定できる感じですね。&lt;br /&gt;&lt;br /&gt;設定は mm.cfg ファイルで行うらしい。ということで、以下のように設定しました。&lt;br /&gt;&lt;pre class="prettyprint"&gt;ErrorReportingEnable=1&lt;br /&gt;TraceOutputFileEnable=1&lt;br /&gt;&lt;/pre&gt;配置場所は、WinXP の場合は C:\Documents and Settings\username フォルダです。&lt;br /&gt;&lt;br /&gt;trace() を埋め込んだ Flex アプリケーション Flash Builder から実行したところ、通常モードでもデバッグモードでも C:\Documents and Settings\username\Application Data\Macromedia\Flash Player\Logs\flashlog.txt ファイルが生成され、trace() の内容が表示されました。&lt;br /&gt;&lt;br /&gt;mxmlファイル内に &lt;mx:tracetarget level="2"&gt; を入れたところ、Flex からのログも出力されるようになりました。&lt;br /&gt;&lt;br /&gt;ちなみに、ドキュメントでは &lt;mx:tracetarget loglevel="2"&gt; となっていましたが、Flash Builder 4 では loglevel 要素は存在しませんでした。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Server-side logging&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;サーバサイドのログ設定は services-config.xml に記述します。デフォルトでは標準出力に吐かれます。&lt;br /&gt;&lt;br /&gt;利用可能なログレベルは以下のようになっているらしいです。&lt;/mx:tracetarget&gt;&lt;/mx:tracetarget&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;mx:tracetarget level="2"&gt;&lt;mx:tracetarget loglevel="2"&gt;All&lt;/mx:tracetarget&gt;&lt;/mx:tracetarget&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;Debug&lt;/li&gt;&lt;li&gt;Info&lt;/li&gt;&lt;li&gt;Warn&lt;/li&gt;&lt;li&gt;Error&lt;/li&gt;&lt;li&gt;None&lt;/li&gt;&lt;/ul&gt;&lt;mx:tracetarget level="2"&gt;&lt;mx:tracetarget loglevel="2"&gt; &lt;br /&gt;以下、ログレベルを利用した設定例です。&lt;br /&gt;&lt;/mx:tracetarget&gt;&lt;/mx:tracetarget&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;logging&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;!-- You may also use flex.messaging.log.ServletLogTarget. --&amp;gt;&lt;br /&gt;    &amp;lt;target class="flex.messaging.log.ConsoleTarget" level="Debug"&amp;gt;&lt;br /&gt;        &amp;lt;properties&amp;gt;&lt;br /&gt;            &amp;lt;prefix&amp;gt;[Flex]&amp;lt;/prefix&amp;gt;&lt;br /&gt;            &amp;lt;includeDate&amp;gt;false&amp;lt;/includeDate&amp;gt;&lt;br /&gt;            &amp;lt;includeTime&amp;gt;false&amp;lt;/includeTime&amp;gt;&lt;br /&gt;            &amp;lt;includeLevel&amp;gt;false&amp;lt;/includeLevel&amp;gt;&lt;br /&gt;            &amp;lt;includeCategory&amp;gt;false&amp;lt;/includeCategory&amp;gt;&lt;br /&gt;        &amp;lt;/properties&amp;gt;&lt;br /&gt;        &amp;lt;filters&amp;gt;&lt;br /&gt;            &amp;lt;pattern&amp;gt;Endpoint&amp;lt;/pattern&amp;gt;&lt;br /&gt;            &amp;lt;!--&amp;lt;pattern&amp;gt;Service.*&amp;lt;/pattern&amp;gt;--&amp;gt;&lt;br /&gt;            &amp;lt;!--&amp;lt;pattern&amp;gt;Message.*&amp;lt;/pattern&amp;gt;--&amp;gt;&lt;br /&gt;        &amp;lt;/filters&amp;gt;&lt;br /&gt;    &amp;lt;/target&amp;gt;&lt;br /&gt;&amp;lt;/logging&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;設定は logging 要素を services-config.xml ファイルの services-config 要素直下に配置してあげれば OK です。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_6.html#176493"&gt;Measuring application performance&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;メッセージ処理部分のタイミングとサイジングに関するデータが取れるらしいです。&lt;br /&gt;&lt;br /&gt;デフォルトではこの機能は動作してないが、動作させるとメッセージサイズ、サーバ処理時間、ネットワーク移動時間が取得できるらしい。この情報は、クライアント側がデータ送信、データ受信、メッセージ送信後の応答受信時に取得可能らしい。この情報のサブセットはサーバ上のアクセスでも取得できるらしい（ちょっと意味分からん）。&lt;br /&gt;&lt;br /&gt;useProxy プロパティを false にしているとき以外はこのデータが取得できるらしい。&lt;br /&gt;&lt;br /&gt;チャネル定義に以下の定義を設定すればデータが取れるらしい。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;record-message-times&amp;gt;&lt;br /&gt;&amp;lt;record-message-sizes&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/mpi_1.html#182914"&gt;Measuring message processing performance&lt;/a&gt; に詳しい説明があるので、ここでは割愛。&lt;/record-message-sizes&gt;&lt;/record-message-times&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-7462830369788318386?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/7462830369788318386/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-debugging-your-application.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7462830369788318386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/7462830369788318386'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazeds-debugging-your-application.html' title='BlazeDS 入門記（Debugging your application）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-6653882728969003548</id><published>2010-04-05T17:41:00.001+09:00</published><updated>2010-04-05T17:42:04.553+09:00</updated><title type='text'>BlazeDS入門記（Running the BlazeDS sample applications）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_5.html#173498"&gt;Getting started with BlazeDS / Building and deploying BlazeDS applications / Building your server-side application&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;サーバサイドの BlazeDS アプリケーションを java で作成し、javac コンパイラでコンパイルします。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_5.html#174684"&gt;Creating a simple Java class to return data to the client&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;A common reason to create a server-side Java class is to represent data returned to the client. For example, the client-side RemoteObject component lets you access the methods of server-side Java objects to return data to the client.&lt;/blockquote&gt;&lt;br /&gt;ここでは、サーバサイドの java クラスを作成する一般的な理由のひとつは、クライアントに返却されるデータを表現することであると書かれています。&lt;br /&gt;&lt;br /&gt;この文脈での java クラスは純粋なデータクラスであり、ドメインモデルに所属しないクラスであることを意識しておくことが重要ですね。&lt;br /&gt;&lt;br /&gt;データクラスだけではなく BlazeDS の destination となるサービスもドメインモデル内のものではなく、 Remote Facade だと割り切るのが重要だと思います。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The Test Drive sample application contains the Accessing Data Using Remoting sample where the client-side code uses the RemoteObject component to access product data on the server. The Product.java class represents that data. After starting the BlazeDS server and the samples database, view this example by opening the following URL in a browser: http://localhost:8400/samples/testdrive-remoteobject/index.html.&lt;/blockquote&gt;&lt;br /&gt;Product.java をデータとしてやり取りするサンプルがあるよんという話ですね。&lt;br /&gt;&lt;br /&gt;以下略ｗ&lt;br /&gt;&lt;br /&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_5.html#174893"&gt;&lt;br /&gt;Creating a Java class that extends a BlazeDS class&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;data adapter を自作する場合など、BlazeDS のクラスを拡張したクラスを作成することもあるよという話。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-6653882728969003548?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/6653882728969003548/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsrunning-blazeds-sample_05.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6653882728969003548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6653882728969003548'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsrunning-blazeds-sample_05.html' title='BlazeDS入門記（Running the BlazeDS sample applications）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-5579219468396456910</id><published>2010-04-05T15:54:00.000+09:00</published><updated>2010-04-05T15:54:54.170+09:00</updated><title type='text'>BlazeDS入門記（Running the BlazeDS sample applications）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_3.html#174618"&gt;Getting started with BlazeDS  / Building and deploying BlazeDS applications / Running the BlazeDS sample applications&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS Turnkey 版のサンプルアプリの起動方法について書かれています。&lt;br /&gt;&lt;br /&gt;特に語ることは無いっす。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-5579219468396456910?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/5579219468396456910/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsrunning-blazeds-sample.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5579219468396456910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/5579219468396456910'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsrunning-blazeds-sample.html' title='BlazeDS入門記（Running the BlazeDS sample applications）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-6907544104163218120</id><published>2010-04-05T15:49:00.002+09:00</published><updated>2010-04-05T15:51:20.438+09:00</updated><title type='text'>BlazeDS入門記（Setting up your development environment）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#173418"&gt; Getting started with BlazeDS  / Building and deploying BlazeDS applications / Setting up your development environment&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#167988"&gt;Installation directory structure&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ここでは BlazeDS Turnkey ZIP file のディレクトリ構造を説明しています。&lt;br /&gt;&lt;br /&gt;あんま興味ないので割愛ｗ&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#172781"&gt;Accessing a web application&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ここではサンプルのアクセス方法が書かれています。&lt;br /&gt;&lt;br /&gt;あんま興味ないので割愛ｗｗ&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#171641"&gt;Creating a web application&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;BlazeDS アプリケーションをWebアプリケーションとごっちゃにしないで分けておきましょうという話。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#172800"&gt;Defining the directory structure for client-side code&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;クライアントアプリを開発する際のディレクトリ構造についての説明。&lt;br /&gt;&lt;br /&gt;ここら辺については、おいら自身がまた Flex のアプリ開発に慣れてないので、とりあえず読んでおくだけに留めておくことにしよう。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/build_apps_2.html#173318"&gt;Defining the directory structure for server-side code&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;サーバサイドの開発をする際のディレクトリ構造についての説明。&lt;br /&gt;&lt;br /&gt;IDE 環境とか maven とか絡んできそうですね。おいおい研究していくことにしよう。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-6907544104163218120?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/6907544104163218120/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedssetting-up-your-development.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6907544104163218120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/6907544104163218120'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedssetting-up-your-development.html' title='BlazeDS入門記（Setting up your development environment）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-4765237347459647860</id><published>2010-04-05T13:50:00.009+09:00</published><updated>2010-04-05T14:45:52.675+09:00</updated><title type='text'>BlazeDS入門記（Example BlazeDS applications）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcoverview_4.html#1072892"&gt;Getting started with BlazeDS  / Introduction to BlazeDS / Example BlazeDS applications&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;今回は、ほとんどマニュアルをなぞってるだけです。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;RPC service example&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Remoting Service は BlazeDS に含まれる RPC サービスの１つです。クライアントは Remoting Service によりサーバ上の POJO にアクセスできます。&lt;br /&gt;&lt;br /&gt;この例では、クライアントから渡された文字列をエコーバックする EchoService.java という java のクラスをサーバ上にデプロイします。&lt;br /&gt;&lt;br /&gt;EchoService.java&lt;br /&gt;&lt;pre class="prettyprint"&gt;package remoting;&lt;br /&gt;public class EchoService&lt;br /&gt;{&lt;br /&gt;    public String echo(String text) {&lt;br /&gt;        return "Server says: I received '" + text + "' from you";&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;echo()メソッドは String の引数を受け、それにテキストを付加したものを返します。EchoService.java をコンパイル後、EchoService.class を WEB-INF/classes/remoting ディレクトリ以下に配置します。java クラスが BlazeDS に一切依存していないところが重要。&lt;br /&gt;&lt;br /&gt;destination を定義し、ひとつ以上の channel を参照します。WEB-INF/flex/remoting-config.xml　を編集して、EchoService.class を Remoting Service の destination として設定します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;destination id="echoServiceDestination" channels="my-amf"&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;source&amp;gt;remoting.EchoService&amp;lt;/source&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/destination&amp;gt;&lt;br /&gt;&lt;/pre&gt;source 要素は java クラスを参照しています。そして channels 属性は my-amf という名前の channel を参照します。&lt;br /&gt;&lt;br /&gt;以下のように WEB-INF/flex/services-config.xml に my-amf channel を定義します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"&amp;gt;&lt;br /&gt;    &amp;lt;endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" &lt;br /&gt;        class="flex.messaging.endpoints.AMFEndpoint"/&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;polling-enabled&amp;gt;false&amp;lt;/polling-enabled&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/channel-definition&amp;gt;&lt;br /&gt;&lt;/pre&gt;この channel 定義は Flex クライアントがサーバ上の AMFEndpoint に non-polling AMFChannel を使用することを指定しています。&lt;br /&gt;&lt;br /&gt;今回作成する Flex client application は EchoService へのアクセスに RemoteObject コンポーネントを使用します。RemoteObject コンポーネントは destination を特定するために destination を使用します。ユーザがボタンをクリックすると、サーバ上の echo() メソッドが呼び出されます。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;!-- intro\intro_remoting.mxml --&amp;gt; &lt;br /&gt;&amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" &lt;br /&gt;    width="100%" height="100%"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Script&amp;gt;&lt;br /&gt;        &amp;lt;![CDATA[&lt;br /&gt;            import mx.rpc.events.FaultEvent;&lt;br /&gt;            import mx.rpc.events.ResultEvent;&lt;br /&gt;&lt;br /&gt;            // Send the message in response to a Button click.&lt;br /&gt;            private function echo():void {&lt;br /&gt;                var text:String = ti.text;&lt;br /&gt;                remoteObject.echo(text);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Handle the recevied message.&lt;br /&gt;            private function resultHandler(event:ResultEvent):void {&lt;br /&gt;                ta.text += "Server responded: "+ event.result + "\n";&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Handle a message fault.&lt;br /&gt;            private function faultHandler(event:FaultEvent):void {&lt;br /&gt;                ta.text += "Received fault: " + event.fault + "\n";&lt;br /&gt;            }&lt;br /&gt;        ]]&amp;gt;&lt;br /&gt;    &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:RemoteObject id="remoteObject"&lt;br /&gt;        destination="echoServiceDestination"&lt;br /&gt;        result="resultHandler(event);"&lt;br /&gt;        fault="faultHandler(event);"/&amp;gt;&lt;br /&gt;        &lt;br /&gt;    &amp;lt;mx:Label text="Enter a text for the server to echo"/&amp;gt;&lt;br /&gt;    &amp;lt;mx:TextInput id="ti" text="Hello World!"/&amp;gt;&lt;br /&gt;    &amp;lt;mx:Button label="Send" click="echo();"/&amp;gt;&lt;br /&gt;    &amp;lt;mx:TextArea id="ta" width="100%" height="100%"/&amp;gt;&lt;br /&gt;&amp;lt;/mx:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;Flash Builder か mxmlc コンパイラを使用してクライアントアプリケーションを SWF ファイルにコンパイルし、Webアプリケーションにデプロイします。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Messaging Service example&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;クライアントアプリケーションは、Messaging Service により他のクライアントとのメッセージの送受信ができます。今回の例では、同一の BlazeDS destination へのメッセージの送受信をする Flex アプリケーションを作成します。&lt;br /&gt;&lt;br /&gt;次のように WEB-INF/flex/messaging-config.xml に messaging destination を定義します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;destination id="MessagingDestination" channels="my-amf-poll"/&amp;gt;&lt;br /&gt;&lt;/pre&gt;次のように WEB-INF/flex/services-config.xml に my-amf-poll channel を定義します。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;channel-definition id="my-amf-poll" class="mx.messaging.channels.AMFChannel"&amp;gt;&lt;br /&gt;    &amp;lt;endpoint&lt;br /&gt;        url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpoll"&lt;br /&gt;        class="flex.messaging.endpoints.AMFEndpoint"/&amp;gt;&lt;br /&gt;    &amp;lt;properties&amp;gt;&lt;br /&gt;        &amp;lt;polling-enabled&amp;gt;true&amp;lt;/polling-enabled&amp;gt;&lt;br /&gt;        &amp;lt;polling-interval-seconds&amp;gt;1&amp;lt;/polling-interval-seconds&amp;gt;&lt;br /&gt;    &amp;lt;/properties&amp;gt;&lt;br /&gt;&amp;lt;/channel-definition&amp;gt;&lt;br /&gt;&lt;/pre&gt;このチャネル定義はインターバルが１秒のポーリングチャネルを定義しています。そのため、このクライアントはサーバに１秒ごとにポーリングメッセージを送ります。ポーリングチャネルはクライアントが変更通知を受けるもっとも簡単な方法です。他の選択肢としては、piggybacking を用いたポーリング、long-polling、streaming があります。&lt;br /&gt;&lt;br /&gt;以下の Flex クライアントアプリケーションはメッセージの送信に Producer コンポーネントを、受信に Consumer コンポーネントを使用しています。メッセージを送信するために Producer はまず AsyncMessage クラスのインスタンスを作成してその body 要素にメッセージをセットします。そして Producer.send() メソッドによって送信します。メッセージを受信するためには、Consumer はまず Consumer.subscribe() メソッドにより特定の destination に対して送信されるメッセージに対するサブスクライブをします。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0"?&amp;gt;&lt;br /&gt;&amp;lt;!-- intro\intro_messaging.mxml --&amp;gt; &lt;br /&gt;&amp;lt;mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" &lt;br /&gt;    width="100%" height="100%"&lt;br /&gt;    creationComplete="consumer.subscribe();"&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Script&amp;gt;&lt;br /&gt;        &amp;lt;![CDATA[&lt;br /&gt;            import mx.messaging.events.MessageFaultEvent;&lt;br /&gt;            import mx.messaging.events.MessageEvent;&lt;br /&gt;            import mx.messaging.messages.AsyncMessage;&lt;br /&gt;            import mx.messaging.Producer;&lt;br /&gt;            import mx.messaging.Consumer;&lt;br /&gt;&lt;br /&gt;            // Send the message in response to a Button click.&lt;br /&gt;            private function sendMessage():void {&lt;br /&gt;                var msg:AsyncMessage = new AsyncMessage();&lt;br /&gt;                msg.body = "Foo";&lt;br /&gt;                producer.send(msg);&lt;br /&gt;            }&lt;br /&gt;            &lt;br /&gt;            // Handle the received message.&lt;br /&gt;            private function messageHandler(event:MessageEvent):void {&lt;br /&gt;                ta.text += "Consumer received message: "+ event.message.body + "\n";&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // Handle a message fault.&lt;br /&gt;            private function faultHandler(event:MessageFaultEvent):void {&lt;br /&gt;                ta.text += "Received fault: " + event.faultString + "\n";&lt;br /&gt;            }&lt;br /&gt;        ]]&amp;gt;&lt;br /&gt;    &amp;lt;/mx:Script&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Producer id="producer"&lt;br /&gt;        destination="MessagingDestination"&lt;br /&gt;        fault="faultHandler(event);"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Consumer id="consumer"&lt;br /&gt;        destination="MessagingDestination"&lt;br /&gt;        fault="faultHandler(event);"&lt;br /&gt;        message="messageHandler(event);"/&amp;gt;&lt;br /&gt;&lt;br /&gt;    &amp;lt;mx:Button label="Send" click="sendMessage();"/&amp;gt;&lt;br /&gt;    &amp;lt;mx:TextArea id="ta" width="100%" height="100%"/&amp;gt;&lt;br /&gt;&amp;lt;/mx:Application&amp;gt;&lt;br /&gt;&lt;/pre&gt;Flash Builder か mxmlc コンパイラを使用してクライアントアプリケーションを SWF ファイルにコンパイルし、Webアプリケーションにデプロイします。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3144177333818784642-4765237347459647860?l=kcw-diary.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kcw-diary.blogspot.com/feeds/4765237347459647860/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsexample-blazeds-applications.html#comment-form' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4765237347459647860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3144177333818784642/posts/default/4765237347459647860'/><link rel='alternate' type='text/html' href='http://kcw-diary.blogspot.com/2010/04/blazedsexample-blazeds-applications.html' title='BlazeDS入門記（Example BlazeDS applications）'/><author><name>せい</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_IYJOWXQH1bw/S2SJaLp6BII/AAAAAAAAAAw/OZYzTD0EjAw/S220/inu.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3144177333818784642.post-2713381057466364264</id><published>2010-04-05T10:28:00.001+09:00</published><updated>2010-04-05T10:42:59.140+09:00</updated><title type='text'>BlazeDS入門記（BlazeDS features ）</title><content type='html'>&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcoverview_3.html#1087716"&gt;Getting started with BlazeDS  / Introduction to BlazeDS / BlazeDS features&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The following figure shows the main features of BlazeDS:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/images/blazeds_features.png" /&gt;&lt;br /&gt;&lt;br /&gt;上の図が BlazeDS の主な特徴を示しているとのことです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/lcoverview_3.html#1088191"&gt;BlazeDS core features&lt;/a&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The BlazeDS core features include the RPC services and the Messaging Service.&lt;/blockquote&gt;&lt;br /&gt;RPC services と Messaging Service が core features らしい。ということは、図中の Service Adapters と Proxy Service は異なる位置づけを持つということですね。どう違うのかな？&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;RPC services&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The Remote Procedure Call (RPC) services are designed for applications in which a call and response model is a good choice for accessing external data. RPC services let a client application make asynchronous requests to remote services that process the requests and then return data directly to the client. You can access data through client-side RPC components that include HTTP GET or POST (HTTP services), SOAP (web services), or Java objects (remote object services).&lt;/blockquote&gt;&lt;br /&gt;普通にRPCですが、コールバック形式というのがポイントですね。同期呼び出しはサポートしなさそうです。ActionScript や JavaScript から利用されることを考えれば、特に違和感はありません。&lt;br /&gt;&lt;br /&gt;クライアント側では、RPC用のコンポーネントとして HTTP GET or POST (HTTP services), SOAP (web services), Java objects (remote object services) の３種類が用意されているとのこと。REST につなぐ場合、Web Service につなぐ場合、BlazeDS につなぐ場合で使い分けるという感じでしょうか。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Use RPC components when you want to provide enterprise functionality, such as proxying of service traffic from different domains, client authentication, whitelists of permitted RPC service URLs, server-side logging, localization support, and centralized management of RPC services. BlazeDS lets you use RemoteObject components to access remote Java objects without configuring them as SOAP-compliant web services.&lt;/blockquote&gt;&lt;br /&gt;異なるドメインからのトラフィックのプロキシ、クライアント認証、許可されたRPCサービスURLのホワイトリスト、サーバサイドロギング、ローカライゼーション、RCP サービスの中央管理等に RPC を使うらしい。&lt;br /&gt;&lt;br /&gt;プロキシはクロスドメインへの対応かな。さまざまなドメインの REST サービスを多用する場合などには重宝するかも。&lt;br /&gt;&lt;br /&gt;クライアント認証はセッション単位とクライアント単位が使えるらしい。HttpSession がレプリケーションされていないサーバ環境でも使えるかどうかが気になるところですね。&lt;br /&gt;&lt;br /&gt;許可されたRPCサービスURLのホワイトリストは、普通に crossdomain.xml を使うことを指しているのかな？&lt;br /&gt;&lt;br /&gt;サーバサイドロギングは、log4j のような感じの機能を独自に持っているということっぽい。&lt;br /&gt;&lt;br /&gt;ローカライゼーションは、locale 毎のリソースを用意する方法っぽい。&lt;br /&gt;&lt;br /&gt;RCP サービスの中央管理というのは、destination を利用することらしい。クライアントは destination を設定するだけで RPC サービスにアクセスできる。サーバ側でどのようなメソッドに関連付けられているかとか、プロキシ経由でほかのドメインのRESTサービスにアクセスしているとか、クライアント側では一切考えなくていいということですね。&lt;br /&gt;&lt;br /&gt;クライアント側で RemoteObject コンポーネントを使うと、SOAP準拠の Web Service として設定しなくてもリモートの Java オブジェクトにアクセスできるらしい。&lt;br /&gt;&lt;br /&gt;ここら辺の各特長については、後の章の詳しい説明に期待しましょう。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;A client-side RPC component calls a remote service. The component then stores the response data from the service in an ActionScript object from which you can easily obtain the data. The client-side RPC components are the HTTPService, WebService, and RemoteObject components.&lt;/blockquote&gt;&lt;br /&gt;クライアント側には HTTPService, WebService, RemoteObject 用の RPC コンポーネントがあって、リモートサービスから取得したデータを ActionScript object に格納してくれるらしい。そういう低レベルの処理を自動でやってくれるのは楽でいいですね。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Note: You can use Flex SDK without the BlazeDS proxy service to call HTTP services or web services directly. You cannot use RemoteObject components without BlazeDS or ColdFusion.&lt;/blockquote&gt;&lt;br /&gt;BlazeDS proxy service を利用しなくても Flex SDK を利用して HTTP services や web services を直接呼び出せるらしい。しかし、BlazeDS もしくは ColdFusion 無しでは RemoteObject コンポーネントとしてアクセスすることはできないとのこと。&lt;br /&gt;&lt;br /&gt;詳細は &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/rpc_httpws_01.html#1099711"&gt;Using HTTP and web services&lt;/a&gt; 参照のこと。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Messaging Service&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The Messaging Service lets client applications communicate asynchronously by passing messages back and forth through the server. A message defines properties such as a unique identifier, BlazeDS headers, any custom headers, and a message body.&lt;/blockquote&gt;&lt;br /&gt;Messaging Service では、クライアントとサーバ間で相互にメッセージのやり取りができるらしい。メッセージはユニーク ID や BlazeDS ヘッダやカスタムヘッダやメッセージボディによって定義されるらしい。決められたヘッダがあってカスタムヘッダがあってデータ本体がある点は、普通のHTTPアクセスに似てますね。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Client applications that send messages are called message producers. You define a producer in a Flex application by using the Producer component. Client applications that receive messages are called message consumers. You define a consumer in a Flex application by using the Consumer component. A Consumer component subscribes to a server-side destination and receives messages that a Producer component sends to that destination. For more information on messaging, see &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_1.html#171137"&gt;Using the Messaging Service&lt;/a&gt;.&lt;/blockquote&gt;&lt;br /&gt;メッセージを送信するクライアントアプリケーションをプロデューサと呼び、Flex アプリケーション内で Producer コンポーネントを使用することによって定義するらしい。&lt;br /&gt;&lt;br /&gt;メッセージを受信するクライアントアプリケーションをコンシューマと呼び、Flex アプリケーション内で Consumer コンポーネントを使用することによって定義するらしい。&lt;br /&gt;&lt;br /&gt;Consumer コンポーネントはサーバ側の destination にサブスクライブして、Producer コンポーネントがその destination に送信したメッセージを受け取るらしい。&lt;br /&gt;&lt;br /&gt;ひとことで言うと、JMS のようなメッセージングサービスが使えるということですね。&lt;br /&gt;&lt;br /&gt;詳細は &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/messaging_1.html#171137"&gt;Using the Messaging Service&lt;/a&gt; 参照のこと。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The Messaging Service also supports bridging to JMS topics and queues on an embedded or external JMS server by using the JMSAdapter. Bridging lets Flex client applications exchange messages with Java client applications. For more information, see &lt;a href="http://livedocs.adobe.com/blazeds/1/blazeds_devguide/jms_messaging_1.html#263647"&gt;Connecting to the Java Message S
