CodeZine(コードジン)

特集ページ一覧

クラウド時代のRIA構築入門(1)
~Google App Engine for JavaとCurlの連携~

CurlとGAEを使ったRIA構築

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2009/05/12 14:00

 クラウド・コンピューティング開発環境であるGoogle App Engine(GAE) for Javaがリリースされたので早速Curlと連携してみました。今回は、CurlとJavaを簡単に連携し、高速通信実現する、日本発オープンソース・ツールのCurl ORB for javaを用いて検証します。

はじめに

 クラウド・コンピューティング開発環境であるGoogle App Engine(GAE) for Javaがリリースされましたので、早速Curlと連携してみましょう。

 今回は、CurlとJavaを簡単に連携し、高速通信を実現する日本発オープンソース・ツールのCurl ORB for javaを用いて検証したいと思います。

手順

 CurlとGoogle App Engineの連携は、以下の手順で実施していきます。

サーバサイド

  1. Google App Engine SDKインストール
  2. プロジェクトの作成
  3. Curl ORBセットアップ
  4. Spring Frameworkセットアップ
  5. ライブラリ登録
  6. 各種設定ファイル(applicationContext.xml、web.xml、curl-access.txt)の設定
  7. Google App EngineのDataStore機能を利用したサービス作成
  8. Web Application起動

クライアントサイド

  • CurlからGoogle App Engine上のサービスへアクセス

デプロイ

  • Google App Engineへデプロイ

サーバサイドの構築 1

1.Google App Engine SDKインストール

 Google App Engine SDKをインストールするにはEclipseを利用します。EclipseのSoftware Updateから、次のインストール・ロケーションを入力し、インストールします(Eclipse 3.4使用時)。

  • http://dl.google.com/eclipse/plugin/3.4

2.プロジェクトの作成

 Google App Engineのプロジェクトを作成するには、Eclipseのツールバーから以下のアイコンをクリックします。

 次の画面が表示されるので、Project nameとPackageを入力し、Use Google Web Toolkitのチェックをはずして、Finishボタンを押下します。ここでは、Project nameにmemo_server、Packageにmemoを入力しています。

 これでGoogle App Engineプロジェクトが新規に作成されます。ここで自動生成されたサーブレット(memo/memo_serverServlet.java)は、Curl ORBが通信部分の処理を担ってくれるため必要ありません。POJOで作ったサービスクラスを用意するだけで、Curlとのやり取りが可能となります。

3.Curl ORBセットアップ

 次にCurl ORBをSourceForge.NETからダウンロードし、展開します(curl-orb_0.6_stable_bin.zipをダウンロードします)。展開したディレクトリのjava/webをEclipseのwarディレクトリ配下にまるごと上書きコピーします。Curl ORBはXMLやJSONとは違い、バイナリフォーマットを利用しており、高速かつデータ通信量を大幅に縮小できますので、Googleの課金体系にも有利になるかもしれません。

4.Spring Frameworkセットアップ

 Spring Frameworkは必ずしも必要ではありませんが、今回はサービスクラスの管理にSpring Frameworkを使いたいので、バージョン2.5をダウンロードし、以下の4つのjarファイルをwar/WEB-INF/libにコピーします。

  • spring-core.jar
  • spring-beans.jar
  • spring-context.jar
  • spring-web.jar

5.ライブラリの登録

 Curl ORBおよびSpring Frameworkのライブラリを利用するため、User Librariesとして登録します。登録するには、Eclipse上のプロジェクト(ここではmemo-server)を右クリックし、Build Path → Add librariesから以下の2つのUser Librariesを作成してください。

User Libraries
User Libraries 登録するjarファイル
Curl ORB common-annotations.jar、commons-beanutils-1.8.0.jar、commons-codec-1.2.jar、commons-httpclient-3.1.jar、commons-lang-2.4.jar、commons-logging-1.1.jar、curl-orb-server.jar、curl-serializer.jar
Spring Framework spring-beans.jar、spring-context.jar、spring-core.jar、spring-web.jar

 Google App Engine for Javaの利用については、こちらに詳しく説明されていますのでご覧ください。

