[GAE/J][Event]FLASHerによる【初めてのGAE(GoogleAppEngine)】

先日、東京てらこ 14に参加してきました。

GoogleAPIということで「はじめてのGAE(GoogleAppEngine)」というテーマで発表しました。

発表のスライドはこちら。
【初めてのGAE/てらこ14発表資料】

///////////////////////////////////////////////////////////////////////////

環境設定のざっくりとした流れ
1.Eclipseのインストール

2.Eclipseの日本語化

3.(Eclipseへ)Goolge Plugin for Eclipseのインストール

4.(Eclipseへ)Slim3 Plugin for Eclipseのインストール

1~3.については以下に詳しく書いてありました。
Google App Engine for Java(GAE/J)プログラミング入門: 「開発環境の準備からデプロイまで」 (1/5)
※一点だけはまったのは日本語化する際に、Eclipseのインストール場所に注意
気持ち的にc:\Program Files\eclipseにインストールしたところだけど、途中のファイルパスにスペースの入ったフォルダがあるとだめみたい。
というわけで、c:\にインストールしました。

4.に関しては以下に詳しく書いてあります。
Slim3 日本語サイト(非公式)
※Eclipse3.4と3.5をサポートと書いてありますが、3.6でも一応できるようです。

///////////////////////////////////////////////////////////////////////////

実際に作ってみたサンプル
393.bz/Invader
GAEと連動してレトロアーケードゲーム的なネームエントリーによるスコア共有の仕組みを仕込んでいます。
(NAMEとSCOREをGAEのDatastore(DB的なもの)に保存し、別ドメインからアクセス)
///////////////////////////////////////////////////////////////////////////

作成したGAE/Jのプロジェクト一式はこちら
Flash2GAE(10MB)

一応invaderゲームプロジェクト一式はこちら
(やっつけ書いたのでソース汚い。。)
InvaderForGAE(1MB)

///////////////////////////////////////////////////////////////////////////

今回のポイントは、別ドメインからGAEのドメインへのアクセス。
何もしないとセキュリティポリシー引っ掛かりますが、crossdomain.xmlをGAE側においてあげれば問題ないみたい。
配置の仕方は、GAEのwarフォルダ内にcrossdomain.xmlを置いた状態でデプロイ処理(アップロード)をするだけ。

不明なところがありましたら、コメントなりどうぞ。
(というかJavaはぜんぜんよくわかってませんが…)

///////////////////////////////////////////////////////////////////////////
PS.
他の方の発表を聞いて、Python+AMFの方が楽そうだなぁと思ったのでそっちも試してみたいところ。
pyAMFというライブラリがあるみたい。
さらにもっとお手軽なのは、PREAIR
これならJavaもPythonも書かなくてもAS3だけでGAEと連動できるサービス作れちゃう!

[GAE/J]Slim3プロジェクトでjava.lang.ExceptionInInitializerError at org.slim3.datastore.DatastoreFilter.doFilter(DatastoreFilter.java:68) が出続けたけどいつのまに直った。

謎謎謎。。。

java.lang.ExceptionInInitializerError at org.slim3.datastore.DatastoreFilter.doFilter(DatastoreFilter.java:68)

Slim3 日本語サイト(非公式)を見ながらSlim3プロジェクトを生成しHelloWorld的なことをやろうと思ったら、上記エラーが発生
コード書いてないんだから当然DatastoreFilterとか使ってるわけがなかろうに。。。

同じような人がいたけど、ごにょごにょしてたら直ったらしく原因わからず。。。

べつのチュートリアルを覗いてみたところ、

Slim3プラグインいれてみた

repackaged-appengine-jakarta-standard-1.1.2.jar
↑をBuildPathに追加とあったので試したら、エラーがでなくなった。
ただし、ビルドパスからはずしてもエラーでないまま。。。
ホントにこれが原因だったのか・・・?

謎謎謎。。。

>2011.03.26追記
なんとなくわかった。
上記作業は必ず必要。
ビルドパスパスからはずしても問題ないというのは、ビルドパスを通すとwar/WEB-INF/libに必要なjarがコピーされるので、コピー後はビルドパスからはずしても問題ないということみたい。

[GAE/J]JSONPなサーブレットにクロスドメインでアクセスできるようにするには

GAEもJavaもまるでわかってないけど、わからないなりに調べたことをメモ。

JASONPを返すようなサーブレットを作ったとして、クロスドメインでアクセス可能にするには、

“Access-Control-Allow-Origin”に”*”を設定する。
具体的には、

resp.setHeader("Access-Control-Allow-Origin", "*");
//※resp:HttpServletResponseインスタンス

あとこんな感じでMethodも設定が必要らしい。

resp.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS");  

ただこれだとIEだとダメらしい。
Ajaxならクロスドメインで値が取れた。

参考記事
Google App Engineでクロスドメイン通信
※GAEソースはPython

ちなみにFlashではセキュリティポリシーひっかかってダメだった(なぜ?)
もちろんGAE元にcrossdomain.xmlを配置すればOK。

※元にしたGAEのDataStoreいじるサーブレットのサンプルはこちら
「Google App Engine for Java(GAE/J)プログラミング入門」

[AS]Embedした複数の画像(クラス)を連番(文字列)で参照したい場合の方法

たとえば、aImage00.png,aImage01.png,aImage02.pngって画像をEmbedで埋め込んだ場合に、クラス名をfor文とかでまわすにはどうすればいいかということ。

二通りのやり方があるみたい。
まずは、ここの記事に教えていただきました。
[Embed]したものを動的に使いたいとき:TWO HEARTS

ポイントはstaticにして、配列アクセス演算子を使うということ。
直感的に納得できる感じ。
↓サンプルソース

package assetImage
{
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.getDefinitionByName;
	
	public class Main2 extends Sprite 
	{
		[Embed(source = 'asset/aImage00.png')] private static var AImage0:Class;
		[Embed(source = 'asset/aImage01.png')] private static var AImage1:Class;
		[Embed(source = 'asset/aImage02.png')] private static var AImage2:Class;
		
		public function Main2():void 
		{
			for (var i:int =  0; i < 3; i++)
			{
				var bm:Bitmap = new Main2["AImage" + i];
				addChild(bm).x = bm.width * i + 20 * i;
			}
		}
	}
}

つづいて、getDefinitionByNameを使う方法
ここで教えていただきました。
■ 埋め込みアセットクラスをgetDefinitionByName()で参照する :棚からパルチャギ

こっちは埋め込むクラス名に対して、埋め込んだ場所のクラスをパッケージから書いたりとと直感的には全くわからない仕様。
(どうもmxmlのお作法もまざってるっぽい)
↓サンプルソース

package assetImage
{
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.getDefinitionByName;
	
	public class Main extends Sprite 
	{
		[Embed(source = 'asset/aImage00.png')] private var AImage0:Class;
		[Embed(source = 'asset/aImage01.png')] private var AImage1:Class;
		[Embed(source = 'asset/aImage02.png')] private var AImage2:Class;
		
		public function Main():void 
		{
			for (var i:int =  0; i < 3; i++)
			{
				var bm:Bitmap = new (getDefinitionByName("assetImage.Main_AImage"+i) as Class);
				addChild(bm).x = bm.width * i + 20 * i;
			}
		}
	}
}

とりあえずどっちでもよさげ。