2008/03/14

Flex Builder 2から3へのアップグレード

Upgrade to Flex Builder 3 Standard from US$99 (12,600円)
Upgrade to Flex Builder 3 Professional from US$299 (37,800円)
今って1ドル100円くらいだから、ドルで買った方が安くね?

2008/03/11

view(MXML)とlogic(ActionScript)の分離


今更ながらやってみた。
確かにMXMLにScriptがなくてスッキリしてイイな。(全体のコード量は若干増えるけど)

  • MXMLはFlexBuilderでペタペタ、CSSでデザインを小奇麗に。

  • ActionScriptでコードをガリガリ。


[分離前]
ComplexView.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:logic="hoge.logic.*"
width="360" height="300" layout="absolute" title="左から右へ受け流す">
<mx:Script>
<![CDATA[
private function clickCopyButtonHandler(event:MouseEvent):void {
rightField.text = leftField.text;
}

private function clickClearButtonHandler(event:MouseEvent):void {
leftField.text = "";
rightField.text = "";
}
]]>
</mx:Script>

<mx:TextInput left="10" top="10" id="leftField" width="100"/>
<mx:TextInput top="10" id="rightField" right="10" width="100"
editable="false"/>
<mx:Button y="10" label="Copy" id="copyButton" horizontalCenter="0"
click="clickCopyButtonHandler(event)"/>
<mx:Button y="60" label="Clear" horizontalCenter="0" id="clearButton"
click="clickClearButtonHandler(event)"/>
</mx:Panel>

[分離後]
SimpleView.mxml(view)

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:logic="hoge.logic.*"
width="360" height="300" layout="absolute" title="左から右へ受け流す">
<logic:SimpleViewLogic id="logic"/>

<mx:TextInput left="10" top="10" id="leftField" width="100"/>
<mx:TextInput top="10" id="rightField" right="10" width="100"
editable="false"/>
<mx:Button y="10" label="Copy" id="copyButton" horizontalCenter="0"
click="logic.clickCopyButtonHandler(event)"/>
<mx:Button y="60" label="Clear" horizontalCenter="0" id="clearButton"
click="logic.clickClearButtonHandler(event)"/>
</mx:Panel>

SimpleViewLogic.as(logic)

package hoge.logic {
import hoge.view.SimpleView;

import flash.events.MouseEvent;

import mx.core.IMXMLObject;
import mx.events.FlexEvent;

public class SimpleViewLogic implements IMXMLObject {
private var view:SimpleView;

public function initialized(document:Object, id:String):void {
view = document as SimpleView;
}

public function clickCopyButtonHandler(event:MouseEvent):void {
view.rightField.text = view.leftField.text;
}

public function clickClearButtonHandler(event:MouseEvent):void {
view.leftField.text = "";
view.rightField.text = "";
}
}
}

  1. ロジック部分を非ビジュアルオブジェクトとして、IMXMLObjectを実装したActionScriptのクラスで定義する。

  2. ビュー側(MXML)では、上記の非ビジュアルオブジェクトのタグを記述する。

ってだけ。
単体テストも書きやすくなりそうだし、フレームワークに依存することもなくてステキ。
ちなみに上記プログラムを実行するとこんな感じ。
f:id:infy2c:20080311131836j:image

2008/02/27

ディープリンク

Adobe Flex3開発ガイド p822
http://livedocs.adobe.com/flex/3_jp/devguide_flex3.pdf
「ディープリンクが動作する仕組み」より
URL を解析するには、通常は URLUtil クラスのメソッドを使用します。このクラスには、URL のサーバー名、ポート番号、およびプロトコルを検出するメソッドが用意されています。さらに、objectToString() メソッドを使用して、ActionScript オブジェクトをストリングに変換して URL の末尾に追加できます。また、URLUtil クラスのstringToObject() メソッドを使用して、クエリ文字列の任意の数の名前と値のペアをオブジェクトに変換できます。これによって、アプリケーションロジックでより簡単にフラグメントを操作できるようになります。
URLUtilクラスのobjectToString()、stringToObjectメソッドがイイ感じ。

2008/01/19

BlazeDS + Seasar2(S2Flex) + Flex(Cairngorm)


AdobeからBlazeDS(現時点ではβだけど)が公開されたので、これを機にSeasar2と連携させてみた。
今まではS2FlexのGatewayを使っていたけど、そこんとこをBlazeDS任せにする。
BlazeDSはFlex Data Servicesとベースは一緒なので、S2Factory for FDS2を試したところ、S2Containerにサービスのインスタンスを登録するのはそのままイケた。

手順としてはこんな感じ。

1. BlazeDS一式をダウンロード、展開。

BlazeDS
http://labs.adobe.com/technologies/blazeds/

2008年1月19日現在はblazeds_b1_121307.zipというアーカイブファイルで提供されている。
この中にはBlazeDSの空コンテキストやサンプルアプリケーションコンテキスト等が含まれている。

