yui-frameworks でとりあえず Django AMF を使ってみた

Flex/AIR開発でデザイナとの協業を楽にする「yui」(1/3) - @IT
Flex ってなんかフレームワーク的なものないんかなーと思って探してたら、yui-frameworks なるものがあるってことを知った。実は1年ほど前に素の Flex と Django AMF を使って色々いじってたんだけども、またいじる必要が出て来て yui-frameworks がなんかよさげなんで yui-frameworks から Django AMF を使ってみることにした。
とりあえず、今回つなぐとこまで。
Flex 側のコードは ここの記事のサンプルの劣化版。

まずは yui-frameworks の導入

yuiを使ったFlexアプリを作って、便利さを体感しよう(1/4) - @IT
ほぼここの記事通り。ただ、名前を yui→ stmapp、datavisualization → test って変えてある。んで、そんな感じで Flex プロジェクトを作って libs ディレクトリに yui-frameworks-1.0.0-beta-2-rc1.swc を追加した。

Django AMF のインストール

DjangoAMF - Django AMF
以前使ってたのはもうだいぶ前なので当然のごとく新しいバージョンが出てた。なのでこっから最新版をとってきてインストール。

Django 側のコードをいじくる

UserManual - Django AMF
マニュアルに従って色々やってく。今回は諸事情により stmapp ってプロジェクトを作って、そんなかに tm ってアプリケーションを作ってやってみた。

settings.py

ミドルウェアに追加。

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'amf.django.middleware.AMFMiddleware',
)
urls.py

URL 設定を追加。
マニュアルには「アプリ名.views」しか書いてないだけど、なぜか「プロジェクト名.アプリ名.views」ってしないと動かなかった。ほんとここのせいでずっと動かん動かんって悩んどったがな。。

urlpatterns = patterns('',
    # Django AMF
    (r'^gateway/testService/(.*)', 'amf.django.views',
     {'views': 'stmapp.tm.views'}),

     (r'^admin/doc/', include('django.contrib.admindocs.urls')),
     (r'^admin/(.*)', admin.site.root),
)
tm/views.py

tmってアプリん中の views に適当な足し算する処理を書いた。

# AMFテスト関数
def calculate(request, arg1, arg2):
    return arg1 + arg2

Flex 側のコードもいじくる

ボタン押したらテキストエリアに処理結果が表示される的なものを作ってくことにした。

main.mxml

大元。チュートリアルどおり。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:akabana="http://akabana.seasar.org/yui/mxml" 
    xmlns:tes="stmapp.example.test.view.*" layout="vertical">

    <mx:Style source="assets/ExampleClasses.css" />

    <tes:ExampleView />

    <akabana:YuiFrameworkMixin>
        <akabana:conventions>
            stmapp.example.test
        </akabana:conventions>
    </akabana:YuiFrameworkMixin>
    
</mx:Application>
ExampleView.mxml

見た目のなんやかんやを配置。

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">

    <mx:Box horizontalAlign="right">
        <mx:Button id="testButton" label="テスト" />
    </mx:Box>

    <mx:TextArea id="testArea">
    </mx:TextArea>

</mx:Panel>
ExampleAction.as

イベント関連を色々書いてく場所らしい。イベントハンドラの名前の付け方次第で自動で Views のオブジェクトと結びつけてくれる。
ここでの Django AMF の呼び出しかたが全然わからなんだ。なのでいらんかもしれんけど一応試行錯誤をコメントでのっけときます。

