IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Web development | XML | Information Management  >

Project Zero のデータ・アクセス API 使って作成する単純なウィキ

お馴染みのモデル・ビュー・コントローラー・パターンを使って単純なウィキ・アプリケーションを作成する

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

サンプルコード

原文はこちら

原文はこちら


レベル: 中級

Brandon J.W. Smith (brandon+dW@16cards.com), Software Engineer, IBM
Hanumanth R. Kanthi (kanthi@us.ibm.com), IT Architect, IBM

2008年 1月 08日

Project Zero は、サービス指向アーキテクチャー (SOA) に準拠した Web 2.0 アプリケーションのアジャイル開発を焦点として単純化された開発プラットフォームです。そんな Project Zero が武器とするライブラリーのなかに、SQL クエリーを実行するための簡易 API があります。この記事では、これらの API を利用して単純なウィキを作成する方法を説明します。

始める前に

この記事は、読者に Project Zero についての基本的な知識があることを前提とします。まだこの前提を満たしていない方は、2 つの初心者向け記事、「Web アプリケーションのための RESTful なサービスを作成する」と「Get started with Project Zero and PHP」を読むことから始めてください。Project Zero を使い慣れている方は、このプロジェクトをダウンロードして (「参考文献」を参照)、単純なアプリケーションを自力で作成できるはずです。

はじめに

Larry Wall 曰く、最善なのは、「簡単なことは簡単に、難しいことは可能にする」ことです。

データ・アクセスには、簡単なものから極めて複雑なものまで、さまざまなケースがあります。それ故に多くの開発者たちは、複雑なケースに対応できると同時に単純なケースを扱いにくくすることもない柔軟性の高いデータ・アクセス API を願ってやみません。まさにそんな願いを叶えるのが、Project Zero のデータ・アクセス API (zero.data) です。zero.data は Hibernate や Java™ Persistence Architecture のような抽象化レイヤーとして意図された API ではありません。この記事でこれから説明するように、zero.data は SQL をシン・ラッパーで囲むことによって、簡単なことを簡単に、難しいことを可能にすることを目的としたライブラリーです。一例として、単純なクエリーを実行し、その結果を Bean インスタンスのリストとして取得する方法をリスト 1 に示します。


リスト 1. zero.data を使用して Bean およびマップ・インスタンスのリストを返す場合
                
Manager data = Manager.create("myDb");
List<Person> results = data.queryList("SELECT * FROM person", Person.class);
List<Map<String,Object>> resultsMap = data.queryList("SELECT * FROM person");

去年 1 年間、Project Zero チームは IBM® の Information Management 開発者たちと緊密に連携して pureQuery に取り組みました。このハイパフォーマンス・データ・アクセス・プラットフォームには、Java アプリケーション用の開発ツール、API、そして高度なランタイムが組み込まれています。zero.data が利用しているのは、この pureQuery の API とランタイムです。pureQuery ツールは Java 成果物を生成するので、zero.data では pureQuery のツールセットの使用を除外していませんが、この記事を書いている時点では、この堅牢なツールセットとの Project Zero 固有の統合はまだありません (pureQuery についての詳細は、「参考文献」を参照してください)。図 1 に、Project Zero の API と pureQuery との関係を示します。


図 1. Project Zero の zero.data リレーショナル・データ・アクセス API 間の関係

Project Zero コミュニティー
Project Zero の Web サイトをざっと見て、Project Zero が最近の Web アプリケーションに強力な (しかも極めて単純な) 開発および実行プラットフォームをどのように提供するかを確かめてください。コミュニティーではプロジェクト開発についての議論、開発者の支援を活発に行っています。あなたの意見もぜひお聞かせください。

zero.data は、pureQuery の API とランタイムが提供する機能をラップするシン・ラッピング API を提供しています。pureQuery の API を使用せずにこのような方法が取られている理由は、Project Zero アプリケーションでの前提を単純化できるようにするため (構成、コネクション・プーリングなど)、さらに共通 API を提供して Groovy スクリプトと PHP スクリプトの両方がそれぞれの言語の理にかなった方法で堅牢な API を使用できるようにするためです。例えば、Groovy インターフェースに公開されるいくつかのメソッドはクロージャーを使用する一方、PHP でそれに対応するものは PHP リソース識別子を使用します。

この記事では、Groovy の API に焦点を当てます。Java および PHP の API について詳しく学ぶには、Project Zero の資料を参照してください。ここから先は、Zero アプリケーションでの基本的な zero.data の使い方について説明します。まず始めに、zero.data.groovy.Manager インターフェースを使用してデータを管理する方法、そしてその設計の背後にある動機を、Java と Groovy 両方の観点から API を検討しながら解説します。続いて簡単な実践例として zero.data API を使用するためのアプリケーションを作成します。このアプリケーションを作成した後、単純なウィキの作成、テーブルの初期化、そして最後にアプリケーションのコーディングを行います。以下に、この記事の概要を示します。

