これまで、Web ベースのクライアントをリッチ・クライアントにするには、各種の技術を 1 つのシステムに組み合わせて Web ベースのアプリケーションを作成しなければなりませんでした。これらの技術には以下のものがあります。
- サーバー・サイドの Web またはアプリケーション・サーバー。Apache HTTP Server、Microsoft® IIS (Internet Information Services)、Sun Java™ Web Server、IBM® WebSphere®、または BEA WebLogic など
- サーバー・サイドのスクリプト言語または処理言語。Java、PHP、JSP (JavaServer Pages™)、または ASP (Active Server Pages) など
- クライアント・サイドのスクリプト作成およびフォーマット設定。HTML、CSS (Cascading Style Sheets)、JavaScript、または DOMなど
- HTTP 通信プロトコルまたは API (Application Program Interface)。XMLHttpRequests または JSON (JavaScript Serialized Object Notation) など
しかし、今では Jaxer を使用できます。この新しい Ajax サーバーは上記の技術すべてを 1 つのサーバーに統合してデプロイするだけでなく、クライアント・ベースの技術のいくつか (JavaScript コード、DOM など) を使用してサーバー・サイドのスクリプトや処理を提供します。無料のオープンソース・コードの Jaxer はそのまま使用することも、付属の JavaScript フレームワークを使って拡張することもできます。
想像してみてください。JavaScript コードを直接 HTML ページで使用して、そのコードをサーバー・サイドで実行してクライアント・サイドの HTML に戻すように指定するだけでよいとしたらどうでしょう。そうなれば、クライアントからサーバーへの通信を、ページの更新をせずに直接必要な部分だけ行うことができます。さらに、サーバー・サイドで実行された JavaScript コードに基づいて HTML を作成することができます。この方法を用いれば技術の数も作成しなければならないコードの量も減るため、開発者とユーザーの双方にとって全体的なエクスペリエンスが改善されることになります。
ユーザーには、リッチなネイティブ・アプリケーションにより近い Ajax ベースの機能を提供できるようになります。なぜなら、Jaxer は初めての正真正銘の Ajax サーバーだからです。Ajax コードがどのブラウザーで実行されるかを判断する必要も、サーバーと通信を行うためのプロトコル・コードを作成する必要もありません。単純な Jaxer API を呼び出すことによって、最小限の手間で堅牢な Web アプリケーションを実現できます。さらに重要な点は、使用するコードすべてを組み込み JavaScript によって公開しなくても済むようになったことです。実際、Jaxer を使用してクライアント・コードをサーバー・コードに統一すれば、戦略的コードをファイアウォールの背後にしっかり隠しながらも、クライアントからは引き続きアクセスすることができます。
Jaxer を使用する Web ベースのアプリケーションをデプロイするには、その前にまず、Jaxer をお使いのマシンまたは開発環境にインストールしなければなりません。Jaxer の選択肢には、Microsoft Windows® 用、Mac OS X 用、Linux® 用の 3 つがあります。Jaxer インストールは、必要なものをすべて完備したスタンドアロンの Apache/Jaxer サーバーとなりますが、その一方、既存の Apache または Jetty 環境内のモジュールとしてインストールすることもできます。IIS についても、Aptana では近い将来サポートする計画を発表しています。
この記事の目的から、そして大抵の開発者は Windows でコードを作成してから Windows 環境または *NIX 環境 (UNIX® や Linux など) にデプロイすることから、ここではスタンドアロンの Windows バージョンをインストールすることにします。Windows でのインストール手順はとても簡単です。Aptana Jaxer ダウンロード・ページ (「このページへのリンクについては「参考文献」を参照) にアクセスして、Windows スタンドアロン・バージョンの圧縮 (.zip) ファイルをダウンロードしてください。この記事を執筆している時点での最新バージョンはビルド 0.9.7.2472 です。
ダウンロードした圧縮ファイルを解凍したら、Aptana Jaxer フォルダーをハード・ディスクにコピーします。私は C: ドライブに直接コピーしました。したがって私の場合、Jaxer のルート・フォルダーには C:\Aptana Jaxer でアクセスすることができます。
Aptana Jaxer フォルダーのなかには多数のファイルとフォルダーがあります。ルート・フォルダーに含まれているファイルは以下のとおりです。
- ConfigureFirewall.exe
- LICENSE.TXT
- README.TXT
- StartServers.bat
さらに以下のフォルダーも含まれています。
- Apache22
- data
- jaxer
- local_jaxer
- logs
- public
- tmp
サーバーを起動するのは、インストール手順よりさらに簡単です。StartServers.bat ファイルを実行するだけで、起動ウィンドウが表示されます (図 1 を参照)。
図 1. Jaxer 起動ウィンドウ
Jaxer 環境でアプリケーションを使い、またアプリケーションのテストを実行する間、このウィンドウは開いたままにしておいてください。Jaxer サーバーが正しく実行されていることをテストするためには、ブラウザーのウィンドウを開いて http://localhost:8081/aptana までナビゲートします。すると、ブラウザーに About Jaxer ページが表示されるはずです (図 2 を参照)。
図 2. About Jaxer ページ
<jaxer_install_dir>\jaxer\aptana\samples に置かれた Samples フォルダーには、他にも Jaxer ベースの Web アプリケーションが用意されています。表 1 に、そのうちのいくつかを抜粋して説明します。
表 1. Jaxer Samples フォルダー内に含まれているアプリケーション
| アプリケーション | 説明 |
|---|---|
| chat | ページ全体を更新せずにチャット・メッセージを送受信するデモ・アプリケーションです。 |
| csajax | Web アプリケーションの中で、JavaScript コードを使用するクライアントのブラウザーから別のドメインと通信しようとするときに一般に持ち上がってくる問題を、Ajax によって解決するアプリケーションです。ブラウザー・ベースのクライアントが Jaxer を使用してサーバーと通信し、その上でサーバーが別のドメインと通信できるようにするというこのアプリケーションは、本質的に、クロスサイトの問題に対するソリューションとなります。クロスサイトの問題についての詳細は、「参考文献」を参照してください。 |
| logging | サーバー・サイドのロギングをラップし、クライアント・サイドの JavaScript を使ってアクセスする方法を説明します。 |
| rss-sample | ページを分割して、その 1 つのセクションにニュース記事を一覧表示し、別のセクションには選択された記事を表示する方法のデモンストレーションを行うアプリケーションです。選択された記事は、ページ全体を更新することなくセクション内に表示されます。すべては、Ajax と Jaxer を使用して行われます。 |
| smtp-email | Jaxer SMTP (Simple Mail Transfer Protocol) オブジェクトを使って E メールを非同期で送信できるアプリケーションです。 |
| tasks | 非同期通信を使用して、単純な ToDo リストやタスク・リストの項目を追加、変更、削除できるアプリケーションです。 |
| wikilite | ユーザーが編集モードで単純なウィキのテキストを入力し、そのテキストを保存して後で表示できるようにするアプリケーションです。 |
これらのサンプルにアクセスするには、Samples and Tools リンクをクリックします (図 2 を参照)。この操作によって、Samples and Tools ページが表示されます (図 3 を参照)。
図 3. Samples and Tools ページ
記事ではこの後、tasks アプリケーションのサンプルを使用して Aptana Jaxer について詳しく学びます。
お気付きかもしれませんが、問題が発生したときに Jaxer と対話動作を行って問題を診断するための Web ツールや診断ツールもいくつか用意されています。例えば Server Diagnostics リンクをクリックすると、Jaxer Diagnostics ページが表示されます (図 4 を参照)。
図 4. Jaxer Diagnostics ページ
Jaxer ルート・フォルダーについて説明したときに、このフォルダー内にはいくつかのサブフォルダーがあると述べました。そのうちの 1 つに、public というフォルダーがあります。このフォルダーは、独自のコンテンツを提供するために使用することができます。ここにコンテンツを追加すると、ブラウザーのアドレス行に host:port アドレスを指定するだけで、そのコンテンツがブラウザーから呼び出されます。例えば http://localhost:8081/ と指定すると、このフォルダーに提供した index ファイルが表示されます。
さらに都合のよいことに、public フォルダー内に複数のプロジェクトを作成して、名前を基準に特定のプロジェクトをロードすることもできます。例えば my_project という名前のプロジェクトを作成したとすると、このフォルダーへの完全なパスは C:\<jaxer_root>\public\my_project となります。
それではここで、index.html という名前を付けた index ファイルを作成し、my_project フォルダー内にそのファイルを配置してください。Jaxer サーバーを使ってファイルをロードするには、フォルダーのパスをブラウザーに入力します。この例の場合に入力するパスは、http://localhost:8081/my_project です。このフォルダーやそのサブフォルダーには、任意の HTML、画像、JavaScript ファイル、CSS ファイルなどを配置することができます。
私の my_project フォルダーには、Aptana Web サイトに用意されたクイック・スタート・コードを引用して index.html ファイルを作成することにしました。このコード (リスト 1 に記載) は、サーバー・サイドの DOM、JavaScript コード、そしてコールバックを実例で説明しています。
リスト 1. Jaxer をテストするためのサンプル・コード
<html>
<head>
<title>Quick Jaxer Sample</title>
</head>
<body>
<h3>Quick Jaxer Sample</h3>
<p>This demonstrates server-side DOM, JavaScript and callbacks.</p>
<script runat="server-proxy">
document.write("This is Jaxer version " + Jaxer.buildNumber);
function getLatestVersion() {
var url = "http://update.aptana.com/update/jaxer/win32/version.txt";
try {
var versionString = Jaxer.Web.get(url);
}
catch (e) {
throw "Could not retrieve version number from " + url;
}
var matches = versionString.match(/\"([\.\d]+)\"/);
return (matches && matches.length > 1) ? matches[1] : "(unknown)";
}
</script>
<input type="button" value="Check Latest" onclick="alert('Latest version: '
+ getLatestVersion())">
</body>
</html>
|
このコードを実行すると、図 5 に示すページが生成されます。
図 5. my_project に使用したクイック・スタート・コード
ブラウザーに送信された実際の HTML ソース・コードを調べると、元の index.html コードとはかなり違っていることに気付くはずです。リスト 2 を見てください。
リスト 2. Jaxer によって生成されてブラウザーに返された HTML コード
<html><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<script src="\jaxer\framework\clientFramework_compressed.js?
version=0.9.7.2472"></script>
<script>Jaxer.Callback.pageSignature = -1837648436;
Jaxer.Callback.pageName = 'localhost:8081/my_project';
Jaxer.CALLBACK_URI = '/jaxer-server/callback';
Jaxer.ALERT_CALLBACK_ERRORS = true;</script>
<title>Quick Jaxer Sample</title>
</head><body>
<h3>Quick Jaxer Sample</h3>
<p>This demonstrates server-side DOM, JavaScript and callbacks.</p>
<script>
function getLatestVersion() {return Jaxer.remote("getLatestVersion", arguments);}
function getLatestVersionAsync(callback) {return Jaxer.remote(
"getLatestVersion", arguments, callback);}
</script>This is Jaxer version 0.9.7.2472
<input value="Check Latest" onclick=
"alert('Latest version: ' + getLatestVersion())" type="button">
</body></html>
|
元の index.html コードでは、外部 JavaScript ファイルを組み込む必要は一切なかったことに注意してください。次に元のコードの <script> ブロックでラップされた JavaScript セクションを見てみると、通常ブラウザーで実行するために作成する JavaScript コードと異なる点は 1 つしかありません。それは、元のコードでは server-proxy でコードを実行するように runat 属性で指定しているという点です。
Jaxer のアーキテクチャーを検討する前に、従来のアプリケーションのアーキテクチャーを検討してみましょう (図 6 を参照)。
図 6. 従来のアプリケーション・スタック
すべてのアプリケーション・スタックは、クライアントからサーバーへのリクエストによって動作を開始します。従来のアプリケーションでは、サーバー・サイドは 1 つ以上の技術を使ってリクエストを処理しますが、使用される技術には、PHP、Java コード、C#、Ruby On Rails などをはじめ、あらゆるスクリプト/オブジェクト技術が考えられます。サーバー・サイドはデータベースまたはファイルにアクセスしてデータを処理し、処理したデータをフォーマット設定してからブラウザーに返します。これらの技術は個別のコンポーネントであるため、接続コードによって 1 つにまとめなければなりません。
Web ベースのアプリケーションが Ajax を使用するとしたら、クライアントの要求を処理し、呼び出し/パラメーターをラップし、そしてリクエストとして送信するためのステップが必要になります。サーバー・サイドのコードは、リクエストをアンラップして呼び出し/パラメーターを判断し、それから呼び出しを実行して応答を受信し、今度はレスポンスとしてクライアントに返さなければなりません。さらに、レスポンスを受け取ったクライアントはレスポンスをアンラップしてから、やっと応答を処理することになります。これらのラップ/アンラップ操作に使用するのは JSON、実際のリクエスト/レスポンス/コールバックに使用するのは XMLHttpRequest です。このような従来のアプリケーションとは対照的に、Jaxer の場合のアプリケーション・スタックは図 7 のようになります。
図 7. Jaxer のアプリケーション・スタック
このように、Jaxer のアプリケーション・スタックは遥かに単純になっています。また、外部スクリプトの必要がないことにも注目してください。すべては実際の HTML ページ内で処理されるからです。JavaScript コードの目的はコードをどこで実行するかを指定することだけで、そのロケーションは runat 属性によって指定されます。
クライアント・コードがサーバー・サイドを呼び出す必要があるときには、Jaxer がブラウザーに返される HTML 内にシームレスに JavaScript ラッパー・コードを組み込みます。これが、リスト 2 のコードがリスト 1 の元のコードとは異なっていた理由です。
疑問に思っている方のために説明しておくと、Jaxer のコアは実際には C++ で作成されています。また、HTML、CSS、そして JavaScript コードの構文解析と API を提供するために、Jaxer のコアには Mozilla エンジンも統合されています。プログラマーの観点からすれば、このコードはサーバー・サイドの JavaScript コードとクライアント・サイドの Ajax を実現するためのフレームワークとして提供された、純粋な JavaScript コードです。
Jaxer は、以下の技術を必要とするアプリケーションの開発をサポートするためのサービスを提供します。
- Ajax
- クライアントまたはサーバーからのデータベース通信
- クライアント・サイドまたはサーバー・サイドのロギング
- セッションの操作
- クライアント・サイドまたはサーバー・サイドのネットワーク API 接続
- ファイル・オブジェクト
- その他いろいろ
さらに、Jaxer と従来の技術 (Java コードなど) を統合して、クロス・プラットフォーム問題の解決に役立てることもできます。
Jaxer アプリケーションの構築方法をわかりやすく説明するために、これから Jaxer に付属のサンプル・サイトの 1 つを使って実際の手順を説明していきます。ここで使用するのは tasks アプリケーションです。http://localhost:8081/aptana/samples/tasks を指定してこのアプリケーションにアクセスすると、図 8 のページが表示されます。このページは、すでにいくつかのタスクが追加された状態になっています。
図 8. tasks サンプルのメイン・ページ
この tasks アプリケーションは、ユーザーから見ると単純なものです。New ボックスに新しいタスクを入力し、add をクリックするだけで項目が追加されます。項目を削除するための操作は、削除対象の項目の隣にあるチェック・ボックスをクリックするだけです。
リスト 3 を見てください。ここに記載されているのは、tasks の HTML ページに組み込まれた JavaScript コードの一部です。
リスト 3. クライアントとサーバーの両方で実行される tasks の JavaScript コード
<script type="text/javascript" runat="both">
/*
* Easy access to a named element in the DOM
*/
function $(id)
{
return document.getElementById(id);
}
/*
*
*/
function addTaskToUI(description, id)
{
var newId = id || Math.ceil(1000000000 * Math.random());
var div = document.createElement("div");
div.id = "task_" + newId;
div.className = "task";
var checkbox = document.createElement("input");
checkbox.setAttribute("type", "checkbox");
checkbox.setAttribute("title", "done");
checkbox.setAttribute("id", "checkbox_" + newId);
Jaxer.setEvent(checkbox, "onclick", "completeTask(" + newId + ")");
div.appendChild(checkbox);
var input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("size", "60");
input.setAttribute("title", "description");
input.setAttribute("id", "input_" + newId);
input.value = description;
Jaxer.setEvent(input, "onchange",
"saveTaskInDB(" + newId + ", this.value)");
div.appendChild(input);
$("tasks").insertBefore(div, $("tasks").firstChild);
if (!Jaxer.isOnServer)
{
saveTaskInDB(newId, description);
}
}
</script>
|
まず、さまざまな JavaScript ブロックがあることに注意してください。最初のブロックの runat 属性は both に設定されています。これは、このブロック内のコードがクライアント・サイドとサーバー・サイドの両方に対して使用可能になることを意味します。リスト 3 に記載されている関数は、クライアント・サイドとサーバー・サイドの両方で実行されるその他の関数がアクセスできる一般的な機能を提供します。$ 関数は、指定された ID に基づいて要素を返すだけです。addTaskToUI は、createElement メソッドと insertBefore メソッドを使用してクライアント・サイドにタスクを指定してユーザー・インターフェースを作成します。
ここには Jaxer 固有の API に対する呼び出しは、ほとんどありません。ここにあるのは、入力とチェック・ボックスに接続されたイベントの定義、そして Jaxer.isOnServer プロパティーに対する論理比較だけです。このプロパティーは、JavaScript コードが現在サーバー・サイドで実行されている場合には true に設定されます。
Jaxer.setEvent は、クライアントからのサーバー呼び出しに使用される通信プロキシーを確立するために使用されます。これについては、この後の簡単な説明で明らかになるはずです。
JavaScript コードの次のセグメントは、サーバー上で実行されることになります。これは、リスト 4 の runat 属性に指定されている値を見ればわかります。
リスト 4. tasks のサーバー・サイドの JavaScript コード
<script type="text/javascript" runat="server">
/*
* The SQL to create the database table we'll use to store the tasks
*/
var sql = "CREATE TABLE IF NOT EXISTS tasks " +
"( id INTEGER NOT NULL" +
", description VARCHAR(255)" +
", created DATETIME NOT NULL" +
")";
// Execute the sql statement against the default Jaxer database
Jaxer.DB.execute(sql);
/*
* Set the 'onserverload' property to call our function
* once the page has been fully
* loaded server-side. We could have also set this attribute
* on the <body> tag of our
* page and had it call a function by name.
*/
window.onserverload = function()
{
var resultSet = Jaxer.DB.execute("SELECT * FROM tasks ORDER BY created");
for (var i=0; i<resultSet.rows.length; i++)
{
var task = resultSet.rows[i];
addTaskToUI(task.description, task.id);
}
}
/*
* Save a task directly into the database
*/
function saveTaskInDB(id, description)
{
var resultSet = Jaxer.DB.execute(
"SELECT * FROM tasks WHERE id = ?", [id]);
if (resultSet.rows.length > 0) // task already exists
{
Jaxer.DB.execute("UPDATE tasks SET description = ? WHERE id = ?",
[description, id]);
}
else // insert new task
{
Jaxer.DB.execute("INSERT INTO tasks (id, description, created) " +
"VALUES (?, ?, ?)",
[id, description, new Date()]);
}
}
// Because we want this function callable from the client, we set its proxy
// value to true
saveTaskInDB.proxy = true;
/*
* Delete a task from the database
*/
function deleteSavedTask(id)
{
Jaxer.DB.execute("DELETE FROM tasks WHERE id = ?", [id]);
}
// Because we want this function callable from the client, we set its proxy
// value to true
deleteSavedTask.proxy = true;</script>
|
このサンプル・コードを実行したら、Jaxer によって生成されたソース・コードをブラウザーで確認してください。するとリスト 4 のコードがなくなっていることに気付くはずです。都合のよいことに、リスト 4 で定義された関数は実際の関数の単純なシェルに変換され、代わって単純な Jaxer リモーティングが作成されています。
リスト 4 には、興味深い JavaScript コードがあります。これは完全な JavaScript コードですが、JavaScript コードをサーバー・サイドで定義して実行できることによってもたらされる威力を見逃さないでください。このセグメントの最初の部分では、SQL (Structured Query Language) テーブルが作成されます (SQL テーブルが存在しない場合)。続いて、onload のようなイベントが設定されますが、これはブラウザー・サイドではなくサーバー・サイドでのイベントです。onserverload に定義されて割り当てられている関数は、Jaxer がファイル全体をロードして、すべてのグローバル・サーバー関数と変数を確認した後に呼び出されます。
この例で定義されるメソッドには、saveTaskInDB と deleteSavedTask があります。関数をクライアント・サイドから呼び出せるようにするには、プロキシーを定義しなければなりません。プロキシーは、関数の proxy プロパティーを true に設定することによって定義されます。
Jaxer がファイルのロードを完了すると、onserverload に割り当てられた機能が実行されます。この例の場合には、この関数が SQL 呼び出しを実行してデータベースから現在のタスクを取得します。関数は続いて、取得したすべてのタスクを繰り返し処理し、addTaskToUI メソッドを呼び出します。前に、このメソッドはチェック・ボックスと入力ボックスを HTML 文書に挿入すると説明しましたが、この例では、サーバーがこれらのチェック・ボックスと入力ボックスを実際に文書に組み込むということになります。サーバー・サイドで実行されるこのコードが addTaskToUI 内で唯一実行しないのは、isOnServer が true であるか、false であるかを確認するために論理チェック内にラップされたコードです。コードのこの部分は、クライアント・サイドがタスクをデータベースに追加する際にサーバーに対してリモート呼び出しを行うためだけに必要だからです。
リスト 4 では、関数全体にわたって Jaxer 呼び出しが散りばめられています。これは主に、データベースに対する処理をするためです。見てのとおり、外部コンポーネントやファサード、そして DAO (Data Access Object) はまるで必要ありません。このリストでは単純な Jaxer API 呼び出しによって SQL 関数を実行しています。念頭に置いておく点として、使用しているデータベースの実際の詳細に、より対応していると思われる具体的な JavaScript コンポーネントでこれらの単純な呼び出しをラップして、実質的に SQL データベースのファサードを提供するという方法を採るのでも一向に構いません。
tasks サンプルの残りの JavaScript コードは、フォーム・コントロールの操作によって発生するイベントを処理するだけに過ぎません (リスト 5 を参照)。
リスト 5. tasks の残りの JavaScript コード (クライアント・サイドでのみ実行)
<script type="text/javascript">
/*
* This client function sets a task as completed and
* calls the server-side function
* 'deleteSavedTask' to remove it from the database
*/
function completeTask(taskId)
{
var div = $("task_" + taskId);
div.parentNode.removeChild(div);
deleteSavedTask(taskId);
}
/*
* Create a new task and add it to the user interface
*/
function newTask()
{
var description = $('txt_new').value;
if (description != '')
{
addTaskToUI(description);
$('txt_new').value = '';
}
}
/*
* Create a new task if the enter key was hit
*/
function newKeyDown(evt)
{
if (evt.keyCode == 13)
{
newTask();
return false;
}
}
</script>
|
上記のコードは昔ながらの単純な JavaScript クライアント・コードで、クライアント・サイドでのみ実行されます。ただし、これらの関数は、サーバー・サイドの JavaScript コードにラップされた関数を呼び出すことに注意してください。関数のプロキシー・メソッドは HTML によって生成されたコードが提供し、これらのプロキシー・メソッドがサーバー・サイドのリモート・メソッドを呼び出します。サーバー・サイドのメソッドの実際の関数やコードがクライアント・サイドに公開されることは決してありません。
この初期段階ですでに Jaxer が示している素晴らしい可能性を納得していただけたでしょうか。まさに Jaxer は初期の段階にあり、おそらくこれから完成していく部分もありますが、前途有望であることは確かです。結局のところ、サーバー・サイドで JavaScript コードを実行し、クライアント・サイドで Ajax を実行できること、そして既存の成熟した技術の多くをベースにしているという事実だけをとっても Jaxer は大きなプラスです。Jaxer はセットアップするのが簡単で、既存の Web サーバー環境と併せて実行しても、ほとんど、あるいはまったく問題ありません。実際、私は現在 Apache と一緒に PHP、MySQL などを実行している Windows マシンにセットアップしていますが、スムーズに動作しています。他の Apache インスタンスを停止させたことは一度もなく、ポート 8081 でも Jaxer インスタンスと問題なく通信できました。たった 1 つの例外として、現在ポート 8081 を他の目的 (Tomcat など) で使用している場合には問題が起こる可能性があります。
学ぶために
- ウィキペディアでクロスサイト・スクリプティングについて詳しく学んでください。
- Jaxer のJavaScript フレームワークを構成する個々の部分に対処する詳細なフォローアップ項目については、本著者のブログおよび Web サイトを参照してください。
- オープンソース技術を使用して開発し、IBM の製品と併用するときに役立つ広範囲のハウツー情報、ツール、およびプロジェクト・アップデートについては、developerWorks Open source ゾーンを参照してください。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- technology bookstore で、この記事で取り上げた技術やその他の技術に関する本を探してください。
製品や技術を入手するために
- Aptana Jaxer ダウンロード・ページにアクセスして、お使いのオペレーティング・システムに合った Jaxer のバージョンをダウンロードしてください。
- IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。
議論するために
- developerWorks blogs から developerWorks コミュニティーに加わってください。

Ken Ramirez は、Axsys Hosting を介してホスティングおよびカスタム Web サイト開発を提供する Axsys Technology Group の創立者です。また、低コストの Web サイト・ソリューションを求める小中企業の経営者とも BuildMySiteTonight.com Web サイトをとおして協力しています。彼の会社では、PHP、MySql、Linux、XHTML/CSS、Adobe Flash、E-commerce ソリューション、そしてコンテンツ・マネージメント・ソリューションを専門としています。彼の連絡先は、AxsysHosting.BlogSpot.com です。