package stmapp.example.test.action
{
    import flash.events.MouseEvent;
    
    import org.seasar.akabana.yui.framework.event.FrameworkEvent;
    import org.seasar.akabana.yui.logging.Logger;
    import org.seasar.akabana.yui.service.event.ResultEvent;
    import org.seasar.akabana.yui.service.event.FaultEvent;
    import org.seasar.akabana.yui.service.event.FaultStatus;
    import org.seasar.akabana.yui.service.event.*;
    import org.seasar.akabana.yui.service.PendingCall;
    import org.seasar.akabana.yui.service.rpc.RpcResponder;
    import org.seasar.akabana.yui.service.rpc.remoting.*;
    import stmapp.example.test.logic.ExampleLogic;
    import stmapp.example.test.helper.ExampleHelper;

    public class ExampleAction
    {
        public function ExampleAction()
        {
        }
        
        public var logic:ExampleLogic;
        public var helper:ExampleHelper;
        public var testService:RemotingService;
        
        public var logger:Logger = Logger.getLogger(ExampleAction);
        
        //色々初期化
        public function onAssembleCompleteHandler(event:FrameworkEvent):void{
            logger.debug(">>> call onAssembleCompleteHandler <<<");
            testService.gatewayUrl = 'http://localhost:8000/gateway/';
            
            // 思いつき その1    
            //testService.addEventListener(ResultEvent.RESULT, testServiceCalculateResultHandler);
            //testService.addEventListener(FaultEvent.FAULT, testServiceCalculateFaultHandler);

            // 思いつき その2
            //var calculate:RemotingOperation = new RemotingOperation(testService, "calculate");
            //calculate.addEventListener(ResultEvent.RESULT, testServiceCalculateResultHandler);
            //calculate.addEventListener(FaultEvent.FAULT, testServiceCalculateFaultHandler);
            //calculate.showBusyCursor = true;
            //testService.addOperation("calculate");
            
            // 思いつき その3
            //trace(Sample.gatewayUrl);
            //var pc:PendingCall = testService.calculate;
            //pc.addResponder(new RpcResponder(testServicecalculateResultHandler, testServicecalculateFaultHandler));

            // 思いつき その4
            //testService.calculate.addResponder(new RpcResponder(testServiceCalculateResultHandler, testServiceCalculateFaultHandler));
        }
        
        public function testButtonClickHandler(event:MouseEvent):void {
            logger.debug(">>> call testButtonHandler <<<");
            trace(testService.operations['calculate']);
            logic.doCalculate(testServicecalculateResultHandler, testServicecalculateFaultHandler, 1, 2);
        }

       public function testServicecalculateResultHandler(event:ResultEvent):void {
            logger.debug(">>> call ResultHandler <<<");
            helper.testPrint(int(event.result))
        }
        
        public function testServicecalculateFaultHandler(event:FaultEvent):void {
            logger.debug(String(event.faultStatus.details));
            logger.debug(">>> call FaultHandler <<<");
        }

    }
}
ExampleHelper.as

見た目を変えたりする処理を書くらしい。

package stmapp.example.test.helper
{   
    import stmapp.example.test.view.ExampleView;

    import flash.printing.PrintJob;
    import org.seasar.akabana.yui.logging.Logger;
    import org.seasar.akabana.yui.logging.LogManager;
    import mx.rpc.AsyncToken;
    
    public class ExampleHelper
    {
        public function ExampleHelper()
        {
        }
        
        public var view:ExampleView;
        private var logger:Logger = Logger.getLogger(ExampleHelper);
        
        public function testPrint(data:int):void {
            logger.debug(">>> called testPrint function <<<");
            view.testArea.data = data;
        }

    }
}
ExampleLogic.as

たしかデータの処理とかサービス関連の処理とか。

package stmapp.example.test.logic
{
    import org.seasar.akabana.yui.service.PendingCall;
    import org.seasar.akabana.yui.service.event.ResultEvent;
    import org.seasar.akabana.yui.service.rpc.remoting.*;
    
    public class ExampleLogic
    {
        public function ExampleLogic()
        {
        }
        
        public var testService:RemotingService;
        
        public function doCalculate(resultHandler:Function, faultHandler:Function, arg1:int, arg2:int):void {
            var pc:PendingCall = testService.calculate(arg1, arg2);
            pc.addResponceHandler(resultHandler, faultHandler);
        }

    }
}
ExampleClasses.css

なんか色々呼び出せるようにするらしい。あと見た目いじるのもここ?

/* CSS file */
ExampleView {
    action: ClassReference(
    "stmapp.example.test.action.ExampleAction");
    helper: ClassReference(
    "stmapp.example.test.helper.ExampleHelper");
    logic: ClassReference(
    "stmapp.example.test.logic.ExampleLogic");
}

動かす

そんで manage.py runserver して Flex Builder でデバッグ実行したらだいたいこんな感じになって、めでたくちゃんとサービスが呼び出されてくれやした。

main.html
Uploaded with plasq's Skitch!


んーー、これでええのんかなぁ。ActionScript 全然わかってなくてほんとなんとなくでしか書いてないので、たぶん不自然なところやおかしいところが多々あると思うのよねぇ。つーか絶対ありまくるのよねぇ。特に サービスの呼び出しや登録んところ。あれは絶対もっといい方法があると思う。あと yui-frameworks 的な分割の仕方もあんまよく理解してないしなぁ。。
なので、なんか微妙なところとかあったら指摘していただけると非常にありがたいっす。
あ、あと全然関係ないけどはてなダイアリーって ActionScript のシンタックスハイライトできんのですか?なんかよーわからんかったんで今回 JavaScript のやつで代用してみたんだけど。。