Archive for the ‘ActionScript’ Category
今回は前回のFlashのオブジェクトをJavaのオブジェクトに変換するの逆です。
Javaから、Flashにデータを変換します。
Date date = new Date();
Amf3Output output = new Amf3Output(new SerializationContext());
output.reset();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.setOutputStream(baos);
output.writeObject(date);
output.flush();
byte[] data = baos.toByteArray();
Base64 base64 = new Base64();
String base64str = base64.encodeToString(data);
// ここでBASE64のデータをXMLSocketを通じてFlash側に渡してあげます。
e.getChannel().write(base64str);
// これを忘れてはいけません。これがないと、XMLSocketは終わりを認識できません。
e.getChannel().write("\0");
前回、Base64の処理はBlazeDSについていたjarを利用しましたが、
Jakartaのcommons-codecに変更しました。
こんどはFlash側ですが、こちらは、
var str:String = event.data as String; var bytes:ByteArray; var b64:Base64Decoder = new Base64Decoder(); b64.decode(str); bytes = b64.flush(); var obj:Object = bytes.readObject();
とこんな感じになります。
非常に簡単にできました。
要するにAMFのデータをJava側で処理する方法です。
しかし、httpのプロトコルを使っての話ではないです。
たとえば、AMF3のデータをBase64してそれを、再度Javaで復元するという感じです。
具体的には、XMLSocketを通じてやりとりをしてみます。
XMLSocketのサーバについてはこちらにて多少説明してあります。
httpプロトコルを使わないのは、Flash側に簡単にpush配信ができるからです。
まあ、ずーとコネクションを張っていますから、そりゃできますよね。
でも、http通信を使ってもクライアント側にpush配信できるソリューションがあるので、
どうやっているのかなーと思ったら、keep-aliveでずーとコネクションを張りっぱなしにしてトンネルするのですね。知りませんでした。
(この方法、XMPPを見ていて知りました。)
そんなことをやろうとも思いもしませんでしたが、確かに、httpサーバを作る側になったときに、
keep-aliveでセッションを張られたときにいったいいつコネクションを切ればいいのかというのが悩みの種という思いをいただいた記憶がありました。
idleタイムとかでやるしかないのでしょうが・・・・めんどくさいです。でもサーバですからね。。。。
それと、PHPなんかには、AMF3のデータを処理するライブラリがたくさんあるのに、Javaにはないのかなーと思っていたら、
本家(Adobe)から出しているので、ないのですね。
さて、それではJavaのライブラリの取得方法は
本家から、BlazeDSのBinaryをダウンロードしてきます。
次に、blazeds.warがありますから、これがZIP圧縮されていますので解凍して、
\blazeds\WEB-INF\lib
にある
flex-messaging-common.jar
flex-messaging-core.jar
を取得して、これをJavaのクラスパスに設定できるようにしておいてください。
さて、AS3側の処理です。簡単なのでかなりはしょっていますが、流れを見ていただければ・・・
var sock:XMLSocket = new XMLSocket();
sock.connect(HOST,PORT);
:
public function send(data:*):void{
var bytes:ByteArray = new ByteArray();
bytes.writeObject(data);
var b64:Base64Encoder = new Base64Encoder();
b64.encodeBytes(bytes);
sock.send(b64.toString());
}
のように、どんなオブジェクトでもByteArrayからBase64してXMLSocketへ投げます。これで、as3側はOKです。
次にJava側ですが・・・
再度、XMLSocketのサーバについてはこちらにて多少説明しています、そして、そのソースを再利用しています。
// ここで送られたBase64の文字列をどうにかして取得する。
String request = (String) e.getMessage();
Decoder base64 = new Base64.Decoder();
base64.decode(request);
byte[] data = base64.flush();
ByteArrayInputStream bais = new ByteArrayInputStream(data);
Amf3Input input = new Amf3Input(new SerializationContext());
input.setInputStream(bais);
log.debug("request object:" + input.readObject().getClass());
と、Amf3Inputというオブジェクトを使ってあげればよくて、そこで、readObject()を使えば、オブジェクトが取得できます。
たとえば、AS3のDate型のオブジェクトを渡せば、Javaでは、java.util.Dateの型になるという感じです。
次は、JavaのオブジェクトをAS3側で扱えるようにしてみたいと思います。
昨日の続きであるが、ローカルマシンとの接続はXMLSocketを使うことにしてみた。
とりあえず、これで思うようにできるのか、試してみることにした。
XMLSocketは、AIR以外でも使えるSocket通信だ。
いろいろ、セキュリティ関係はみれていないので、まだまだよくわからないところもあるが・・・
XMLというとなんか、定義されたルールがあるのかと思ったら、
要するに、テキストしか送受信できないSocket通信のようだ。
また、サーバのフレームワークにはnettyを使うことにした。
どうやら、MINAとnettyを作った(ている)人は同じ人らしいが、現在はnettyの方をやっているらしい
ここでは、nettyについて詳しく述べないが、夜にちょっと調べたレベルでも、簡単なサーバが作れる。
実際の受信して、返信するレベルの実装は、こんな感じだ。
(ただ、まだまだ意味がわからず書いているところも多少あるが、どれだけ簡単なイメージかはつかめるかと思う)
package com.coltware.airboost.netty.flash;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
@ChannelPipelineCoverage("all")
public class FlashXMLSocketServerHandler extends SimpleChannelUpstreamHandler {
private static Log log = LogFactory
.getLog(FlashXMLSocketServerHandler.class);
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
log.debug("channelConnected ... " + e.toString());
e.getChannel().write("hello\0");
super.channelConnected(ctx, e);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
log.debug(e.getMessage().getClass());
String request = (String) e.getMessage();
log.debug("request: " + request);
String response = "say what!?\0";
ChannelFuture future = e.getChannel().write(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
log.warn("Unexpected exception from downstream.", e.getCause());
e.getChannel().close();
}
}
これは、Flashの方から、接続すると、「hello」が返され、何かメッセージを送ると、「say what!?」と返すだけのサーバだ。
少なくとも、これで、merapiのサンプルで書かれていたレベルの基盤はほとんどできてしまっている。
通常、サービスを止める場合には、シグナルを送る(Unix/Linux)とか、管理ポートを開いてそこで、管理コマンドを受けるとかあるが、
私は、JMXを利用した。
後は、送る文字列と送信する文字列をAMFベースにしてしまえばいいわけだ。
ただ、バイナリが送れるかわからないので、そのあたりはbase64してしまえばいい。
また、nettyのいいところは、httpの通信を標準でサポートしているので、httpベースのサーバも簡単に作れるので、
もし、XMLSocketがだめなら、別の通信と、通信プロトコルは好きに定義すればいい。
AIRでアプリを作っていて、いくつか悩みが出てきた。
バックグラウンドとして、安定して処理をするにはActionScriptで大丈夫なのだろうか?
ということだ。
これは、速度についてもあるし、たとえば、自分が端末の前に座っていない、深夜に処理をやってほしい。
などなど・・・・
具体的には、処理があいているときに全文検索の為のインデックスをつくれないかなーとか・・・・
でも、ActionScriptで、そもそも全文検索DBの構築をするための処理を書くのは、Javaなんかでさんざんいろいろなものがあるのに、
することじゃないだろうなー。と。
んー、やっぱり、100% AIRでクライアントツールを作るのにも、どこかで無理があるのかな。
でも、そのためにインターネット上にサーバを用意するのは、ちょっと考え物だし・・・・
つまり、ローカルでサーバが動いている必要がでてきてしまう。
まあ、Tomcatとかを動かしてしまえばいいのかもしれませんが、やっぱり、
ちょっと気分的にそれは重いかな・・・・
と、まずは探そうとおもったら、
Merapi
というものがありました。
AIRとJavaのブリッジだとあります。
ちょっと、ソースを見てみると、127.0.0.1のポート12345を使って、Socket通信している感じ。
(よくは調べていないので、そうでないかもしれませんが・・・)
んー、これだと、自分で作り込んじゃっても、それほどかわらないかなという感じです。
それに、これをソケット通信にしないで、127.0.0.1のサーバとHTTP通信すると、
AIRだけでなく、ブラウザ上のFlashからもアクセスできるのかな?
まあ、セキュリティも問題もあるが・・・・
でも、技術的なセキュリティ問題の回避の為に、根本的なセキュリティを許容するのも本末転倒だし。
(つまり、ネットワーク上に上げる必要も無いデータを、加工するためだけにネットワークに上げるという意味。)
ローカルホスト上に、基本的な機能(DB、File、ネットワーク)なんかの操作APIを提供するサーバがあれば、
配布はWEB(ブラウザ上のFlashという意味)で行って、ローカルアプリのような事ができる。
どうも、最初のAIRの配布方法と実行条件に難があるのですよね。
あと、あのアプリへの署名。
お手軽アプリを作りたいだけなのに、「危険です」みたいなものを表示し続けなければならないのは、ちょっと・・・・
特に最近のWindowsなどは、管理権限などもうるさく(?)なり、簡単にローカルアプリはインストール・アップデートできなくなったことを考えると、
AIRの位置づけが微妙だなという認識が消えないのです。
でも、やっぱり、ローカルで何でもできるようなサーバがたっていて、それにアクセスできるのは明らかにセキュリティ上の穴だし・・・・
まあ、とりあえずは、その何でもサーバを作ることを考えてみると、いいアイデアや、情報が見えるかもしれません。
そもそも、AIRでないFlashアプリが127.0.0.1にアクセスできるのかも今は知らないのですが・・・・
と、Javaでお手軽サーバを作ろう、せっかく作るのであれば、HTTP以外のプロトコルも簡単にあつかいたいなーという欲も出てくる。
ならばと、調べると、
Apache MINAとか、nettyのようなものをベースに作るのがらくかなーと。
と、Flex4もまだ浸透していないし、AIR2もまだリリースされていないし、
当分、Javaのほうに足をつっこもうかなと思う今日この頃です。
今まで、リビジョンで管理していましたが、ある程度こなれてきたとも思うので、バージョン 0.5としました。
どうしてVersion 1 ではないかといえば、せっかくなので、Flex4 & AIR2.0 でVersion 1.0 にしようと思っています。
ちなみに、前回のRevision44からの主な変更点(バグ修正)では、
1)長いサブジェクトの場合におかしなサブジェクトになっていた。
2)本文の最後に.(ドット)がついてしまっていた。
を修正しました。
ダウンロードは