サーバサイドの構築 2

6.各種設定ファイル(applicationContext.xml、web.xml、curl-access.txt)の設定

 Spring Frameworkの設定ファイル“applicationContext.xml”をWEB-INFディレクトリ配下に追加し、Spring Frameworkを利用するため、web.xmlを修正します。また、Curlのアクセス制御ファイル“curl-access.txt”をwarディレクトリ配下に追加します。

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jee="http://www.springframework.org/schema/jee"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/jee
            http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

  <context:component-scan base-package="memo"/>

</beans>
web.xml
<?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>

  <!-- InvokeApplicationContextServlet -->
  <servlet>
    <servlet-name>InvokeApplicationContextServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.InvokeApplicationContextServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>InvokeApplicationContextServlet</servlet-name>
    <url-pattern>/invoke-application-context</url-pattern>
  </servlet-mapping>
  
  <!-- NewInstanceServlet -->
  <servlet>
    <servlet-name>NewInstanceServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.NewInstanceServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>NewInstanceServlet</servlet-name>
    <url-pattern>/new-instance</url-pattern>
  </servlet-mapping>
  
  <!-- InvokeHttpSessionServlet -->
  <servlet>
    <servlet-name>InvokeHttpSessionServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.InvokeHttpSessionServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>InvokeHttpSessionServlet</servlet-name>
    <url-pattern>/invoke-http-session</url-pattern>
  </servlet-mapping>

  <!-- DestroyInstanceServlet -->
  <servlet>
    <servlet-name>DestroyInstanceServlet</servlet-name>
    <servlet-class>com.curlap.orb.servlet.DestroyInstanceServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DestroyInstanceServlet</servlet-name>
    <url-pattern>/destroy-instance</url-pattern>
  </servlet-mapping>
  
  <!-- DefaultFilter -->
  <filter>
    <filter-name>DefaultFilter</filter-name>
    <filter-class>com.curlap.orb.servlet.DefaultInstanceManagementFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>DefaultFilter</filter-name>
    <!-- <url-pattern>/*</url-pattern> -->
    <url-pattern>/invoke-application-context</url-pattern>
    <url-pattern>/new-instance</url-pattern>
    <url-pattern>/invoke-http-session</url-pattern>
    <url-pattern>/destroy-instance</url-pattern>
  </filter-mapping>
 
  <!--
    Curl ORB - Environment - (since 0.6)
      default: none
        - none (none security)
        - development
        - test
        - production
  -->
  <context-param>
    <param-name>com.curlap.orb.environment</param-name>
    <param-value>development</param-value>
  </context-param>
  
  <!-- 
    Curl ORB - DI container integration - (since 0.6)
      default: com.curlap.orb.context.ServletApplicationContext
        - spring : com.curlap.orb.context.Spring2_5ApplicationContext
        - seasar2: com.curlap.orb.context.Seasar2ApplicationContext 
  -->
  <context-param>
    <param-name>com.curlap.orb.applicationContextClass</param-name>
    <param-value>com.curlap.orb.context.Spring2_5ApplicationContext</param-value>
  </context-param>

  <!-- Listener for Spring framework --> 
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>

  <!-- 
    Curl ORB - filter of generator - (since 0.6)
      NOTE: It is enabled when this environment is development. 
  -->
  <context-param>
    <param-name>com.curlap.orb.generator.filter</param-name>
    <param-value>org.apache.commons.,org.springframework.,org.seasar.,ognl.,org.aopalliance.,junit.,org.datanucleus.</param-value>
  </context-param>
  
</web-app>
curl-access.txt
# curl-access.txt for an Internet Web site
version: 2.0
allow-all:

7.Google App EngineのDataStore機能を利用したサービス作成

 ここでは、DataStoreを操作するため、JDO(Java Data Objects)、JPA(Java Persistence API)を利用して、ストレージに書き込む機能・読み込む機能・削除する機能を作成します。

 まず、データクラスであるMemoクラスとサービスクラスであるMemoServiceインターフェース、MemoServiceImplクラスを作成します。

Memo.java
package memo;

import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Memo {

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;

	@Persistent
	private String name;

	@Persistent
	private String message;

	@Persistent
	private Date date;

	public Long getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}
	
	/* NOTE: ORB needs the constructor of no arguments. */
	public Memo() {
		// do nothing
	}

	public Memo(String name, String message, Date date) {
		this.name = name;
		this.message = message;
		this.date = date;
	}
}
MemoService.java
package memo;

