AJAJA: 勉強材料としての可能性とSQLiteを使ったちょっとした実験

AJAJA: Asynchronous JavaScript and JavaScript/ASP

AJAJA は「ブラウザだけでなくサーバサイドでも JavaScript を使おう!」というプロジェクトです。

  • できること

- JavaScript を埋め込んだ ASP ファイルを処理する
- JavaScript から SQLite などのシステムライブラリを呼び出す
- JSAN のライブラリをサーバサイドで利用する
- Server Side JavaScript の実行処理系 asp_js を提供しています

  • asp_js の特徴

- IISASP/JavaScirpt の記法をそのまま処理することができます
- Mozilla の C の JavaScript 処理系 SpiderMonkey を組み込んでいます
- SQLite を標準サポート、拡張も容易です

AJAJA - Trac

AJAJA、おもしろいです。久しぶりにワクワクするソフトウェアが出た感じがします。Pugs 6.0.0のコードを読んでいた頃と同じような感覚です。

そこで今回は、

  • 非常に良い勉強材料になる可能性が高いAJAJA
  • 面白かったコード
  • AJAJASQLiteを使ったデータベースプログラミングの実験

について書いてみたいと思います。

外部コンポーネントとの連携には勉強材料がいっぱい

普通、JavaScriptと言えばクライアントサイドで動作させますが、このAJAJAではサーバーサイドでJavaScriptのコードが走ります。

ここで、ふと疑問に思いました。

「ブラウザを経由しないで、AJAJAはどうやってJavaScriptのコードを実行しているのだろう?」

その答えは、SpiderMonkeyでした。SpiderMonkeyMozillaのCによるJavaScriptの実行処理系で、FireFoxなどで使われているコンポーネントの1つのようです。

SpiderMonkeyという実行処理系とうまくリンクさせて、JavaScriptが走るようにしている所が凄いなぁと思います。すでにある外部コンポーネントとの連携のやり方を勉強するのに、AJAJAは良い勉強材料になりそうです。(C言語のコードを読む練習をしよう)

外部コンポーネントと言えば、JSANのライブラリやSQLiteもそうです。これらのコンポーネントについても、どのようにしてAJAJAの核のコードとバインディングされているのかを勉強すれば、なかなか面白いのでは?と思っています。

AJAJAが誕生して、まだ日が浅いので、ソフトウェアの複雑さはそれほど高くありません。ですので、勉強をするには今がチャンスだと思います。勉強をするには、今くらいがちょうど良い複雑さだと直感的に思っています。(Pugs 6.0.0がそうであったように)

面白かったコード

それで、ちょっとだけコードを読んでみました。コードを読んで、特に「あっ」と思ったコードは以下の2つです。(今の所)

SpiderMonkeyのコードへのパッチ

今は、全然意味がわかっていませんが、SpiderMonkeyのコードへのパッチ(ajaja-build/ajaja/js.patch)の書き方が1つ勉強になりました。それは、プリプロセッサの命令(#define、#ifdef、#endif)を使って、パッチを当てた部分を明確化するというテクニックです。

以下がそのパッチの一部です。

[...]
===================================================================
RCS file: /cvsroot/mozilla/js/src/js.c,v
retrieving revision 3.118
diff -u -r3.118 js.c
--- js.c    26 Jun 2006 21:22:12 -0000  3.118
+++ js.c    11 Jul 2006 09:22:49 -0000
@@ -92,6 +92,14 @@
 #include <io.h>     /* for isatty() */
 #endif

+#define ASP_JS 1
+
+#ifdef ASP_JS
+#define JSPATH "/usr/lib/js/0.2"
+
+static int asp_js = 0;
+#endif
+
 #define EXITCODE_RUNTIME_ERROR 3
 #define EXITCODE_FILE_NOT_FOUND 4

@@ -355,6 +363,11 @@
         return 1;
     }

+#ifdef ASP_JS
+    if (asp_js && i > 0)
+        i--;
+#endif
+
     length = argc - i;
     for (j = 0; j < length; j++) {
         JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
@@ -476,8 +489,16 @@
         }
     }