2. BlazeDSアプリケーションの設定。

展開後のblazeds_b1_121307\tomcat\webapps\blazeds に空コンテキストがあるので、それをベースにBlazeDSアプリケーションを構築していく。

2.1. web.xmlの設定。
blazeds\WEB-INF\web.xmlにs2filterの設定を追加する。

<filter>
<filter-name>s2filter</filter-name>
<filter-class>org.seasar.framework.container.filter.S2ContainerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>s2filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

2.2. Flexコンパイルオプション -context-root, -services の設定。

FlexBuilderでFlexコンパイラのオプションを設定する。
FDSと違って、このコンパイルオプションを指定しないとRemoteObjectの呼び出しで失敗してしまった。

blazedsというコンテキストであれば下記のように指定する。

-context-root /blazeds -services=C:\blazeds\WEB-INF\flex\services-config.xml

BlazeDSではなく、FDS(LCDS)を使う場合はWeb層コンパイラにコンテキスト名を渡す必要がそもそもないのでこのようなコンパイルオプションは不要っぽい。

BlazeDSではWeb層コンパイラや他いろいろが提供されていないので、上記のオプションが必要。
FlexBuilderコンパイラはflex-config.xmlは使用しないので、コンパイルオプションにload-configオプションの指定をする。

http://livedocs.adobe.com/flex/2_jp/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001490.html

外部ファイル内部でcontext-root, servicesを記述して、コンパイラにその外部ファイルをロードさせる形でもOK。
その場合のコンパイルオプションはこんな感じにした。

-load-config+=C:\blazeds\WEB-INF\flex\flex-config-ext.xml

load-configのところが += ってしてあるのは、FlexBuilderが内包するデフォルト設定(flex-config.xml)に追加する形とするため。

flex-config-ext.xml

<flex-config>
<compiler>
<context-root>/blazeds</context-root>
<services>services-config.xml</services>
</compiler>

<metadata>
<title>blazeds with Seasar2</title>
<description>blazeds with S2 application</description>
<publisher>infy2c</publisher>
<creator>infy2c</creator>
<language>JA</language>
</metadata>
</flex-config>

3. S2Factory for FDS2, S2Flex2, S2Container2 2.4をダウンロード、展開。

S2Factory for FDS2
http://akabana.sandbox.seasar.org/ja/products/fds/

前提条件に
・Flex Data Services2
・S2Flex2
・S2Container2 2.4
が挙げられているけど、今回はBlazeDSを使うので、Flex Data Services2はいらない。

S2Factory for FDS2を通してFlexクライアントのリクエストに応えるインスタンスを生成する。

Flex2開発ガイドのファクトリメカニズムの使用を参照。
ファクトリメカニズムの使用
http://www.adobe.com/livedocs/flex/201_jp/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=ent_services_config_097_26.html

3.1. FlexFactoryの設定。

C:\blazeds\WEB-INF\flex\services-config.xml にFlexFactoryの設定を追加する。

<factories>
<factory id="s2" class="org.seasar.flex2.rpc.remoting.service.fds2.factory.Seasar2Factory" />
</factories>

3.2. RemoteObjectの設定。

C:\blazeds\WEB-INF\flex\remoting-config.xml にRemoteObjectのdestinationを追加する。

下記のような記述をRemoteObjectの数分だけ必要になる。
factoryには3.1. で指定したs2を使う。

<destination id="hogeService">
<properties>
<factory>s2</factory>
</properties>
</destination>

なお、クライアント側はFDSを使っていたときのものでOK。
私はCairngormを使用しているので、下記のような感じになる。

ServiceLocatorとBusinessDelegateを例に挙げておく。
コマンドクラスをresponderに指定して、BusinessDelegateのメソッドを呼んでください。
Services.xml(ServiceLocator)

<?xml version="1.0" encoding="utf-8"?>
<cairngorm:ServiceLocator
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cairngorm="com.adobe.cairngorm.business.*">
<mx:RemoteObject
id="hogeService"
destination="hogeService"
result="event.token.resultHandler(event);"
fault="event.token.faultHandler(event);">
</mx:RemoteObject>
</cairngorm:ServiceLocator>

hogeDelegate.as(BusinessDelegate)

package hoge {
import com.adobe.cairngorm.business.ServiceLocator;

import mx.rpc.AbstractService;
import mx.rpc.AsyncToken;
import mx.rpc.IResponder;

public class hogeDelegate {
private var responder:IResponder;
private var service:AbstractService;

public function hogeDelegate(responder:IResponder) {
this.service = ServiceLocator.getInstance().getService("hogeService");
this.responder = responder;
}

public function hoge():void {
var token:AsyncToken = service.hoge();
token.resultHandler = responder.result;
token.faultHandler = responder.fault;
}
}

かなり手抜きだけど以上。