import java.util.List;

public interface MemoService {
	
	public List<Memo> getMemos();

	public void registerMemo(Memo memo);
	
	public void removeMemo(Long id);
	
}
MemoServiceImpl.java
package memo.impl;

import java.util.List;

import javax.jdo.PersistenceManager;

import memo.Memo;
import memo.MemoService;

import org.springframework.stereotype.Service;

import com.curlap.orb.security.RemoteService;
import common.PMF;

@RemoteService
@Service("memoService")
public class MemoServiceImpl implements MemoService {

	@SuppressWarnings("unchecked")
	@Override
	public List<Memo> getMemos() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String query = "select from " + Memo.class.getName();
		List<Memo> memos = (List<Memo>) pm.newQuery(query).execute();
		return memos;
	}

	@Override
	public void registerMemo(Memo memo) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(new Memo(memo.getName(), memo.getMessage(), memo.getDate()));
		} finally {
			if (!pm.isClosed())
				pm.close();
		}
	}

	@Override
	public void removeMemo(Long id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.deletePersistent(pm.getObjectById(Memo.class, id));
		} finally {
			if (!pm.isClosed())
				pm.close();
		}
	}
}

 また、PersistenceManagerFactoryのユーティリティPMFも作成します。

PMF.java
package common;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

/* This code from google. */
public final class PMF {
	private static final PersistenceManagerFactory pmfInstance =
		JDOHelper.getPersistenceManagerFactory("transactions-optional");
	private PMF() {}
	public static PersistenceManagerFactory get() {
		return pmfInstance;
	}
}

8.Web Applicationの起動

 Web Applicationとは、Google App Engine SDKに含まれるWebサーバです。プロジェクト(ここではmemo_server)を選択して右クリックし、Run As → Web Applicationをクリックすることで、Web Applicationを実行できます。Eclipse上では、localhost:8080が稼動するデフォルト設定になっています。

クライアントサイドの実装

CurlからGoogle App Engine上のサービスへアクセス

 CurlからGoogle App Engine上のサービスにアクセスするには、Curl ORBのCurlコード生成ツールを利用して、サービススタブ・クラス(MemoService)とデータクラス(Memo)を生成します。その生成されたCurlのクラスを呼び出すことで、CurlからGoogle App Engine上のサービスクラスへアクセスできます。詳細なCurlコード生成ツールの利用方法はこちらを参照ください。

生成されたサービススタブ・クラス(MemoService.scurl)
|||
||| Curl ORB for java (version 0.6)
|||  This code was generated by the Curl code generator automatically.

|||  package name   : MEMO
|||  generated date : 2009-04-15 16:46:27.126000
|||

{import * from COM.CURLAP.ORB} 

