2009年9月8日火曜日

Google App EngineでBlazeDSのMessagingを試す

GAE上でBlazeのROは使えることは確認したが、Messagingを使ってチャットのようなNearリアルタイム通信は可能なのか試してみる。Messagingといっても、StreamingAMFChannelを使ったものや、AMFChannelのpollingを使ったものがあるが、とりあえずはStreamingAMFChannelが使えるかチェックしてみる。

[環境]

Remotingを試した時と変わっていません。
  • OS : Windows Vista SP2
  • IDE : Eclipse v3.4.2(Ganymade)
  • SDK : appengine-sdk-1.2.5/JDK1.6.0_07/Flex Builder3.2.0
  • ライブラリ : BlazeDS3.2.0.3978

[サーバーサイド]

1.WEB-INF/flex/messaging-config.xmlにdestinationとしてid=chatを追加

GAEのプロジェクト配下にあるWEB-INF/flex/messaging-config.xmlにdestinationを追加。これがmxml側で指定するdestination先になる。


    
        
        
    

    
        
    
    
    



2.WEB-INF/flex/services-config.xmlのchannelsにStreamingAMFChannelが設定されていることを確認
    

        
            
        

    

[クライアントサイド]

1.mxmlを作成

ローカルとGAEへデプロイした時と接続するチャンネルのパスが変わるので、ラジオボタンで簡単に接続先を設定できるようにしています。BlazeDSのサンプルにあるtestdrive-chatをベースにしています。

  
  
    
  
  
    


 
 

  
    
    
    
  

  
    
    
       
       
    
  
  


2.swfなどのコンテンツをGAEのプロジェクトへ配置

swf、html、AC_OETags.js、playerProductInstall.swfをGAEプロジェクト下のwarに配置。history機能を使う場合はhistoryフォルダもwarに配置する。


[動作確認]

ローカル上で動作確認。Streaming通信に
失敗・・・ノーorz
2009/09/08 4:57:25 com.google.apphosting.utils.jetty.JettyLogger warn
警告: /messagebroker/streamingamf
java.security.AccessControlException: access denied (java.lang.RuntimePermission modifyThread)
 at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
 at java.security.AccessController.checkPermission(AccessController.java:546)
 at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
 at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:139)
 at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkAccess(DevAppServerFactory.java:178)
 at java.lang.Thread.checkAccess(Thread.java:1263)
 at java.lang.Thread.setName(Thread.java:1050)
 at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.handleFlexClientStreamingOpenRequest(BaseStreamingHTTPEndpoint.java:833)
 at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.serviceStreamingRequest(BaseStreamingHTTPEndpoint.java:1022)
 at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.service(BaseStreamingHTTPEndpoint.java:430)
 at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:322)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
 at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
 at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
 at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:121)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
 at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
 at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:313)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
 at org.mortbay.jetty.Server.handle(Server.java:313)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
 at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:844)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:644)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
 at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
GAEのセキュリティサンドボックスにひっかかってしまったようだ。よって、Martinの記事を参考に、StreamingAMFChannelではなく、AMFChannelのpollingを使って動作チェックしてみる。
参考:Martin's Blog: AppEngine & BlazeDS (Messaging)


[エラー解決までの道のり]

1.mxmlでStreamingAMFChannelを使っていた箇所をAMFChannelのpollingを使った記述へ変更。以下、変更部部分。
      private function onClickButton():void{
       
       consumer.unsubscribe();
       
       if(local.selected){
        amfchannel.url="http://127.0.0.1:8080/messagebroker/amfpolling";
       }else{
        amfchannel.url = "http://xxx.appspot.com/messagebroker/amfpolling";
       }
       
       consumer.subscribe();
      }
    ]]>
  
  
  
    
  

2.WEB-INF/flex/services-config.xmlのchannelsにAMFChannelが設定されていることを確認
2秒おきにポーリングするようにしてみました。
    

        
            
            
                true
                2
            
        

    


3.通信テスト
ローカル上で通信が確立することを確認!イェイ。
GAE上にデプロイして動作確認。
通信成功!やたっ!

結局、polling使わないとGAEではダメだった。今度はLong Pollingを試してみよう。