データの管理

zero.data.groovy.Manager (以降、Manager と略します) は、ユーザーがリレーショナル・データベースに対し、クエリーを実行したり、操作を行ったりするのに便利な API を定義しています。この API の最も基本的な使用方法は、SQL ストリングを渡すことです。Groovy では例えば data.queryFirst("SELECT * FROM t WHERE id=$id") といったように、パラメーターをストリングに組み込んで渡します。すると ManagerPreparedStatement を使って SQL のストリングを準備し、その SQL を実行して結果を返します。さらに、作成された最終的なリソース (結果セット、ステートメント、そして接続など) をインテリジェントに管理します。

Manager には、以下の操作を実行する一連のメソッドがあります。

  • クエリーを実行し、各行を繰り返し処理してクロージャーを実行する。
  • クエリーを実行し、以下のいずれかに変換された ResultSet の先頭行だけを返す。
    • Java Bean クラスのインスタンス
    • java.util.Map
  • クエリーを実行し、以下のいずれかに含まれ、上記のいずれかに変換された ResultSet のすべての行を返す。
    • java.util.Iterator
    • java.util.List
    • Java 配列
  • クエリーを実行し、ResultSet を返す。
  • 生成されたキー専用のメソッドが組み込まれたデータ操作言語のステートメント (INSERT、UPDATE、DELETE など) を実行する。

単純な API

データの観点からすると、Manager がボイラープレート・コードを減らし、バグが出る可能性のある「サポート」コードではなく機能そのものに専念できるようにする仕組みを比較する価値はあります。リスト 2 では、リスト 1 に記載したコードを JDBC のみで実装しています。これを見ると、Manager がどのようにして単純なことを劇的に簡単にするかがわかります。


リスト 2. JDBC を使用して Map のインスタンスを返す場合の冗長なコード
                
// assumes Connection has already been initialized
// see JDBC documentation for more details

List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
try {
  PreparedStatement stmt =
    connection.prepareStatement("SELECT * FROM person");
  ResultSet rs = stmt.executeQuery();
  try {
    while(rs.next()) {
      ResultSetMetaData meta = rs.getMetaData();
      int numColumns = meta.getColumnCount();
      Map<String,Object> row = new HashMap<String,Object>(numColumns);
      for (int i = 1; i <= numColumns; i++) {
        row.put(meta.getColumnName(i).toLowerCase(), rs.getObject(i));
      }
      results.add(row);
    }
  } finally {
    rs.close();
  }
} finally {
  stmt.close();
}

リスト 2 のように JDBC を直接使用するアプリケーション・コードはめったにありません。大抵のフレームワークではある程度の間接化および簡易化が行われていますが、Manager では単純なことを簡単にして難しいことを可能にするためにかなりの取り組みが行われているように思われます。例えばリスト 1 に示されているように、zero.data は Java Bean クラス (Map) の単一のインスタンス (List、Iterator、または Array) を返すだけでなく、開発者、あるいは第三者が複雑な ResultSet の処理を実装することを可能にするテンプレート・メソッドの手法も提供します。

このような一層高度なテンプレート・メソッドの手法を使用する方法については、今後の developerWorks の記事で取り上げることにします。前述したように、zero.data は pureQuery のランタイム・エンジンをベースに作成されています。pureQuery ランタイムはオープン API を使用してデータベース・アクセスを予測可能ながらも柔軟な方法で制約するためのフレームワークになるだけでなく、コードの再利用を大幅に促進します。例えば、pureQuery ランタイム自体のほとんどを構成するインターフェースの実装は、開発者がエンジンを拡張するために実装できるインターフェースそのもののです。このように、pureQuery ランタイムは、特定のアプリケーション用に pureQuery のランタイム・エンジンに「一度限り」の拡張を施したものから、再利用可能な ResultSet 処理コンポーネントのライブラリーを支持する組織に至るまで、あらゆるケースに対応するだけの柔軟性を持ち合わせています。

図 1 に示されているように、Manager は実際に zero.data.Manager をラップして、Groovy から操作しやすいショートカットを提供します。Managerzero.data.Manager のデータ・アクセス API を比較した以下の表を見てください。この表から、どちらも共通したテーマを持っていることがわかるはずです。つまり、実現する内容はほとんど同じながらも、特殊な使用ケースを目的としたさまざまなメソッド・タイプがあるということです。例えば queryListjava.util.List を返す一方、queryIteratorjava.util.Iterator を返します。ほとんど説明するまでもありません。メソッド・タイプのそれぞれにはオーバーロードされたメソッドが 3 つあり、メソッド・タイプのすべてでシグニチャーと関数は対となっています。これらのメソッド・タイプとオーバーロードされたメソッドすべてを、それぞれの説明と併せて表 1 に記載します。詳細は、Project Zero の Javadoc API マニュアルを参照してください。