{define-class public MemoService {inherits ApplicationContextClient}
 

  {constructor public {default server-url:#Url = null} 
    {construct-super.ApplicationContextClient "memoService", server-url = server-url} 
  } 

  {method public {async-get-memos ...:EventHandler}:AsyncWorker 
    {return {self.async-invoke "getMemos", {splice ...}} asa AsyncWorker} 
  } 

  {method public {get-memos}:#Array 
    {return {self.invoke "getMemos"} asa #Array} 
  } 

  {method public {async-register-memo v0:Memo, ...:EventHandler}:AsyncWorker 
    {return {self.async-invoke "registerMemo", arguments = {FastArray v0}, {splice ...}} asa AsyncWorker} 
  } 

  {method public {register-memo v0:Memo}:void 
    {self.invoke "registerMemo", arguments = {FastArray v0}} 
  } 

  {method public {async-remove-memo v0:int64, ...:EventHandler}:AsyncWorker 
    {return {self.async-invoke "removeMemo", arguments = {FastArray v0}, {splice ...}} asa AsyncWorker} 
  } 

  {method public {remove-memo v0:int64}:void 
    {self.invoke "removeMemo", arguments = {FastArray v0}} 
  } 
 
}
生成されたデータクラス(Memo.scurl)
|||
||| Curl ORB for java (version 0.6)
|||  This code was generated by the Curl code generator automatically.

|||  package name   : MEMO
|||  generated date : 2009-04-15 16:46:53.742000
|||

||--{import * from JAVAX.JDO} 
{import * from COM.CURLAP.ORB} 
||--{import * from JAVAX.JDO.SPI} 

{define-class public serializable Memo 
 
  field private _id:int64 
  field private _name:#String 
  field private _message:#String 
  field private _date:#Date 
||--  field protected transient _jdo-state-manager:#StateManager 
||--  field protected transient _jdo-flags:int8 

  {getter public {name}:#String 
    {return self._name asa #String} 
  } 

  {getter public {message}:#String 
    {return self._message asa #String} 
  } 

  {getter public {id}:int64 
    {return self._id asa int64} 
  } 

  {getter public {date}:#Date 
    {return self._date asa #Date} 
  } 

  {setter public {message v:String}:void 
    set self._message = v 
  } 

  {setter public {name v:String}:void 
    set self._name = v 
  } 

  {setter public {date v:Date}:void 
    set self._date = v 
  } 
 
}

 次のようにコードを記載することで、このサービススタブ・クラスやデータクラスを使ってGoogle App Engine上のサービスにアクセスできます。

 サンプルコードはこちらからダウンロードできます。memo.zipを展開し、memo-client/memo.dcurlを実行してください。

|| Google App EngineのURLを指定
{set-default-server-url {url http://localhost:8080}}
|| サービスクラスのインスタンス生成
def service = {MemoService}
|| メモの作成(データクラス作成と値セット)
def memo = {Memo}
set memo.name = “おかだ ひとし”
set memo.message = “あいうえお!”
set memo.date = {Date}
|| メモ登録(GAEのストレージに登録)
{service.register-memo memo}

デプロイ

 デプロイをする前に、WEB-INF/appengine-web.xmlにアプリケーションIDを追加します。アプリケーションIDはGoogleのサイトから取得します(「http://<アプリケーションID>.appspot.com」のような形になります)。

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
	<application>ここにアプリケーションIDを入力</application>
	<version>1</version>
	
	<!-- Configure java.util.logging -->
	<system-properties>
		<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
	</system-properties>
	
</appengine-web-app>

 デプロイは、ツールバーにある次のボタンを押下します。

 下記画面にて、対象のプロジェクト(ここではmemo_server)とEmail(Gmailのアカウント)、パスワードを入力して、Deployボタンを押下します。

 成功するとConsoleに次のように表示されます。

Deployment completed successfully

 先ほどのCurlのサンプルでは、ローカルの開発環境(http://localhost:8080)を向いていましたので、今度はデプロイしたGoogle App EngineサーバのURLを指定します。

|| Google App EngineのURLを指定
{set-default-server-url {url http://<アプリケーションID>.appspot.com”}}

 アプリケーションIDは以下のサイトから取得します。

 サンプル(memo.zip)を実行すると次の画面が起動します(memo-client/memo.dcurl)。

  • 画面起動時、MemoService.getMemosメソッドを呼び、DataStoreからデータを取得します。
  • メモ作成ボタン押下時、MemoService.registerMemoメソッドを呼び、DataStoreへデータを登録します。
  • 1行選択し、メモ削除ボタン押下時、MemoService.removeMemoを呼び、DataStoreからデータを削除します。

最後に

 このシリーズでは、今後もクラウド・コンピューティングにおけるRIAの可能性を追求していきたいと考えています。

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 岡田 一志(オカダ ヒトシ)

    大企業向けSI開発、IT基盤設計/構築やiDC設立プロジェクトの企画/開発/運用など幅広く活躍し、2006年にCurlに参画する。米Curl社(マサチューセッツ)にてCurl Core RTEの設計・開発に従事した後、現在は株式会社カールにて、Innovation Centerのオペレーションおよび...

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5