第 1 回の「Web アプリケーションのための RESTful なサービスを作成する」では、リソース・ハンドラーとデータ API を使って単純なテーブルを RESTful なリソースとして公開する方法を説明しました。また、RESTful なサービスを起動する Dojo ベースのアプリケーションも作成しました。
今回はこのサンプル・アプリケーションを拡張して、より複雑なデータを RESTful なスタイルで公開する方法を紹介します。さらに前回とは別の利用者用アプリケーションも作成します。このアプリケーションの作成手順に従って、Zero を使ってリソースをモデル化し、Zero のイベント・ベースのクライアント・プログラミング・モデルを使って簡単なリッチ・クライアントを作成する方法を説明します。
第 1 回の演習では、incentive テーブルを RESTful なサービスとして公開しました。今回の記事ではこの一般的なサンプル・アプリケーションを拡張します。図 1 に、ユース・ケース図を示します。
図 1. ユース・ケース
ロールには、利用者 (Consumer) とインセンティブ・プロバイダー (Incentive provider) の 2 つがあります。したがって、次の 2 つのアプリケーションを作成することになります。
- プロバイダー用インセンティブ・アプリケーション
- プロバイダーが、(プロバイダーが提供する) インセンティブを管理し、インセンティブの利用対象者を見つけるための、アプリケーションです。この記事では、インセンティブを対象とした RESTful なサービスの作成のみに焦点を絞ります。
- 利用者用インセンティブ・アプリケーション
- 利用者がインセンティブを見つけられるようにするためのアプリケーションです。プロバイダーまたはロケーションのどちらかを基準にインセンティブを検索できるようにします。
エンタープライズでは、サーバー中心の考え方に追従するのは、プラットフォーム (Java™ EE ベースのサーバーなど) です。つまり、Web アプリケーションはアプリケーション・サーバー・プラットフォーム上でビルド、そしてデプロイされ、WebSphere® などのサーバー・プラットフォームが Java EE 仕様で要求されるあらゆるサービス品質を実現することになります。このようなサービスの例には、キュー・ベースのメッセージング、分散トランザクション、プロトコル管理などがあります。アプリケーション・サーバーが 1 つの Java 仮想マシン上で複数のアプリケーションを実行することもよくありました。そして、アーキテクトがアプリケーションを設計する際の基本概念は、ソフトウェアおよびデータ・リソースを他のアプリケーションと共有し、アプリケーション・サーバーからサービスを (そのサービスが使用されていない場合でも) 提供するというものでした。
アプリケーションが、孤立したアプリケーション・サーバーにデプロイされているとしても、大抵の場合は依然としてサーバー自体が利用可能なすべてのサービスを保持します。アプリケーション・サーバーはエンタープライズ・レベルの統合を可能にするからです。エンタープライズ統合の特徴としては、各種システムにまたがる分散トランザクション、重要なデータ配信のためのキュー・ベースのメッセージングなど、さまざまなタイプのサービスがあります。以下の図 2 は、エンタープライズ統合の一例を示したものです。エンタープライズ内のプラットフォームは各種のプロトコルとミドルウェアの管理を中心に設計され、場合によっては多数のアプリケーションに対応するエンタープライズ・データベースと通信します。
図 2. エンタープライズ・レベルの統合
Web 2.0 の世界には、それほど重要でない類の HTTP レベルでの統合が関わってきます。通常、アプリケーション設計の中心となるのは一連のデータです。これらのデータは公開されて他のデータ・セットと組み合わせられ、データ・プロバイダーが予期しないような新しいアプリケーションを作り出すように意図されています。図 3 に、統合の一例を示します。
図 3. Web 2.0 での統合
アプリケーションはデータを中心に設計され、HTTP によって RESTful に公開されます。すると、リッチ・インターネット・アプリケーションは、そのデータをさまざまに組み合わせて適合させることで、新しい状態を作り出すことができます。例えば、マップ・アプリケーションがマップ上のポイントを RESTful に公開すると、雇用管理ツールといったまるで別のアプリケーションが一連の従業員をマップ・アプリケーションに組み合わせ、従業員の配属場所を示すビジュアル・マップを作成することができるといった具合です。こういった機会をもたらすのは、2 つのデータ・セットのマッシュアップです。エンタープライズにおいては重要ではないと言え、このようなアプリケーションがエンタープライズ・プロセスをさらに展開するためには必要になります。
サーバー中心の設計とアプリケーション中心の設計との比較は、スケーリングに関しては行われていません。アプリケーション中心の設計には、アプリケーションのスケーリングを行うための外部エンティティーが必要となり、それにはプロセスを管理し、状態を複製するソフトウェア (WebSphere XD など) が必要になってきます。一方サーバー中心の設計には、アプリケーション・サーバーがスケーリング・メカニズムを組み込むことのできる、より総合的なスケーリング・ソリューションが必要になる場合があります。
アプリケーション中心の設計では、小規模にスタートし、ユーザー数の増加に合わせて規模を拡張していくことは容易であり、ひいては Web 2.0 スタイルの設計における価値命題の実現につながっていきます。そしてもう 1 つの重要な特徴は、Web 2.0 スタイルのアプリケーションからエンタープライズ・アプリケーションを起動できること、またその逆も可能であるという点です。図 4 に示すマッシュアップは、HTTP によってエンタープライズ・アプリケーションにアクセスします。エンタープライズの成果物は WebSphere Web 2.0 Feature Pack などの技術を使用して RESTful に公開できるので、マッシュアップやリッチ・インターネット・アプリケーション (RIA) の一部となることができます。
図 4. マッシュアップによるエンタープライズへのアクセス
いずれの手法にも長所と短所があります。サーバー中心の手法は管理しやすい一方、開発者にとってコードを作成しやすいのはアプリケーション中心の手法です。ただし、アプリケーション中心のソリューションには大抵の場合、それを管理するための外部ソフトウェアが必要になります。
RESTful なデータ
このように、データを Web 2.0 マッシュアップの一部にするにはデータを RESTful に公開することが不可欠です。第 1 回で説明したように Project Zero の中核となるのは REST であり、リソースの公開は REST によって行われます。リソースはインターネットで情報を公開する上での基礎となるので、REST を使用して、異なる Web アプリケーションを容易に構成することができ、複数のリソースからマッシュアップを素早く構成することができます。Project Zero は、このようにリソースを RESTfull に公開するという概念を中心に最適化されています。この記事のサンプル・アプリケーションで公開する必要があるのは、エネルギー・プロバイダーが提供するインセンティブです。図 5 のデータ・モデルに、プロバイダーとそのインセンティブとの関係を示します。
図 5. プロバイダーとインセンティブのデータ・モデル
ここで目標とするのは、関係者がインセンティブを検索できるようにすることです。さらに、プロバイダーがインセンティブを管理する必要もあります。表 1 に、このデータを RESTful に公開する方法を示します (このような表がリソースを RESTful にモデル化する上でいかに役立つかは、第 1 回で説明しました)。
表 1. REST 設計
| リソース | URI | メソッド | 表現形式 | 説明 |
| プロバイダー | /provider/<providerId> | GET | JSON オブジェクト | プロバイダーのレコードを取得する |
| インセンティブ | /provider/<providerId>/incentive | POST | JSON オブジェクト | インセンティブを新規に作成する |
| インセンティブ | /provider/<providerId>/incentive | GET | JSON オブジェクトの配列 | 特定 providerId のインセンティブのリストを取得する |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | GET | JSON オブジェクト | 個々のインセンティブを取得する |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | PUT | JSON オブジェクト | 単一のインセンティブを更新する |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | DELETE | 単一のインセンティブを削除する | |
| インセンティブ | /incentive?location=<state_name> | GET | JSON オブジェクトの配列 | 任意のプロバイダーの特定状態にあるインセンティブのリストを返す |
第 1 回とは異なり、インセンティブにはプロバイダーの名前空間でアクセスすることができます。インセンティブのライフサイクルはプロバイダーに結び付いているため、提供元のプロバイダーがこれを管理します。RESTful な方法により、インセンティブ・レコードが確実に該当プロバイダー内でネストされ、要件を満たすようにすることはできますが、利用者がプロバイダー全体でインセンティブを検索したい可能性もあります。その場合には、/incentive 名前空間を使用すると、複数のプロバイダーを範囲としたインセンティブのリストを表示することができます。
プロバイダーの数が多い場合には、インセンティブの名前空間がかなり大きくなる可能性があるため、何らかの方法で名前空間を制限しなければなりません。このサンプル・アプリケーションでは、ロケーションを指定しないと /incentive 名前空間にアクセスできないようにしています。また、選択範囲を絞り込むためにクエリー・パラメーターも使用することにしました。
サービスを定義したら、次はサービス品質をサービスに加えられるようになります。非機能要件は、形もサイズもさまざまです (非機能要件に対する適切で実際的な対処法については、記事「Why do non-functional requirements matter?」を参照してください)。REST では HTTP ベースのサービスを提供するため、非機能要件の適用は簡易化することができます。このサンプル・アプリケーションではセキュリティーに対処するため、URL をセキュアにすることによって REST リソースにセキュリティー・ルールを適用します。表 2 は、セキュリティーに重点を置いた REST の例を示す表です。
表 2. セキュアな REST リソース
| リソース | URI | メソッド | ロール | インスタンス・レベルでのセキュリティーの必要性 |
| プロバイダー | /provider/<providerId> | GET | すべて | なし |
| インセンティブ | /provider/<providerId>/incentive | POST | プロバイダー | あり。各プロバイダーが管理できるのは所有するインセンティブのみ |
| インセンティブ | /provider/<providerId>/incentive | GET | すべて | なし |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | GET | すべて | なし |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | PUT | プロバイダー | あり。各プロバイダーが管理できるのは所有するインセンティブのみ |
| インセンティブ | /provider/<providerId>/incentive/<incentiveId> | DELETE | プロバイダー | あり。各プロバイダーが管理できるのは所有するインセンティブのみ |
| インセンティブ | /incentive?location=<state_name> | GET | すべて | なし |
| その他のリソース | /<Anything Else> | すべて | 該当者のみ | 適用外 |
表 2 に示しているのは、URL リソースとそのリソースにアクセスすることができるロールです。重要な考慮事項として、REST はエンティティーの公開パターンを定義します。データによってはインスタンス・ベースのセキュリティーが必要なことはよくあります (例えば、その所有者だけがデータを表示できるようにするなど)。このサンプル・アプリケーションの場合、インセンティブを作成、更新、削除できるのは、そのインセンティブを所有するプロバイダーだけに制限します。この制限をプロバイダーのロールの一部とするだけでは不十分なので、上記の設計表にはデータをインスタンス別に保護する必要があるかどうかを示す列を設けています。
この記事のサンプルを実行するには、以下が必要です。
- Eclipse 3.2 以降。この記事では Eclipse 3.3 を使用しました。
- Eclipse 用 Project Zero Java および Groovy プラグイン
このサンプルは、Zero の M3 Release で作成されています。したがって、Eclipse Update Site は必ず http://www.projectzero.org/update/zero.eclipse.M3 に設定してください。
PHP プラグインはこの演習には必要ありません。プラグインのインストールに関する情報は Project Zero Downloads を参照してください。
注: 第 1 回で M1 プラグインをインストールした場合は、これをアンインストールしてから M3 フィーチャーおよびプラグインをインストールする必要があります。プラグインのアンインストール方法については Eclipse のヘルプを参照してください。
- この記事に付属のダウンロード・ファイル。このファイルは C: ドライブに解凍してください。
- Firefox ブラウザー
- 連載第 1 回で説明した概念を十分に理解していること
その他、以下のツールが役に立ちます。
まず始めにプロバイダー用アプリケーションを作成します。目標は、前に定義した RESTful なサービスを作成することです。第 1 回で学んだ知識を基に、プロバイダー用インセンティブ・アプリケーションを作成していきます。
以下の手順に従って、新規アプリケーションを作成します。
- 新しいワークスペースを開きます。
図 6.
- 新規プロジェクトを作成します。
図 7.
-
Project Zero -> Project Zero Application をプロジェクト・タイプとして選択します。
図 8.
- アプリケーションに
ProviderIncentiveAppという名前を付けます。
図 9.
必要な依存関係を追加する必要があります。第 1 回で説明したように、依存関係の管理には ivy 技術を使用しました (詳細は、第 1 回の記事、または Project Zero Developer’s Guide を参照してください)。
- config ディレクトリーの下にある ivy.xml ファイルを開きます。
図 10.
- Dependencies セクションで Add をクリックします。
図 11.
- 以下の依存関係を追加します。
- zero.data
- zero.data.setup.webtools
- derby
以下に示すのは、依存関係ウィザードです。
図 12.
- ivy.xml ファイルを保存します。ソースを調べると、リスト 1 のような内容になっているはずです。
リスト 1<!-- Note: dependencies from maven require the maven2 notation. --> <dependencies> <dependency name="zero.core" org="zero" rev="1.0+"/> <dependency name="zero.webtools" org="zero" rev="1.0+"/> <dependency name="zero.data" org="zero" rev="1+"/> <dependency name="zero.data.setup.webtools" org="zero" rev="1+"/> <dependency name="derby" org="org.apache.derby" rev="10+"/> </dependencies>
-
Update Dependencies アイコンをクリックします。以前も説明したように、このアイコンをクリックするとリモート・リポジトリーとローカル・リポジトリーにある、すべての構成済みパッケージの最新バージョンの確認が行われます。
図 13.
-
OK をクリックして更新を確認します。
図 14.
- 以上の作業が終わったら、エディターを閉じます。
アプリケーションのコーディングには組み込みバージョンの derby を使用します。開発の際には、これがふさわしい選択肢です。サンプルに必要なテーブルの作成には、Project Zero の M3 ドライバーに新しく導入されたデータベース・セットアップ・ツールを使います。
-
ProviderIncentiveApp プロジェクトを右クリックします。
図 15.
-
General->File System を選択します。
図 16.
-
C:\ProjectZeroArticleSeries/Part2Artifacts/ProviderAppArtifacts を選択します (ダウンロード・ファイルを C: ディレクトリーに解凍したという前提です)。sql を選択してから Finish をクリックします。
図 17.
- プロジェクト・ディレクトリーのレイアウトは、以下の図のようになります。
図 18.
- create.sql ファイルを開きます。ここに、PROVIDER および INCENTIVE テーブルを作成するための DDL が含まれています (リスト 2 を参照)。
リスト 2CREATE TABLE PROVIDER ( PROVIDER_ID VARCHAR (50) NOT NULL, NAME VARCHAR(256) NOT NULL, DESCRIPTION VARCHAR(256) NOT NULL, LOCATION VARCHAR(50) NOT NULL, PROVIDER_TYPE VARCHAR(128), CONTACT VARCHAR(256)); ALTER TABLE PROVIDER ADD CONSTRAINT PROVIDER_PK PRIMARY KEY (PROVIDER_ID); CREATE TABLE INCENTIVE ( INCENTIVEID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1), NAME VARCHAR(256) NOT NULL, DESCRIPTION VARCHAR(256) NOT NULL, PROVIDER_ID VARCHAR (50) NOT NULL, INCENTIVETYPE VARCHAR(128), VALIDFROM TIMESTAMP, VALIDTO TIMESTAMP, WEBSITE VARCHAR(256) ); ALTER TABLE INCENTIVE ADD CONSTRAINT INCENTIVE_PK PRIMARY KEY (INCENTIVEID); ALTER TABLE INCENTIVE ADD CONSTRAINT INC_PPR_FK FOREIGN KEY (PROVIDER_ID) REFERENCES PROVIDER (PROVIDER_ID);
- このように、テーブルを削除してサンプル・データを追加するためのファイルが 1 つあります。次に、アプリケーションを実行するため、プロジェクトを右クリックして Run As -> Project Zero Application を選択します。
図 19.
- コンソールで、アプリケーションが起動して実行中になっていることを確認します。
図 20.
- ブラウザーを開いて、http://localhost:8080/setup にアクセスします。ブラウザーの表示は以下の図のようになるはずです。
図 21.
- 以下の情報を入力した上で、Create Tables をクリックします。
- Database Name:
PRO_DB - Database Type: Apache Derby (Embedded)
- User Name:
APP
図 22.
create.sql スクリプトが正常に実行されたというメッセージが表示されるはずです。
- Database Name:
-
Add Sample Data をクリックします。sample.sql スクリプトが正常に実行されたというメッセージが表示されるはずです。
図 23.
- コンソールで Stop ボタンをクリックしてアプリケーションを停止します。
開発の場合には、このようにアプリケーションを停止、起動しても問題ありませんが、テスト環境や実動環境では管理コマンド・ラインを使用してアプリケーションの停止と起動を行うことをお勧めします。詳細は、Zero Management CLI extensions reference を参照してください。
図 24.
プロバイダー用インセンティブ・アプリケーションのための RESTful なサービスの作成
プロバイダー用インセンティブ・アプリケーションのための RESTful なサービスを作成するには、以下の手順に従ってください。
-
app/resources フォルダーを右クリックして New -> File を選択します。
図 25.
- 新しいファイルに
provider.groovyという名前を付けます。
図 26.
-
Yes をクリックして Groovy サポートをプロジェクトに追加します。
図 27.
- provider.groovy ファイルが開いていることを確認して、リスト 3 のコードを入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ProviderAppArtifacts\codeSnippet\proSnippet.1.txt からこのコードを貼り付けることもできます)。
このコードはデータ API を使用してクエリーを実行し、その結果を JSON 形式で格納します。このパターンは連載第 1 回に記載したとおりです。API についての詳細は、Project Zero Developer’s Guide のデータ・アクセスに関するセクションを参照してください。
onRetrieveメソッドは、プロバイダーの単一インスタンスを取得するハンドラーを表すために使用します。このパターンも同じく第 1 回に記載されています (または、Project Zero Developer’s Guide の Part 1 (or, see Resource handling を参照してください)。サービスの上には、アノテーション付きの情報を伴ったコメントがあります。Project Zero では、このようにして RESTful なリソースを文書化しますす。Project Zero はアノテーション付きコメントを使用して、RESTful な文書、そして REST サービスのテスト・ツールをレンダリングすることになります。このツールの動作は後で紹介します (詳細は、RESTful documentation を参照)。以下のサンプルでは、利用可能な HTTP リターン・コードを文書化し、ファイル形式を記述するとともに戻り値の表示例を記載しています。
リスト 3import zero.data.groovy.Manager; /** * * @success 200 Returns the profile for the provider with the given ID. * @error 404 Not authorized Provider for User * @format application/json * @example * { * "name": "Energy Provider Name", * "description": "Sample Output", * "location": "New Jersey" * "provider_type": "energy" * "contact": "roland@projectzero.org" * } * */ def onRetrieve() { def data = Manager.create('PRO_DB'); def result = null; def id = request.params.providerId[0]; //Note: Next piece of code should be in one line. result = data.queryFirst ("select name,description,location,provider_type,contact from provider where provider_id = $id"); if(result != null) { request.view='JSON' request.json.output = result render() } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Provider $id not found." request.view = "error" render() } }
- このデータベース・ツールを使うと、データベースの構成が data.config ファイル内に生成されます。アプリケーションがこの構成を使用できるようにするには、構成をマスター zero.config ファイルに組み込む必要があります (zero 構成モデルについては第 1 回で説明していますが、zero の構成に関してさらに詳しい内容を調べるには Configuration を参照してください)。
図 28.
- zero.config ファイルの最初の部分を見てください。単純化された新しい構成用の構文があることに気付くはずです。
図 29.
- 以下の図に示す 2 番目のエントリーには、生成されたデータ構成が記載されています。複雑なプロパティーのための新しい構文は JSON 形式を使用します。
図 30.
- メニュー・バーの起動ボタンを使ってアプリケーションを起動します。
図 31.
- ブラウザーから http://localhost:8080/resources/docs にアクセスします。以下の図に示されているのは、使用可能な RESTful なリソースです。Provider を選択してください。
図 32.
- リソース文書化ツールが groovy ファイル内のコメントされた情報をレンダリングします。REST ツールを使ってサービスをテストすることもできます。
図 33.
- フォーマットをクリックすると (以下を参照)、サンプルを表示することができます。
図 34.
図 35.
- この RESTful なサービス用のテスト・ドライバーを起動するには、以下に示す URI をクリックします。
図 36.
-
Send をクリックします。
図 37.
- JSON オブジェクトが返されたことが結果に示されます。
図 38.
このセクションではインセンティブ・サービスを作成し、そのインセンティブ・サービスをプロバイダー・サービスに関連付けます。
- /app/resources フォルダーに新しいファイルを作成し、
incentive.groovyという名前を付けます。
図 39.
- /app/resources フォルダーにもう 1 つ新しいファイルを作成し、
incentive.bndという名前を付けます。
図 40.
- 以下の 2 行を入力します。
provider/incentive incentive
上記はプロバイダーとインセンティブとの関係を定義する行です。ここでは、/provider/<provider_id>/incentive と /incentive 名前空間の両方をサポートするように指定しています。ネストされたパターンだけを許可する場合は、provider/incentive のみを指定することになります。
図 41.
- 以下の
onListメソッドを追加します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ProviderAppArtifacts\codeSnippet/proSnippet3.txt からこのメソッドを貼り付けてください)。ここで注目する点は、groovy ショートカットを使用してヘッダーを調べ、まずプロバイダーが存在するかどうかを確認していることです。プロバイダーが存在する場合は、そのプロバイダーのすべてのインセンティブを対象にクエリーを実行します。providerIdが存在しない場合には、リクエストの対象は /incentives 名前空間となります。また、location パラメーターの有無もチェックされます。このパラメーターがある場合には、クエリーによる SQL 検索が実行され、ない場合には他の呼び出しは許可されません。
リスト 4import zero.data.groovy.Manager; /** * * @success 200 Returns incentives by provider or location. * @error 404 Cannot Query all Incentives in the system. /provider/providerId/incentive or /incentive?location=locationValue must be used. * @format application/json * @example * { * "incentiveId" : "Incentive Id" * "name": "Incentive Name", * "description": "Sample Output", * "providerName": "Provider Name" * "providerId": "Provider Id" * "incentive_type": "Incentive Type" * "validfrom": 1189396800000, * "validto": 1189396800000, * "website": "http://www.projectzero.org" * } * */ def onList() { def data = Manager.create('PRO_DB'); def provider = null def location = null; // List by provider flag if(request.params.providerId) provider = request.params.providerId[0]; // List by location flag if(request.params.location) location = request.params.location[0]; def result = null; if(provider != null) { result = data.queryList("select i.incentiveId,i.name,p.name as providerName,i.provider_id,i.incentivetype as incentive_type,i.validFrom,i.validTo,i.website,p.location from provider as p,incentive as i where p.provider_id = $provider and i.provider_id = p.provider_id"); } else if (location != null) { result = data.queryList("select i.incentiveId,i.name,p.name as providerName,i.provider_id,i.incentivetype as incentive_type,i.validFrom,i.validTo,i.website,p.location from provider as p,incentive as i where p.location = $location and i.provider_id = p.provider_id"); } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Cannot Query all Incentives in the system. /provider/providerId/incentive or /incentive?location=locationValue must be used." request.view = "error" render() return; } if(result != null) { request.view='JSON' request.json.output = result render() } }
- ファイルを保存します。
ブラウザーに戻り、http://localhost:8080/resources/doc にアクセスして Incentive リンクを選択します。
図 42.
- インセンティブ URI はプロバイダー名前空間の下にあります。
M3 にはバグがあり、Resource 文書にはそのリソースの 1 つのパターンしか表示されません。このバグは次回のマイルストーンで修正される予定です。
図 43.
- URI をクリックします。Provider ID には
austinEnergyと入力してください。
図 44.
- Austin Energy のインセンティブ・リストが再表示されます。
図 45.
- ブラウザーで、http://localhost:8080/resources/incentive のインセンティブを検索してみてください。以下に示すようなエラーが返ってくるはずです。
図 46.
- ブラウザーか、または Firefox Poster のようなツールを使って、http://localhost:8080/resources/incentive?location=Texas の GET リクエストを実行します。以下の図は、Poster ツールを使用した場合の結果です。
図 47.
- incentive.groovy ファイルに戻って、このファイルにリスト 5 のコードを入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ProviderAppArtifacts\codeSnippet/proSnippet3.txt からコードを貼り付けます)。このコードには、個々のインセンティブを取得するための呼び出し、そしてインセンティブを作成、更新、削除するための呼び出しが含まれています。このコードは、第 1 回に記載したタイプのコードとよく似たものです。
リスト 5/** * * @success 200 Returns incentive by id. * @error 404 Incentive Id not found. * @format application/json * @example * { * "incentiveId" : "Incentive Id" * "name": "Incentive Name", * "description": "Sample Output", * "providerName": "Provider Name" * "incentive_type": "Incentive Type" * "validfrom": 1189396800000, * "validto": 1189396800000, * "website": "http://www.projectzero.org" * } * */ def onRetrieve() { def data = Manager.create('PRO_DB'); def id = request.params.incentiveId[0]; result = data.queryFirst("select i.incentiveId,i.name,i.description,p.name as providerName,i.incentivetype as incentive_type,i.validFrom,i.validTo,i.website from provider as p,incentive as i where i.incentiveId = $id"); if(result != null) { request.view='JSON' request.json.output = result render() } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Incentive $id not found." request.view = "error" render() } } /** * * @success 204 Post new Incentive for the provider. * @error 403 Not authorized to insert this record. * @error 404 Cannot Post directly to /incentives, only /provider/<providerId>/incentive * @format application/json * @example * { * "name": "Incentive Name", * "description": "Sample Output", * "incentive_type": "Incentive Type", * "validfrom": 1189396800000, * "validto": 1189396800000, * "website": "http://www.projectzero.org" * } * */ def onCreate() { def provider = request.params.providerId[0]; if(provider != null) { def data = Manager.create('PRO_DB'); def incentive = zero.json.JsonType.fromData(request.input[]).getJson() def user = request.subject['remoteUser']; def validFrom = new java.sql.Timestamp(incentive.validfrom); def validTo = new java.sql.Timestamp(incentive.validto); def key = data.insert("insert into incentive (name,description,provider_id,incentivetype,validfrom,validto,website) values ($incentive.name,$incentive.description,$provider,$incentive.incentivetype, $validFrom,$validTo,$incentive.website)",['incentiveId']); def locationUri = getRequestedUri(false) + '/' + key request.headers.out.Location = locationUri request.status = HttpURLConnection.HTTP_NO_CONTENT } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Cannot POST directly to /incentive, only /provider/<providerId>/incentive." request.view = "error" render() return; } } /** * * @success 204 Delete Incentive for the provider. * @error 403 Not authorized to insert this record. * @error 404 Cannot delete directly to /incentives, only /provider/<providerId>/incentive * */ def onDelete() { def provider = request.params.providerId[0]; if(provider != null) { def data = Manager.create('PRO_DB'); def id = request.params.incentiveId[0]; def user = request.subject['remoteUser']; data.update("delete from incentive where incentiveId = $id"); request.status = HttpURLConnection.HTTP_NO_CONTENT } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Cannot DELETE directly to /incentive, only /provider/<providerId>/incentive." request.view = "error" render() return; } } /** * * @success 204 Incentive updated for provider. * @error 403 Not authorized to update this record. * @error 404 Cannot Put directly to /incentive/<incentiveId>, only /provider/<providerId>/incentive/<incentiveId> * @format application/json * @example * @example * { * "name": "Incentive Name", * "description": "Sample Output", * "incentive_type": "Incentive Type", * "validfrom": 1189396800000, * "validto": 1189396800000, * "website": "http://www.projectzero.org" * * } * */ def onUpdate() { def provider = request.params.providerId[0]; if(provider != null) { def data = Manager.create('PRO_DB'); def incentive = zero.json.JsonType.fromData(request.input[]).getJson() def user = request.subject['remoteUser']; def id = request.params.incentiveId[0]; def validFrom = new java.sql.Timestamp(incentive.validfrom); def validTo = new java.sql.Timestamp(incentive.validto); data.update("update incentive set name=$incentive.name,description=$incentive.description,incentivetype = $incentive.incentiveType,validfrom=$validFrom,validto=$validTo,website= $incentive.website where incentiveId = $id "); request.status = HttpURLConnection.HTTP_NO_CONTENT } else { request.status = HttpURLConnection.HTTP_NOT_FOUND request.error.message = "Cannot Put directly to /incentive/<incentiveId>, only /provider/<providerId>/incentive/<incentiveId>." request.view = "error" render() return; } }
要件の一環として、インセンティブの作成、更新、削除の操作はそのインセンティブを所有するプロバイダーだけが行えるようセキュアにしなければなりません。この作業は、まず組み込み Zero File Registry を使って始めます。User File Registry は開発に適したオプションです。Project Zero は LDAP ベースのレジストリーもサポートしており、大抵の実動環境では LDAP を使用することがベスト・プラクティスです。Project Zero では、デプロイメント時にデフォルト・レジストリーを上書きするのは簡単です。
- ブラウザーで http://localhost:8080/zero/webtools/user にアクセスします (以下の図を参照)。
以下の情報を入力します。- UserName: austinEnergy
- Password: passw0rd
- Groups: Provider
add をクリックします。
図 48.
- 別のユーザーを以下の図のように入力します。
- UserName: centerPoint
- Password: passw0rd
- Group: Provider
add をクリックします。
図 49.
- これで、File Registry に 2 人のユーザーが登録されたことになります。
図 50.
- config ディレクトリーには、以下に示すように zero.users ファイルが表示されているはずです (このファイルを表示するには Eclipse Project を更新しなければならない場合があります)。
図 51.
この時点で、許可ルールを追加する必要があります。RESTful な URI はセキュアにしなければなりません。サポートされない URI は存在しないグループでセキュアにし、さらに RESTful なデータは所有者だけがアクセスできるようにします。これは、Project Zero がインスタンス・ベースのセキュリティーをサポートしていることを示しています。
- config ディレクトリーに新しいファイルを作成します。
図 52.
- 新しいファイルに
security.configという名前を付けます。
図 53.
-
リスト 6 のテキストを入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ProviderAppArtifacts\codeSnippet\proSnippet4.txt からこのテキストを貼り付けます)。
このテキストは rule.config を組み込み、一連のパラメーターを入力します。
uriは REST url を定義するパラメーターです。垂直バーは、URI パターンの後に続くあらゆるものも考慮します。最初のルールでは、/incentive 名前空間での UPDATE HTTP メソッドを誰に対しても非許可とし、2 番目のルールではログインしたプロバイダーだけに UPDATE メソッドの実行を許可しています。例えば austinEnergy としてログインした場合に austinEnergy 名前空間で実行できる操作は、POST、DELETE、PUT のみです。詳細は、Project Zero Developer’s Guide の Security considerations に記載されています。
リスト 6@include "${/config/dependencies/zero.core}/config/security/rule.config" { "uri":"/resources/incentive|", "condition":"urimatches", "authType":"Basic", "groups":"[NO_ONE]", "methods":"DELETE|POST|PUT" } @include "${/config/dependencies/zero.core}/config/security/rule.config" { "uri":"/resources/provider/{remoteUser}|", "condition":"urimatches", "authType":"Basic", "methods":"DELETE|POST|PUT" }
- config ディレクトリーに含まれている zero.config ファイルを開きます。
図 54.
- security.config ファイルのための
includeエントリーを追加します。
図 55.
RESTful なリソースをセキュアにしたところで、REST 文書化ツールを使ってセキュリティーのテストを行います。
- プロバイダー用アプリケーションを終了 (コンソールの Stop ボタンをクリック) してから再起動します。起動ショートカットを使用しても構いません。
図 56.
- ブラウザーで http://localhost:8080/resources/docs にアクセスし、Incentive をクリックします。
図 57.
- 使用できる HTTP のメソッドがすべて表示されます (以下を参照)。
図 58.
- 個々のレコードを対象とした GET をクリックします。
図 59.
- Provider ID には
austinEnergyを、Incentive ID には1を入力します。
図 60.
- JSON オブジェクトが返されます。
図 61.
- 結果ウィンドウを閉じます。
POST の形式をクリックします。
図 62.
- JSON のサンプルをコピーします。
図 63.
- POST の URI をクリックします。上記の値を Body に貼り付け、Provider ID には
austinEnergyと入力します。
図 64.
- 認証は成功するはずです。
User Name には
austinEnergy、Password にはpassw0rdと入力します。
図 65.
- 以下の結果が表示されます。POST の結果が格納されている場所をメモしておいてください。
図 66.
- 必要であれば、Incentive ID を 5 に設定して PUT と DELETE をテストできます。以下の図では、DELETE の場合を示しています。
図 67.
- austinEnergy としてログインしている状態で、URI を使用して POST を再び開きます。
centerPointURI にあるデータで POST を試してみてください。
図 68.
- 403 Forbidden エラーが返ってくるはずです。
図 69.
アプリケーションのインセンティブに関する演習はこれで完了です。次は利用者用サンプル・アプリケーションを作成するので、アプリケーションは実行中のままにしてください。
これまで Data API を使ってリソース・ハンドラーを作成する方法を説明してきましたが、Project Zero の M2 にはリソースをモデル化する別の方法も導入されています。SQL のコーディングを選ぶか、パーシスタンス技術を選ぶかは開発者によってさまざまです。Zero Resource モデルでは、データと REST (オブジェクトとは限りません) とのマッピングに重点が置かれています。
リモート REST リソースを呼び出すために Zero Connection API を使用する高速クライアントを作成するには、Zero Resource に加え、Zero Web Template 技術を使用することになります。
最初のステップは、新しいアプリケーションを作成することです。
-
ConsumerIncentiveAppという名前の Project Zero Application を新規に作成します。
図 70.
-
ConsumerIncentive アプリケーションを右クリックして Import を選択します。
図 71.
- From directory は C:\ProjectZeroArticleSeries\Part2Artifacts\ConsumerAppArtifacts に設定されているはずなので、sql フォルダーのみを選択します (以下を参照)。
図 72.
- 以下の図に示す create.sql ファイルを確認します。
図 73.
- consumer テーブルはフィールドが 4 つの非常に単純なものであることを確認してください。
図 74.
-
zero.config ファイルを開きます。
図 75.
- デフォルトのポート番号を
8081に変更します。これにより、両方のアプリケーションを同時に実行できるようになります。
図 76.
-
ivy.xml を開きます。
図 77.
- Dependencies に以下の依存関係を追加します。
- derby
- dojo
- zero.data
- zero.data.setup.webtools
- zero.web.template
- zero.resource
図 78.
- 依存関係を更新します。
図 79.
- Consumer を実行します。
図 80.
- Console タブ上で、アプリケーションが Port 8081 で実行中になっていることを確認します。
図 81.
- 利用者用アプリケーションに対してデータベース・セットアップ・ツールを実行します。ポートは http://localhost:8081/setup/ のように指定します。
Database Name には
CON_DB、Database Type には Apache Derby (Embedded) と入力し、Create Tables をクリックします。
図 82.
-
Add Sample Data をクリックします。
図 83.
- アプリケーションの zero.config ファイルをもう一度開き、/config/reosurce/dbKey="COB_DB" という行を図 84 のように入力します。
図 84.
- 利用者用アプリケーションを終了します (プロバイダー用インセンティブ・アプリケーションは終了しないでください)。
このセクションでは、consumerテーブルに基づく単純なリソース・モデルを作成します。M2 はこの技術のプレビュー・リリースなので、その使用方法を表すには極めて単純なパターンを使います (この連載では今後、これよりも手の込んだサンプルを使用する予定です)。
- 新しいソース・フォルダーを作成するために、
appディレクトリーを右クリックして New -> Source フォルダーを選択します。
図 85.
-
app/modelsという名前のフォルダーを作成します。
図 86.
- app/models フォルダーのなかに新規ファイル、
consumer.groovyを作成します。
図 87.
- Finish をクリックして Groovy サポートを追加します。
- リスト 8 のコードを consumer.groovy に入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ConsumerAppArtifacts\conSnippet2.txt からこのコードを貼り付けます)。これによって、単純なモデルが作成されます。
リスト 8import zero.resource.fields.* fields = [ name: [type:'CharField'], state:[type:'CharField'] , provider:[type:'CharField'] ]
- これで、Zero API または HTTP を使用してローカルからデータにアクセスできるようになります。
HTTP でモデルを公開するために、/app/resourcesフォルダーにファイルをもう 1 つ作成します。
図 88.
- このファイルにも consumer.groovy という名前を付けます。consumer.groovy ファイルの重複に関するエラーが表示されますが、このエラーは無視して構いません。
図 89.
- 以下に示すように、
ZRM.delegate()と入力します。このコードは、HTTP によってモデルを公開します。
図 90.
- 利用者用アプリケーション (プロバイダー用アプリケーションではありません) が実行されている場合は終了してから、再度、利用者用アプリケーションを起動します。
図 91.
- ブラウザーを開いて (または Firefox Poster プラグインを使用して)、http://localhost:8081/resources/consumer にアクセスします。
図 92.
- 最終的な JSON テキストを開き、利用者のリストを表示します。
図 93.
-
http://localhost:8081/resources/consumer/
1
にアクセスします。取得されるレコードは 1 つだけのはずです。
図 94.
- 単一のレコードが返されます。
図 95.
このセクションでは、Zero の Web テンプレートを使って非常に単純なリッチ・インターネット・クライアントを作成します。第 1 回では Dojo クライアントから RESTful なサービスを起動する方法を説明しましたが、Zero ではこの他のパターンもサポートします。例えば、ここで説明する HTML フラグメントをフェッチするというパターンです (この連載では今後、Dojo と Zero Templating を併せて使用する予定です)。Zero クライアントについての詳細は、Writing rich Web applications を参照してください。
Zero クライアント・プログラミング・モデルでは、Zero サーバー・イベントが JavaScript イベントに応答することが可能になります。Zero サーバー・イベントは、グローバル・コンテキストのクライアント・ゾーンを使ってデータを共有することもできます。
-
public ディレクトリーの下に新しいファイルを作成します。
図 96.
- ファイルに
incentiveSearch.zhtmlという名前を付けます。
図 97.
-
リスト 9 の HTML コードを入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ConsumerAppArtifacts\conSnippet3.txt からこのコードを貼り付けます)。
この HTML テンプレートは 2 つの Dojo Grid コンポーネントを使用しています。その 1 つは利用者のデータを保持するコンポーネント、そしてもう 1 つはインセンティブの結果を保持するコンポーネントです。Groovy 言語を使用すると、UI イベントに応答してサーバーまたはクライアントのいずれかでアプリケーションのイベントを作成することができます。Project Zero では、Ajax ライフサイクルを使ってアプリケーションのイベントを宣言するために以下の定義構文を使用します。
on("<UI_event>").fire("<application_event>").before ("<before_event>").after("<after_event>")
before_event Ajax リクエストの前に起動するイベントを指定。ロード状況の表示、データ検証など。 after_event Ajax 要求の後に起動するイベントを指定。ロード状況の非表示、UI 更新など。 application_event 起動されるイベント。データの更新/フェッチ、UI の更新、あるいはカスタム biz/UI ロジックなど。
実行時には、イベントの処理は before_event --> application_event --> after_event の順に行われます。
Ajax ライフサイクルでは当然のことながら、application_event はサーバー側で処理されます。before_event と after_event を処理するのは通常、クライアント側です。詳細は、Writing Rich Web Applications を参照してください。
リスト 9<html> <head> <title>Incentive Search</title> <style type="text/css"> @import "incentiveSearch.css"; </style> <script type="text/javascript" src="/dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script> <script type="text/javascript"> dojo.require("dojox.grid.Grid"); dojo.require("dojox.grid._data.model"); dojo.require("dojo.data.ItemFileWriteStore"); dojo.require("dijit.form.ValidationTextBox"); dojo.require("dijit.form.DateTextBox"); dojo.require("dojox.grid._data.editors"); dojo.require("dojox.grid.editors"); dojo.require("dojox.grid._data.dijitEditors"); dojo.require("dojo.parser"); </script> <% on(".search:submit").fire("incentiveSearch").after("incentiveRender") %> </head> <body class="tundra"> <h1> Consumer Incentive Search </h1> <br> <br> <form class=.search> <div id="consumerGrid" dojoType="dojox.Grid" structure="consumerLayout"> </div> </form> <br> <br> <hr> <div id="incentiveGrid" dojoType="dojox.Grid" structure="incentiveLayout"> </div> </body> </html>
- public ディレクトリーに
incentiveSearch.groovyという別のファイルを作成します。このファイルに、incentiveSearch.groovy ファイルのクライアント・イベントに応答するイベント・ハンドラーを含めます。
図 98.
-
リスト 10 のコードを入力します (または、C:\ProjectZeroArticleSeries\Part2Artifacts\ConsumerAppArtifacts\conSnippet4.txt からこのコードを貼り付けます)。
onInitializeメソッドは、テンプレートがロードされると呼び出されます。利用者の情報を取得するためにリソース・モデルのローカル API が使われますが、その API はクライアント・ゾーンに書き込まれます。リソース API についての詳細は、Programmatic Model API を参照してください。
それぞれのイベントごとに 1 つのイベント・ハンドラーがあります。イベント・ハンドラーはリクエスト・パラメーターの有無を調べてプロバイダー検索を行うか、ロケーション検索を行うかを決定します (接続についての詳細は、Using the Connection API を参照)。ここではペイロードをクライアント・ゾーンに変換するために、JSON API も使用しています。変換されたクライアント・ゾーンには、JavaScript クライアントとサーバー Groovy コードの両方がアクセスできます。
リスト 10import zero.core.connection.*; import zero.resource.*; def onInitialize() { def collection = TypeCollection.retrieve('consumer'); def result = collection.list(); def items = []; for(resultItem in result) { def item = [name:resultItem.name ,id:resultItem.id ,state:resultItem.state, provider:resultItem.provider ] items.add(item); } client.data.consumer = items; client.data.incentives = []; } def onIncentiveSearch() { if(event.input.location[]) { Connection.Response response = Connection.doGET("http://localhost:8080/resources/incentive?location= ${event.input.location[]}"); client.data.incentives = zero.json.java.JSONArray.parse(response.getResponseBodyAsString()); } else if(event.input.provider[]) { Connection.Response response = Connection.doGET("http://localhost:8080/resources/provider/ ${event.input.provider[]}/incentive"); client.data.incentives = zero.json.java.JSONArray.parse(response.getResponseBodyAsString()); } else { client.data.incentives = []; } }
- public ディレクトリーに incentiveSearch.js という別のファイルを作成します。このファイルに、クライアント・イベントが含まれることになります。これらのコールバックを使用して、サーバー呼び出しの結果をレンダリングします。
図 99.
- リスト 11 のコードを入力します。このコードでは Dojo FileStore と Grid API の両方を使ってローカルでデータをロードします。Dojo Grid の使用方法についての詳細は、Grid の資料を参照してください。
リスト 11formatDate = function(date) { var d = new Date(); d.setTime(date); return d; } formatLocationLink = function(location) { var locationLink = '<input type="submit" name="location" class="button linktd" value="'; locationLink += location; locationLink += '"/>'; return locationLink; } formatProviderLink = function(provider) { var providerLink = "<input type='submit' name='provider' class='button linktd' value='"; providerLink += provider; providerLink += "'/>"; return providerLink; } var consumerLayout = [{ cells: [[ {name: 'Id', field: "id", width:"10%"}, {name: 'Name', field: "name", width:"30%"}, {name: 'State', field: "state", width:"35%",formatter:formatLocationLink}, {name: 'Provider', field: "provider", width:"25%",formatter:formatProviderLink} ] ] }]; var incentiveLayout = [{ cells: [[ {name: 'Provider', field: "providername",width:"20%"}, {name: 'Type', field: "incentive_type",width:"20%"}, {name: 'Provider Location', field: "location",width:"20%"}, {name: 'Valid From', field: "validfrom",width:"20%",formatter:formatDate}, {name: 'Valid To', field: "validto",width:"20%",formatter:formatDate} ] ] }]; var consumerMeta = { id:'id', items:[], label:'consumer' } var incentiveMeta = { id:'incentiveid', items:[], label:'incentive' } function onLoad(){ zfire("renderConsumers"); } function onRenderConsumers() { consumerMeta.items = dojo.clone(zget("/client/data/consumer")); console.debug(consumerMeta.items); var consumerStore = new dojo.data.ItemFileWriteStore({data: consumerMeta}); var consumerModel = new dojox.grid.data.DojoData(); consumerModel.store = consumerStore; consumerModel.query = {id:'*'}; var consumerGrid = dijit.byId('consumerGrid'); consumerGrid.setModel(consumerModel); } function onIncentiveRender() { incentiveMeta.items = dojo.clone(zget("/client/data/incentives")); console.debug(incentiveMeta.items); var incentiveStore = new dojo.data.ItemFileWriteStore({data: incentiveMeta}); var incentiveModel = new dojox.grid.data.DojoData(); incentiveModel.store = incentiveStore; incentiveModel.query = {incentiveid:'*'}; var incentiveGrid = dijit.byId('incentiveGrid'); incentiveGrid.setModel(incentiveModel); }
- UI の拡張用に incentiveSearch.css ファイルが提供されています。C:\ProjectZeroArticleSeries\Part2Artifacts\ConsumerAppArtifacts\incentiveSearch.css を public ディレクトリーにインポートしてください。
図 100.
- UI を起動するには、ブラウザーを開いて http://localhost:8081/locationSearch.zhtml にアクセスします。すると、クライアントが以下の画面をレンダリングします。
図 101.
-
Texas リンクをクリックしてインセンティブ検索を開始します。
図 102.
- 同じように、それぞれのプロバイダーをクリックしてプロバイダー検索を開始してください。
図 103.
図 104.
今回の記事では、Zero の新しい概念をいくつか紹介するとともに、より複雑なデータを公開して URL ベースのリソースをセキュアにすることに重点を置いて、アプリケーション中心の設計を詳しく説明しました。
さらに、リソースをモデル化する新しい方法と Zero クライアント API についても理解してもらえたはずです。
次回はリソースのモデル化についてさらに詳しく説明し、Dojo 1.0 と Zero クライアント・プログラミング・モデルを使って、さらにソリューションを組み立てます。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Sample code for this article | Part2Artifacts.zip | 10KB | HTTP |
学ぶために
- 代表的な Web 技術をベースにして簡単にアプリケーションを作成、アセンブル、実行するための環境を導入する Project Zero の全容を学んでください。
-
Project Zero Developer's Guide には、Zero アプリケーションのアーキテクチャーを定義する中心的概念を説明しています。
- 現在進行中の開発についてのヘルプ、フィードバック、注意、議論などには Project Zero フォーラムを活用してください。
- 「Why do non-functional requirements matter?」(developerWorks、2006年1月) は、非機能的要件に対する実用的な対処方法となります。
- Java Platform を対象としたアジャイルな動的言語、Groovy について学んでください。
- Project Zero アプリケーションや Project Zero を対象とした新しい PHP 機能拡張を開発するために PHP のインストールおよび構成する方法を読んでください。
- developerWorks の Project Zero に関するその他の記事、チュートリアルを参照してください。
- developerWorks の REST に関するその他の記事、チュートリアルを参照してください。
- JavaScript のツールキット、Dojo と Dojo ウィジェットに関するすべてを学んでください。
-
REST (Representational State Transfer) については、Roy Thomas Fielding の論文「Architectural Styles and the Design of Network-based Software Architectures」を読んでください。
-
JSON および Project Zero での JSON サポートについての詳細を調べてください。
- オープン開発プラットフォーム、Eclipse の全容を学んでください。
- Mozilla による Web ブラウザー、Firefox と Poster プラグインの詳細を調べてください。
- 完全に Java で実装されたオープンソースのデータベース、Apache Derby について読んでください。
- Web 作成者と Web マスターを対象とした caching tutorial で、キャッシングについて詳しく学んでください。
-
コミュニティー主導型商業開発 (CD/CD) について学んでください。
- 「リソース指向Webサービスとアクティビティー指向Webサービスを比較する」(developerWorks、2004年10月) では、REST スタイルと SOAP スタイルの Web サービスの関係について概説しています。
-
この連載の RSS フィード (RSS の詳細を調べてください。)
-
テクノロジーのブックストアで、この記事で取り上げた技術やその他の技術に関する本を探してください。
- developerWorks の Architecture エリアで、アーキテクチャー分野でのスキルを伸ばすために必要な資料を入手してください。
-
テクノロジーのブックストアで、この記事で取り上げた技術やその他の技術に関する本を探してください。
製品や技術を入手するために
-
Project Zero Downloads
-
IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere のアプリケーション開発ツールとミドルウェア製品を使ってみてください。
議論するために

Steve Ims はシニア・テクニカル・スタッフ兼 Project Zero ランタイム「コア」のリーダーです。Project Zero フォーラムに、彼の投稿が載っています。