表 1. Manager メソッドの概要
メソッド説明使用例Groovy での使用例
queryFirst ResultSet の最初の行を返す。Map<String,Object> queryFirst(String, Object...)Map<String,Object> queryFirst(GString)
T queryFirst(String, Class<T>, Object...)T queryFirst(GString, Class<T>)
T queryFirst(String, RowHandler<T>, Object...)T queryFirst(GString, RowHandler<T>)
queryList ResultSetjava.util.List として返す。List<Map<String,Object>> queryList(String, Object...)List<Map<String,Object>> queryList(GString)
List<T> queryList(String, Class<T>, Object...)List<T> queryList(GString, Class<T>)
List<T> queryList(String, RowHandler<T>, Object...)List<T> queryList(GString, RowHandler<T>)
queryIterator ResultSetjava.util.Iterator として返す。Iterator<Map<String,Object>> queryIterator(String, Object...)Iterator<Map<String,Object>> queryIterator(GString)
Iterator<T> queryIterator(String, Class<T>, Object...)Iterator<T> queryIterator(GString, Class<T>)
Iterator<T> queryIterator(String, RowHandler<T>, Object...)Iterator<T> queryIterator(GString, RowHandler<T>)
queryArray ResultSetJava 配列として返す。Map<String,Object>[] queryArray(String, Object...)Map<String,Object>[] queryArray(GString)
T[] queryArray(String, Class<T>, Object...)T[] queryArray(GString, Class<T>)
T[] queryArray(String, RowHandler<T>, Object...)T[] queryArray(GString, RowHandler<T>)
update 更新を実行し、更新によって影響を受けた行の数を返す。 int update(String, Object...)int update(GString)
insert生成したキーの値を 2 番目のパラメーターに指定されたクラスにキャストして返す。Groovy バージョンでは常に int にキャストする。T insert(String, Class<T>, String[], Object...)int insert(GString, List<String>)

Java プログラミングと Groovy

表 1 から推測できるように、zero.data にはさまざまな場合に対応する包括的なデータ・アクセス・メソッドのセットがあります。しかしこの記事で使うのは、zero.data.groovy.Manager バージョンの queryFirst(GString)queryList(GString)update(GString)insert(Gstring, List) のみです。

Groovy は Java プラットフォームで実行する動的なオブジェクト指向のプログラミング言語です。Groovy に関してよくある誤解は、Groovy が Java プログラミング言語になり代わろうとしているというものです。Groovy は Java バイト・コードにコンパイルするため、標準 Java API、そして同じく Java 言語で作成された多数のライブラリーを利用することができます。したがって、Groovy は Java 構文の代替手段となることを目的としているのではなく、よりわかりやすい簡潔なコードを可能にする多くの言語要素が含まれる代替構文を提供することによって Java 構文を補うことを目指しています。

例えば Java バージョンの Project Zero の zero.data API を使うだけで、前に記載した標準 JDBC メソッド呼び出しのコードの行数を減らすことができます。ただしリスト 3 を見比べてみると、Java と Groovy のコードは機能的には等価です。


リスト 3. 機能的に等価な Java および Groovy コードの比較
                
// Java
Manager data = zero.data.Manager.create("wiki");
data.inTransaction(new LocalTransaction() {
  public void execute() {
    data.update("UPDATE mytable SET name=? WHERE id=?", 1, "new name");
    data.insert("INSERT INTO anothertable (name) VALUES (?)", "another name");
    List<Map<String,Object>> results = data.queryList("SELECT * FROM sometable");
    for (Map<String,Object> row : results) {
      for (String key : row.keySet()) {
        System.out.println("key: " + key + ", value: " + row.get(key));
      }
    }
  }
});

// Groovy
def data = zero.data.groovy.Manager.create("wiki")
data.inTransaction {
  data.update("UPDATE mytable SET name=$name WHERE id=$id")
  data.insert("INSERT INTO anothertable (name) VALUES ($name)")
  data.eachRow("SELECT * FROM sometable") { row ->
    row.each { key, value -> 
      println("key: $key, value: $value")
    }
  }
}

