Lisplets: Lisp と Java Servlets のギャップを埋める

Lisplets: Lisp と Java Servlets のギャップを埋める

Rich Hickey が作成したライブラリ Lisplets を探求し、Lisp と Scheme の開発者が s-expression 通信を通じて Java の堅牢なウェブインフラストラクチャを活用できるようにするものです.

Lisplets: Lisp と Java Servlets のギャップを埋める

2000年代初頭、ウェブアプリケーションを構築したい Lisp 開発者にとっての課題は、ホイールを再発明する(独自の HTTP サーバや SSL ハンドラを書く)か、言語の柔軟性を犠牲にするかの選択が多くありました。そこで登場したのが Lisplets です。これは Rich Hickey が 2004 年に作成したプロジェクトで、Java Servlets への Lisp フレンドリーなインターフェースを提供することを目的としています。

Lisplets はブリッジとして機能し、開発者は Java ベースのウェブ環境(Tomcat、Jetty、Resin など)の産業レベルの機能を利用しつつ、実際のアプリケーションロジックを Common Lisp や Scheme で記述できます。ウェブの「配管」作業を Java に委ねることで、Lisp 開発者はスケーラビリティやセキュリティを犠牲にすることなく、言語の表現力に集中できます。

Lisplets の仕組み

Lisplets の核心は、HttpServlet を実装した単一の Java クラスで構成されています。リクエストを内部で処理する代わりに、Lisplet サーブレットはリクエストを転送し、TCP ソケット上の s-expression を使用してレスポンスを取得します。

リクエストフロー

  1. Interception: Java サーブレットコンテナが HTTP リクエストを受け取ります。
  2. Packaging: Lisplet サーブレットがリクエストヘッダー、パラメータ、クッキー、セッションデータ、アプリケーション状態、ユーザー情報を単一の s-expression にパッケージ化します。
  3. Transmission: この s-expression が TCP ソケットを介して待ち受けている Lisp プロセスに送信されます。
  4. Processing: Lisp プロセスは標準の read 関数で s-expression を読み取り、ロジックを処理し、レスポンスを生成します。
  5. Return: Lisp プロセスはステータス、ヘッダー、セッション状態を含む s-expression を返し、その後に生のドキュメントコンテンツを送ります。

Lisp 開発者への主な利点

Java サーブレットコンテナをフロントエンドとして利用することで、Lisplets はいくつかの即時的な利点を提供します。

  • Infrastructure for Free: 開発者は Java コードを一行も書かずに、プロフェッショナルな HTTP サーバ実装、SSL サポート、業界標準ウェブサーバとの統合にアクセスできます。
  • Enterprise Features: Lisplet API は Servlet API の全機能を反映しており、セッション管理、認証、アクセス制御、ユーザーロール、宣言的設定が含まれます。
  • Hybrid Applications: 標準的な Java ウェブアプリケーション内で動作するため、Lisp が生成したコンテンツは Java Server Pages (JSP) や他の Java Servlets と同一アプリケーション内で共存できます。
  • Flexible Deployment: 任意のサーブレットコンテナで動作するため、開発者はコスト、組み込み可能性、プラットフォームサポートに基づいて環境を選択できます。

技術的詳細: API

web.xml による設定

Lisplets は標準の web.xml ファイルで設定します。lisp-hostlisp-port は Lisp プロセスの位置を特定するために必須ですが、細かい調整が可能なオプションパラメータもいくつかあります。

  • lisp-tag-prefix: 開発者がタグの前に文字列(例: :)を付加でき、Common Lisp のキーワードとして扱えるようにします。
  • lisp-create-session: セッションが存在しない場合に自動的に作成すべきかを決定するブール値です。
  • lisp-roles: カンマ区切りのリストで、特定ロールへのユーザー所属を問い合わせる際に使用し、Lisp のロジックと Java の認証システムを統合します。

リクエストとレスポンスのフォーマット

リクエストはリストのリストとして単一のリストで送信されます。各サブリストはタグ(例: :method:uri:headers:session)で始まります。この構造により、Lisp プロセスは標準的なリスト処理手法でリクエストを容易に解析できます。

レスポンスも同様の構造です。Lisp プロセスは少なくとも空リスト () を Java 側に送信しなければなりません。レスポンスの s-expression は以下を制御できます:

  • HTTP Status: ステータス(例: 200 OK)を設定したり、リダイレクトをトリガーしたりします。
  • Cookies: 名前、値、ドメイン、パスを定義します。
  • Session/Context Attributes: Java 側の動的属性を更新し、サーブレットコンテナが永続化します。
  • Logging: 文字列を直接 ServletContext のログに送ります。

実装例

Rich Hickey は Xanalys(LispWorks)向けに書かれたサンプルサーバを提供し、統合のシンプルさを示しました。サーバはポートで待ち受け、ストリームから s-expression を読み取り、リクエストをブラウザにレスポンスボディとしてエコーします。

(defun handle-lisplet-on-stream (stream)
  (unwind-protect
      (let ((req (read stream)))
        (format stream "~S"
                `((:status 200)
                  (:headers (:content-type "text/plain"))
                  (:log "Hello from Lisp")))
        (pprint req stream)
        (force-output stream)
        (close stream))))

まとめ

Lisplets は古典的な問題に対するエレガントな解決策です。ロジックには高水準で柔軟な言語を使用し、インフラには安定かつ高性能なエコシステムを活用する方法です。プロジェクトは 2004 年に遡りますが、シンプルで言語に依存しない通信フォーマット(s-expression)を用いて二つの異なるランタイム環境を橋渡しするという哲学は、時代を超えたアーキテクチャパターンとして残っています。

Sources