+#ifdef ASP_JS
+    if (asp_js) {
+        char buff[FILENAME_MAX];
+        sprintf(buff, "%s/asp_js", JSPATH);
+        Process(cx, obj, buff, JS_FALSE);
+    } else
+#endif
     if (filename || isInteractive)
         Process(cx, obj, filename, forceTTY);
[...]

パッチを良く見ると、追加分のコードは、「#ifdef ASP_JS ... #endif」でラッピングされています。こうしておくと、パッチを当てて変更された部分が強調されて、パッチを当てたソースを読む時に、オリジナルのコードとそうでないコードをはっきり区別できるようになります。こんなちょっとした工夫ですが、僕にとっては凄い勉強になるコードでした。

(僕は、C言語で書かれたソフトウェアのコードを読んでいると、つい、プリプロセッサでどういった面白いテクニックが使われているのか注目してしまいます。プリプロセッサのテクニックを見れば、だいたいその人のC言語の運用スキルが見えてくる気がするからです。そう考えるようになったのは、昔、Linuxカーネルソースコードを眺めていた時に、プリプロセッサによる高度なテクニックを見て感動したためです。)

ビルドスクリプト

何の変哲もないシェルスクリプトですが、ビルドするために、SubversionCVSリポジトリから、それぞれAJAJASpiderMonkeyの最新のコードをチェックアウトしている所が面白いです。ダイナミックな感じが新鮮です。普通のUNIX系のソフトウェアの「tarballを展開してconfigureしてmakeするというテンポ」じゃないのが良いです。少なくとも僕にとっては新鮮で、勉強になりました。

#!/bin/sh

# Download AJAJA
echo "checking out ajaja..."
svn co svn://ajaja.alphageek.jp/trunk/ajaja || exit 1

# Download SpiderMonkey
echo "checking out js..."
cvs -d :pserver:anonymous:anonymous@cvs-mirror.mozilla.org:/cvsroot \
    co mozilla/js/src || exit 1

# Patch SpiderMonkey
(cd mozilla/js/src && patch < ../../../ajaja/js.patch)

# configure
cd ajaja
./buildconf || exit 1
make update || exit 1

# make
make
  • 追記: 2006/07/21

このビルドスクリプトのコードは、rev #28で大きく変更が加えられました。

SQLiteを使ったデータベースプログラミングの実験

Cybozu Labsの竹迫さんのPowerPointにあった掲示板のコードを参考にしながら、ちょっとしたコードを書いてみました。

以下は、実行される毎に、カウント値をインクリメントするカウンターのプログラムです。(かなり適当に書いたコードなので、排他処理はしていません)

% vim counter.js
use('SQLite');
use('System');

var DB_FILE = "counter.db"

function executeQuery(query)
{
    db = new SQLite(DB_FILE);
    db.query(query);
    db.close();
}

if (arguments[0] == 'init') {
    executeQuery("DROP TABLE IF EXISTS counter;");
    executeQuery("CREATE TABLE counter (counter INTEGER NOT NULL);");
    executeQuery("INSERT INTO counter (counter) VALUES (0);");
    System.puts("Database initialized\n");
    System.exit();
}

var db = new SQLite(DB_FILE);
if ((result = db.query("SELECT counter FROM counter")) != null) {
    counter = result.fetch()[0];
    System.puts("counter = " + counter + "\n");

    db.query("UPDATE counter SET counter = " + (counter + 1));
}
db.close();

このコードを実行すると、実行する毎にカウンターの値がインクリメントされていくことが確認できます。こんなJavaScriptのコードが(データベースにアクセスしている!)、ちゃんと走るのを見て、ちょっと感動しました。

% ssjs counter.js init
Database initialized
% ssjs counter.js
counter = 0
% ssjs counter.js
counter = 1
% ssjs counter.js
counter = 2

今回は、AJAJAが勉強材料になるということを強調しましたが、もちろん、これからの実用化も期待しています。どこまで面白いソフトウェアに発展するのか楽しみです。