リスト 3 からわかるように、コードの行数が減るだけでなく、Groovy 言語は余計なことを行わない傾向にあります。この inTransaction メソッドを例に取ると、Java バージョンでは LocalTransaction の匿名インスタンスを明示的に作成しなければなりませんが、Groovy ではクロージャーに隠すことができます。Groovy では、見方によればクロージャーが「移植可能な」コードを作成する手段となります。Java 言語では抽象 LocalTransaction クラスの匿名の実装を作成してメソッド inTransaction に渡すことができるのと同じように、Groovy ではクロージャーの括弧 (「{」と「}」) で囲まれたコードを圧縮して inTransaction メソッドに渡すという遥かに簡潔な方法を取ることができます。Groovy の資料 (「参考文献」を参照) には、クロージャーの例やクロージャーを引数として取る API を作成する方法を含め、Groovy 言語でのクロージャーについて包括的に説明しています。

リスト 3 に記載した Groovy バージョンのコードで使用されている 2 つ目、3 つ目のクロージャーを見てください。eachRow メソッドはクロージャーを取ることが可能で、その場合、結果に含まれる各行に対して括弧内のコードを実行することになります。リストを見るとわかるように、これに該当するコードは別のクロージャーを呼び出し、そのクロージャーが単純に Map 行のエントリーをループしてキーと値を出力します。




上に戻る


アプリケーションの作成

この記事で使用している zero.data API
コンパイル時に行う静的な型チェックを実行可能であるが要求はしない動的言語として、Project Zero では Groovy を利用するため、この記事では Map バージョンの API を使用しています。この API では ResultSet の行を java.util.Map にマッピングします。この場合、列名が Map 内のキーとなり、キーの値は ResultSet の行の値となります。

この記事の残りの部分では、お馴染みのモデル・ビュー・コントローラー・パターンを使用して単純なウィキ・アプリケーションを作成する手順を通して、zero.data の威力を調べていきたいと思います。図 2 に、このパターンが Zero アプリケーションではどのように機能するか大まかなアーキテクチャーを示します。Zero の規約をサポートするコード成果物の配置場所については、記事の最後のほうで説明します。

モデル・ビュー・コントローラー・パターン

図 2 を見てください。この図は、Project Zero アプリケーションでのモデル・ビュー・コントローラーの実装を図解したものです。


図 2. Project Zero アプリケーションでのモデル・ビュー・コントローラー実装

アプリケーションを起動させるには、まず Project Zero アプリケーションを作成する必要があります。以降に記載する図は、Eclipse で Project Zero プラグインを使用した場合の画面です。これらの画面には、アプリケーションを開発するためのユーザー・インターフェースのショートカットが用意されています (ただし、代わりにコマンドライン・ユーティリティーの相当する機能を使ってすべての手順を実行することも可能です)。

最初に作成しなければならないのは Zero アプリケーションです。Project Zero の Eclipse ユーザー・インターフェースを使ってアプリケーションを作成する方法については、「Project Zero の紹介、第 1 回」で詳しく説明しています。さらに、Project Zero アプリケーションを構成するさまざまなフォルダーと成果物についての詳細も記載されているので、ここでは基本的な手順を説明するだけにとどめます。

まず、File > Project.. の順にメニュー項目をクリックしてアプリケーションを作成してください。ダイアログ・ボックスにプロジェクト・ウィザードの選択オプションが表示されるので、Project Zero > Project Zero Application を選択してウィザードを起動します (図 3 を参照)。


図 3. Project Zero Application ウィザードの選択

ウィザードの最初の画面には、アプリケーションの名前 (Project name) を入力するよう求めるプロンプトが表示されます。アプリケーションは任意の名前にできますが、ここではわかりやすいように mywiki という名前を付けることにします (図 4 を参照)。


図 4. 新規 Project Zero アプリケーション名の入力

これで、Eclipse ワークスペース内のプロジェクトとともに、いくつかのデフォルト・アプリケーション成果物が Project Zero アプリケーションのフォルダー構造の中に作成されます。作成された mywiki プロジェクトは図 5 のようになっているはずです。


図 5. Project Zero アプリケーションのフォルダー構造

Project Zero では Ivy フレームワークを使って依存関係を管理するおかげで、とても簡単に zero.data を取得することができます。アプリケーション内で依存関係を宣言する場所は ${app_home}/config/ivy.xml ファイルです。便宜上の理由と単純にすることを目的に、この依存関係の宣言例は組み込みモードの Apache Derby を使って説明します。前述のファイルを編集して、リスト 4 に示す 2 行の XML を組み込んでください。


リスト 4. アプリケーションの ivy.xml への追加内容
                
<dependency org="zero" name="zero.data" rev="1.0+"/>
<dependency org="org.apache.derby" name="derby" rev="10.3.1.4"/>

パスワードの難読化
アプリケーションのプロセスを不足させるデータベースには大抵、接続プロパティーが必須となります。けれども、組み込み Derby をデータベースとして使用している場合には接続プロパティーは不要です。例えば、password プロパティーがないこともあります。Project Zero には、パスワードをわかりにくくして平文で表示されないようにする仕組みがあります。このような構成を実現する方法についての詳細は、Project Zero の資料を参照してください。

