Google Apps EngineにDWR2を乗せてみた
数回のログで、エンタープライズ・アーキテクチャの主流が旧来のMVC2モデルから、コントローラーがクライアントサイドに近づいた形態に移行している、と繰り返し論じた。
また、コントローラーがクライアントサイドに近づいたアーキテクチャでは、自ずとサーバーサイドのアーキテクチャが簡略化され、簡明なクラス設計とその延長線上としてのコンポーネント化が重要になるだろうと書いた。こういった「認識」でクラス設計(モジュール設計)をすることは、テストの容易性や、インターフェイス指向の設計(開発者同士の契約に基づく設計)とも無関係ではなく、アジャイル開発や頑健(ロバスト)な設計に結びついていく。
こういったアーキテクチャ論は、非常に退屈なものであるが、Google Apps Engine(GAE)といった「隠蔽された」インフラを利用する際の「一つの根拠」と「リスク管理のあり方」を与えると思う。
先のログでは、Eclipse(Ganymede)とGoogleの提供するpluginによって、Eclipse上にあるモジュールが何の設定もなくローカル環境で動作し、一気にGAEのサーバーにデプロイされる様子をみた。
サーバーを構築した経験のあるものには、これは驚異的な出来事であると思う。デプロイという作業には、それ以前に、「アプリケーション・サーバーの導入」という面倒な作業があるのが普通である。設計過程におけるこのフェーズを「方式設計」といったりするが、許容できるコストを条件にして、「サーバーOSに何を選ぶのか?」、「サーバーのサイズとスペックをどの程度に想定するのか?」、「仮想化するのか?」、「仮想化した場合のプロビジョニング管理の方法論はどうするのか?」といった課題のクリアと実作業がある。
また、Tomcatにせよ、WebSphereにせよ、WebLogicにせよ、アプリケーションサーバーにデプロイ作業をする場合には必ず「方言」がついて回る。Servlet API 2.5に則っているからといって、デプロイに失敗することは日常茶飯事である。
こういったプロセスを飛ばしてデプロイができる(しかも、一定のロードまで無料でインフラが提供されている)ということは、驚異以外のなにものでもない。
クラウド・コンピューティングが騒がれる所以である。
さて、前置きが長くなったが、以前に紹介したDWR(Direct Web Remoting)は、ServletでAjaxをハンドリングするツール。クライアントサイド寄りにコントローラを置くアーキテクチャに基づいたフレームワーク。POJOでビジネスロジックを実装できる。
以前に紹介した一番簡単なサンプルを、GAEに乗せてみた。
利用するのは、その際につかったものと全く同じコード。
jarのコピー
まずは、先のログで作成したプロジェクト(GaeDWRTest)に対して
- dwr.jar
- commons-logging.jar
をwar/WEB-INF/lib下にコピーする。プロジェクトを選択し、「Properties」->「Java Buid Path」にdwr.jarを追加する。
demo.htmlの配置
以前のログで作成した、demo.htmlをwar配下に配置する。ただし、画像の扱いを確認するために、war下にimagesディレクトリを作成して、faviconを参照するような設定にしてみた。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>DWRのサンプリング</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="shortcut icon" href="../images/egp-favicon.ico" > <style type="text/css" id="defaultstyle"> body { margin:0; padding:0; } #container { margin: 2px; padding: 3px; line-height:1.5em; width: 500px; height: auto; border:1px dashed #999999; } </style> <!-- Demo.jsはDWRによって自動生成される。 dwr/はドキュメントルートとの相対参照。 --> <script src='dwr/interface/Demo.js'></script> <!-- engine.jsは必須 --> <script src='dwr/engine.js'></script> <!-- util.jsは必須 --> <script src='dwr/util.js'></script> <script type="text/javascript"> function update() { var name = dwr.util.getValue("demoName"); // Demoは、dwr.xmlで定義したPOJO名 Demo.sayHello(name, // Callback関数 function(data) { dwr.util.setValue("demoReply", data); } ); } </script> </head> <body> <div id="container"> <p> 簡単なDWRのデモです。<br> 名前を入力して、「送信」ボタンを押してください。 </p> <p> 名前: <input type="text" id="demoName"> <input value="送信" type="button" onclick="update()"> <br> 返信: <span id="demoReply"></span> </p> </div> </body> </html>
Demo.javaの配置
(これも以前に作成した)Demo.javaをtestパッケージ下に配置する。demo.htmlでの入力値(xxx)に対して、Ajaxで「こんばんわ xxx さん」という文字列を返すだけの簡単なクラスである。
package test; /** * DWRのデモ * * 名前(name)を受け取って、「こんにちは、name」を返す。 * */ public class Demo { public String sayHello(String name) { return "こんばんわ " + name + " さん"; } }
dwr.xmlの配置
(これも以前に作成した)dwr.xmlをwar/WEB-INF化に配置する。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://directwebremoting.org/schema/dwr20.dtd"> <dwr> <allow> <!-- test.Demoというクラスのオブジェクトが「new」によって生成され、 クライアントのJavaScriptプログラムでは「Demo」という名前で 参照できることを意味 --> <create creator="new" javascript="Demo"> <param name="class" value="test.Demo"/> </create> </allow> </dwr>
web.xmlの変更
スタブのweb.xmlは、スタブとしてできたサーブレットへのマッピングと、welcomeページの設定となっている。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"> <servlet> <servlet-name>GeaDWRTest</servlet-name> <servlet-class>test.GeaDWRTestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>GeaDWRTest</servlet-name> <url-pattern>/geadwrtest</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
これを以下のように変更する。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app id="dwr" xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"> <display-name>DWR (Direct Web Remoting)</display-name> <description>Sampling DWR</description> <servlet> <servlet-name>dwr-invoker</servlet-name> <display-name>DWR Servlet</display-name> <description>Direct Web Remoter Servlet</description> <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>activeReverseAjaxEnabled</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>initApplicationScopeCreatorsAtStartup</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>maxWaitAfterWrite</param-name> <param-value>-1</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>demo.html</welcome-file> </welcome-file-list> </web-app>