Google Apps EngineにDWR2を乗せてみた

数回のログで、エンタープライズアーキテクチャの主流が旧来のMVC2モデルから、コントローラーがクライアントサイドに近づいた形態に移行している、と繰り返し論じた。

また、コントローラーがクライアントサイドに近づいたアーキテクチャでは、自ずとサーバーサイドのアーキテクチャが簡略化され、簡明なクラス設計とその延長線上としてのコンポーネント化が重要になるだろうと書いた。こういった「認識」でクラス設計(モジュール設計)をすることは、テストの容易性や、インターフェイス指向の設計(開発者同士の契約に基づく設計)とも無関係ではなく、アジャイル開発や頑健(ロバスト)な設計に結びついていく。

こういったアーキテクチャ論は、非常に退屈なものであるが、Google Apps Engine(GAE)といった「隠蔽された」インフラを利用する際の「一つの根拠」と「リスク管理のあり方」を与えると思う。

先のログでは、EclipseGanymede)とGoogleの提供するpluginによって、Eclipse上にあるモジュールが何の設定もなくローカル環境で動作し、一気にGAEのサーバーにデプロイされる様子をみた。
サーバーを構築した経験のあるものには、これは驚異的な出来事であると思う。デプロイという作業には、それ以前に、「アプリケーション・サーバーの導入」という面倒な作業があるのが普通である。設計過程におけるこのフェーズを「方式設計」といったりするが、許容できるコストを条件にして、「サーバーOSに何を選ぶのか?」、「サーバーのサイズとスペックをどの程度に想定するのか?」、「仮想化するのか?」、「仮想化した場合のプロビジョニング管理の方法論はどうするのか?」といった課題のクリアと実作業がある。
また、Tomcatにせよ、WebSphereにせよ、WebLogicにせよ、アプリケーションサーバーにデプロイ作業をする場合には必ず「方言」がついて回る。Servlet API 2.5に則っているからといって、デプロイに失敗することは日常茶飯事である。

こういったプロセスを飛ばしてデプロイができる(しかも、一定のロードまで無料でインフラが提供されている)ということは、驚異以外のなにものでもない。

クラウド・コンピューティングが騒がれる所以である。

さて、前置きが長くなったが、以前に紹介したDWR(Direct Web Remoting)は、ServletAjaxをハンドリングするツール。クライアントサイド寄りにコントローラを置くアーキテクチャに基づいたフレームワーク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>
デプロイ(deploy)

早速デプロイしてみる。今回は、version 2としてデプロイしてみた。URL

http://2.latest.tetsuya-odaka.appspot.com/

にアクセスする(このURLはテスト用なのでアクセスはご勘弁)と、以下の画面が表示される。無事にfaviconも表示されている。

「たろう」と入力した結果が以下。無事にDWRが動いていることが分かる。