Project Zero の紹介、第 1 回」の説明に従って新しい依存関係を解決してから、作業を続けてください。

zero.data を構成する

zero.data は javax.sql.DataSource を使ってデータベースに接続します。1 つ、または複数のデータベースを構成して接続するには、Project Zero アプリケーションの zero.config ファイルで接続プロパティーを構成します。リスト 5 では、キー「wiki」を持つデータベースを指定して構成しています。


リスト 5. zero.config での zero.data の構成
                
/config/db/wiki = {
  "class" : "org.apache.derby.jdbc.EmbeddedDataSource",
  "databaseName" : "db/wiki",
  "connectionAttributes" : "create=true"
}

Manager インスタンスを取得する

データベース接続プロパティーを正しく構成したら、今度は Manager インスタンスを取得します。このインスタンスがあれば、前述した便利なメソッドを使ってデータに対するクエリー、操作を実行することができます。構成された Manager を取得するには、zero.config ファイルで選択したキーを使用します。この例では「wiki」を選択したので、これを引数として create メソッドに渡します (リスト 6 を参照)。


リスト 6. 構成済み Manager の取得
                
def data = zero.data.groovy.Manager.create('wiki')

リスト 4リスト 5リスト 6 を見るとわかるように、Zero アプリケーションを稼動させるために必要な作業はほんの少ししかありません。次は単純なウィキの作成に取り掛かります。その手順として、基本的な要件を定義してから、それをコードに変換します。

単純なウィキの作成

zero.data の使用例を紹介するため、ここでは単純なウィキ・アプリケーションを作成します。最も単純な形のウィキは、ウィキ・ページの作成、編集、リンク、そしてレンダリングを行います。したがって、この例では標準的な CRUD 操作のうち、作成、取得、更新の操作を取り上げて説明します (削除操作については説明しません)。(訳注: CRUD は、ほとんどの場合、Create、Read、Update、Delete ですが、この記事では Read の代わりに Retrieve が使われています)

なぜウィキなのか

zero.data API を説明するために、なぜウィキを実装するのかというと、第一の理由は単純なウィキはその言葉通り、単純だからです。単純なウィキを実装するのであれば、より複雑なウィキの実装で持ち上がってくるような他の実装詳細を深く掘り下げることなく、zero.data API を中心に説明することができます。第二の理由は、追加機能を後から作成し、さらに高度な zero.data の使い方や Project Zero の他の機能を説明するベースとしてはウィキがあつらえ向きだからです。

ウィキとは何か
ウィキとは、ユーザーが素早く簡単に Web ページを作成、編集、リンクできるようにするソフトウェアのことです。この用語は、速い、あるいは形式張らないことを意味するハワイ語に由来しています。

ウィキの要件

前にも説明したように、基本的なウィキの実装に必要なのは、ウィキ・ページの作成、取得、更新です。ほとんどのウィキの実装に共通している点は、ページの作成は、まず他のページからそのページにリンクしてから行うということです。ウィキのユーザーがリンクをクリックすると、ユーザーにページの作成を促すフォームが表示されます。該当するページがすでに存在する場合には、リンクによってそのページがレンダリングされ、ユーザーはフォームを作成する場合と同じような形でページを編集することができます。

この例では、Project Zero のスクリプト機能とテンプレート作成機能を組み合せ、お馴染みの MVC パターン関連のノウハウを利用して実装をプロトタイプ化します。つまり、アプリケーションの公開フォルダーにコントローラー・スクリプトを配置し、これらのスクリプトには URI によってアクセスできるようにします (PHP アプリケーションの場合とほとんど同様です)。フォルダーの階層とファイル・システム上のファイルは、URI の構造に対応します。一方、ビューはアプリケーションの /app/views フォルダーに保存されます。この実装は Groovy で行うため、コントローラーには接尾部 .groovy、views には接尾部 .gt が付けられます。

どのような結果を目的としているかがよくわかるように、図 6 にアプリケーション成果物を作成した後のアプリケーション・ディレクトリーを示します。


図 6. 手順完了後の Project Zero アプリケーションのフォルダー構造

背景となる情報はこれで十分として、今度はコードの詳細を検討します。

テーブルの初期化

コントローラーとビューの実装に気を取られる前に、データの取得、表示、操作に使用できるモデルを用意しなければなりません。ウィキ・ページはデータベース・テーブルに保管します。単純化を図り、モデルはデータベース・テーブルの行にマッピングされた Map のみとします (このようにしないと、zero.data が主題の記事にならないからです)。ストレージの要件は非常に控えめで、ページの名前と実際のページ・コンテンツ以外に必要なものは何もありません。これを表しているのが、setup.sql ファイルに配置されたリスト 7 の SQL コード・スニペットです。


リスト 7. setup.sql のコンテンツ
                
CREATE TABLE pages (
  id int NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
  name varchar(20) NOT NULL,
  content varchar(3000),
  updated timestamp,
  PRIMARY KEY  (id)
);

起動!

今まで説明した他のアプリケーション成果物とは異なり、setup.sql に関する規約はありません。このファイルに含まれるデータ定義は、起動ハンドラーを使用して実行されます。起動ハンドラーとは、Project Zero アプリケーションに対して提供されるコードで、このコードは (ご想像通り) アプリケーションが起動されるある特定の段階で実行されます。

そこでまず作成するのは、Project Zero アプリケーションの起動時に実行させる Groovy スクリプトです。 データベースがまだ用意されていない場合には、このスクリプトに setup.sql 内のステートメントを実行させます。ここで行おうとしているのは開発時にのみ使える手法です。この手法を実動で繰り返することはできません。現時点では既存のデータベース・スキーマを自動的に変更するためのサポートは存在しないため、アプリケーションのスキーマが変更された場合には起動ハンドラーを使ってデータベースをファイル・システムから削除する必要があります。説明のために、ひとまずベスト・プラクティスから離れますが、この (素朴とまではいかないにせよ) 単純な実装から zero.data API の使用方法を十分理解できるはずです (リスト 8 を参照)。


リスト 8. app/scripts/startup.groovy の内容
                
import zero.data.groovy.Manager

//if derby database already exists, don't run the script
def db_dir = new File('db/wiki')
if (!db_dir.isAbsolute())
  db_dir = new File(config.root[], 'db/wiki')

if (!db_dir.exists()) {
  def buffer = new StringBuffer()
  new File('setup.sql').text.split('\n').each() { line ->
    line = line.trim()
    if (line && !line.startsWith("--") && !line.toLowerCase().startsWith("connect"))
      buffer << line << '\n'
  }
  def statements = buffer.toString().split(';')
  def data = Manager.create('wiki')
  try {
    data.inTransaction() {
      statements.each() { statement ->
        statement = statement.trim()
        if (statement)
        data.update(statement)
      }
    }
  } catch (Throwable error) {
    throw new RuntimeException("Setup database error: ${error.message}", error);
  }
}

このスクリプトを起動時に実行できるようにするには、スクリプトをそのように構成する必要があります。したがって、config/zero.config ファイルに、このスクリプトを起動ハンドラーとして登録してください (リスト 9 を参照)。


リスト 9. config/zero.config に追加するスタンザ
                
/config/handlers += {
  "events" : "start",
  "handler" : "startup.groovy"
}

上記の登録では、「start」イベントの起動時にはいかなる場合でも Project Zero ランタイムが startup.groovy スクリプトを実行するように指定しています。これで、Project Zero アプリケーションを起動すると CREATE TABLE 文が実行されるようになります。データベースはまだ存在しないため、組み込み Derby がディスク上にデータベースを作成します (データベースが存在しない場合にはデータベースを作成するように接続プロパティーを構成したからです)。

アプリケーションのコーディング

アプリケーションは実行中のままにしてください。Project Zero は動的なため、ほとんどの変更を反映することができます。テーブルの作成が済んだところで、いよいよコントローラーとビューのコーディングに取り掛かる段階に来ました。まずはページのレンダリングから始めましょう。

動的 HTML のレンダリング

ページをレンダリングするには、Project Zero ランタイムがウィキ・アプリケーションに制御を渡せるようにするためのフックが必要です。そこで、このフックをコントローラーという形で app/public ディレクトリーに実装することにします。このレンダリング機能に付ける名前は「view.groovy」です。まず、レンダリングの際には、Manager にページのクエリーを実行させます。次にクエリーを実行してデータベース内の行を取得し、行が存在する場合はその行をレンダリングし、存在しない場合には作成ページを表示します。この実装は、リスト 10 のとおりです。


リスト 10. view.groovy の実装
                
def name = request.params.name[]
def data = new zero.data.Manager('wiki')
def page = data.queryFirst("SELECT * FROM pages WHERE name=$name")
if (page) {
  request.page.name = page.name
  request.page.content = page.content
  request.view = 'view.gt'
} else {
  request.page.name = name
  request.view = 'create.gt'
}
render()

次に作成する必要があるのは、view.groovy コントローラーをサポートする「view.gt」および「create.gt」ビューです。この 2 つのビューは、Groovy テンプレートを使って単純に要求スコープ内のデータをレンダリングします (リスト 11 とリスト 12 を参照)。


リスト 11. view.gt の実装
                
<html>
 <head>
  <title><%= request.page.name[] %></title>
 </head>
 <body>
  <h1><%= request.page.name[] %></h1>
  <%= request.page.content[] %>
  <hr/>
  <a href="<%= "${getRelativeUri('/edit.groovy')}?page=${request.page.name[]}" %>">
    Edit this page?
  </a>
 </body>
</html>


リスト 12. create.gt の実装
                
<html>
 <head>
  <title><%= request.page.name[] %> - Create</title>
 </head>
 <body>
  <h1><%= request.page.name[] %></h1>
   This page does not exist.
 <a href="<%= "${getRelativeUri("/edit.groovy")}?name=${request.page.name[]}" %>">
   Create?
 </a>
 </body>
</html>

データベースを更新する

前のセクションでは 2 つのビューを作成しました。1 つはレンダリングされるウィキ・ページ、そしてもう 1 つはウィキ・ページを作成するためのフォームです。これらのビューをサポートするには、追加のコントローラーとビューを作成する必要があります。具体的に言うと、view.gt ビューは edit.groovy コントローラーにリンクし、create.gt は edit.gt をレンダリングすることによって、そのフォームを HTTP POST で save.groovy コントローラーに送信します。edit.groovy はデータを取得し、作成ページと同じようなフォームを表示します。この場合にだけ、フォームには既存のウィキ・ページのコンテンツが設定されます。save.groovy は行を挿入するか、あるいはデータベース・テーブルの既存の行を更新します。このそれぞれの実装を、リスト 13 からリスト 15 に示します。


リスト 13. edit.groovy の実装
                
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page = data.queryFirst("SELECT COUNT(*) FROM pages WHERE name=$name")

if (page) {
  request.page.content = page.content
} else {
  request.page.content = ""
}
request.page.name = name
request.view = 'edit.gt'
render()


リスト 14. edit.gt の実装
                
<html>
 <head>
  <title><%= request.page.name[] %> - Editing</title>
 </head>
 <body>
  <h1>Editing <%= request.page.name[] %></h1>
  <form method="POST"
  	action="<%= "${getRelativeUri('/save.groovy')?name=${request.page.name[]}" %>">
   <textarea name="content" rows="20" cols="60"><%= request.page.content[] %></textarea>
   <input type="submit" value="Save Page"/>
  </form>
 </body>
</html>


リスト 15. save.groovy の実装
                
def name = request.params.name[]
def data = zero.data.groovy.Manager('wiki')
def page data.queryFirst("SELECT * FROM pages WHERE name=${name}")
def content = request.params.content[]

if (page) {
  data.update("UPDATE pages SET content=${content}")
} else {
  data.update("INSERT INTO pages (name,content) VALUES ($page_name,$content")
}

uri = "${getAbsoluteUri('/view.groovy')}?name=${name}"
request.headers.out.Location = uri
request.status = HttpURLConnection.HTTP_MOVED_TEMP

アプリケーションをテストする

これで、極めて基本的なウィキ・アプリケーションが完成しました。実際、あまりにも基本的なため、アプリケーションをブートするには存在しないウィキ・ページを指定する必要があります。それには、http://localhost:8080/view.groovy?name=HomePage と入力してください。図 7 のページが表示されるはずです。


図 7. HomePage が見つからない場合

上記にはページが存在しないと示されています。これはアプリケーションが機能していることを意味しており、正常な動作です。URI の name パラメーターにはどんな値でも入力できましたが、「HomePage」と入力したのは、これが手始めとしては妥当だと思ったからです。次に、この HomePage のコンテンツを作成します。任意の HTML を入力して、できればページ (存在していないとわかっているページでも構いません) に確実に飛ぶようにリンクを追加してください (図 8 を参照)。


図 8. HomePage の編集

Save Page ボタンをクリックしてページをデータベースに格納すると、上記で編集したページにリダイレクトされてそのページが表示されます (図 9 を参照)。


図 9. HomePage が見つかった場合

存在しないページにリンクを設定した場合 (データベースには現在 1 つのページしか存在しないため、珍しくないケースです)、そのリンクをクリックするとページが見つからないという画面が再度表示されるはずです。その場合には、リンク先のページに対応するページを作成することができます (図 10 を参照)。


図 10. CodingTips が見つからない場合

以上が、この単純なウィキの機能すべてです。このウィキには当然、他にも多くの機能を加えることができます。例えば、Markdown や Textile などのマークアップ・テキストを使えば、特にコンテンツの作成とリンクの指定を単純化することが可能です (後で演習として試してみてください)。

まとめ

Project Zero は、SOA 準拠の Web 2.0 アプリケーションのアジャイル開発を焦点として簡易化された開発プラットフォームです。そんな Project Zero が武器とするライブラリーのなかに、SQL クエリーを実行するための単純な API があります。この記事では、これらの API を利用して単純なウィキを作成する方法を説明しました。

この記事でまず説明したのは、pureQuery API のラッピングを含め、zero.data API の背後にある動機です。さらに zero.data.Manager の詳細を検討した上で、Java バージョンと Groovy バージョンとでの API の違いを概説しました。続いて実際に zero.data API を使用するアプリケーションを作成し、単純なウィキの作成、データベース・テーブルの初期化、そして最後に実装のコーディングを実践してみました。この記事が読者にとって役立ち、これから Zero アプリケーションの作成に取り組もうという気になっていただけたことを望みます。必要とあらば、活発な Project Zero コミュニティーがいつでも助けになってくれるはずです。





上に戻る


ダウンロード

内容ファイル名サイズダウンロード形式
Sample Project Zero Eclipse projectwa-pz-wiki.zip10KBHTTP
ダウンロード形式について


参考文献

学ぶために
  • Project Zero の紹介、第 1 回: Web アプリケーションのための RESTful なサービスを作成する」(developerWorks、2007年10月) は、強力な Web アプリケーションを作成、アセンブル、デプロイする Project Zero の革新的な方法を分かりやすく説明している実践的ガイドです。

  • Project Zero アプリケーションのセキュリティーを守る、第 1 回: 認証と許可」(developerWorks、2007年11月) では、Project Zero がアプリケーション・リソースのアクセス制御ベースのセキュリティーを簡易化する仕組みを説明しています。

  • Active Content Filtering で強化する Project Zero のセキュリティー」(developerWorks、2007 年 11 月) では、Active Content Filtering を使用して、クロスサイト・スクリプティングをはじめとする一般的な Web 2.0 ベースのアプリケーションに対する攻撃をかわし、Project Zero アプリケーションのセキュリティーを劇的に向上させる方法を解説しています。

  • IBM Data Studio pureQuery Runtime は、Java データベース開発のライフサイクルを管理するための開発ツール、アプリケーションのランタイム API、そしてエンジンをセットにした堅固な開発ツールです。Project Zero ではこのランタイム API とエンジンを使用して、柔軟な Web 2.0 アプリケーション開発環境を提供しています。

  • Groovy Closures には、この高度な言語要素を Groovy で活用するための実際的な方法が記載されています。

  • Template method pattern」(Wikipedia、2007年11月) では、このパターンの詳細、そしてソフトウェア・ライブラリー設計者が API を設計する際にこのパターンを使用して、既存のサービスを変更しなくてもユーザーが新しい機能をシステムに注入できるようにする方法を説明しています。

  • Project Zero アプリケーションのデータベース構成と依存関係を最適化する」(developerWorks、2007年9月) では、複数の Project Zero アプリケーションでデータベース構成を管理する手法を解説しています。

  • zero.data.Manager Javadoc API には、データベース・アクセスに使用できるすべてのメソッドについての詳しい説明が記載されています。

  • Project Zero コミュニティーに参加して、この話題のプロジェクトの全容を理解してください。

  • Project Zero の初心者向けチュートリアル「Get started with Project Zero and PHP」を読んで、今すぐ Project Zero アプリケーションの開発に着手してください。

  • developerWorks Web development ゾーンで、今すぐ Web 2.0 アプリケーションの開発を始めるためのツール、コード、資料を見つけてください。

  • developerWorks Ajax resource center には、Ajax をアプリケーションに組み込んでユーザーの Web エクスペリエンスを劇的に改善するのに役立つ初心者、中級者、上級者向きの情報が豊富に揃っています。


製品や技術を入手するために
  • Project Zero をダウンロードして、独自のウィキを作成してください。


議論するために


著者について

Brandon Smith

Brandon Smith はあらゆるデータの責任者として IBM の Project Zero に取り組んでいます。彼は Carnegie Mellon University で修士号を取得しました。連絡先は、16cards.com および brandon+dW@16cards.comです。


Hanumanth Kanthi photo

Hanumanth Kanthi は、IBM Software Services for WebSphere の IT アーキテクトです。オーストラリアの Victoria University of Technology でコンピューター・サイエンスの修士号を取得しました。連絡先は kanthi@us.ibm.com です。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



はいいいえわからない
 


 


12345
不充分・不完全である大変素晴らしい
 


この記事を共有する

はてなブックマーク はてなブックマーク livedoorクリップ livedoorクリップ del.icio.us del.icio.us Buzzurl(バザール) Buzzurl(バザール) Choix! Choix!
Saafブックマーク Saafブックマーク FC2ブックマーク FC2ブックマーク MM/memo MM/memo ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
CZブックマーク CZブックマーク newsing newsing




上に戻る


Java およびすべての Java 関連の商標およびロゴは、Sun Microsystems, Inc. の米国およびその他の国における商標です。 他の会社名、製品名およびサービス名等はそれぞれ各社の商標です。

    日本IBMについて プライバシー お問い合わせ