-Tapestryサービス(1)

Tapestryにとって、サービス(IEngineservice)は個別の動きを司ります。エンジン(IEngine)がすべてのリクエストを管理する一方で、サービスがHTMLクリックイベントのハンドラやページの遷移を行うのです。イベントハンドラはDirectService、ページ遷移はPageService、デフォルトではHomeServiceなどと複数種類のサービスが利用されています。このサービスのエンジンによる選択的な切り替えは、URLによって行われています。

http://localhost:8080/app?service=page/SomePageName

ページリンクのURLを見てみると、上記のようなURLになっています。サーバー、サーブレットを示す部位を除くと以下のようになります。

service=page/SomepageName

このHTTPのリクエストパラメータ「service」がどのサービスを用いるかを示す値となります。ここでは「page/SomePageName」と指定されています。スラッシュ「/」で区切られた文字列の一番初めの値がサービス名、そしてそれ以外をTapestryではサービスコンテキスト(Service Context)と呼んでいます。サービスコンテキストはサービスの実装ごとに自由な内容をとりますが、コンテキストのノードの区切りはスラッシュで行われます。例では、「page」がサービス名で「SomePageName」が唯一のサービスコンテキストノードです。
サービス名は各アプリケーションのアプリケーションスペックXML(.application拡張子)およびライブラリスペックXML(.library拡張子)に記述される<service>エレメントによって名前の解決が行われます。<service>エレメントはname属性とclass属性を持ち、それぞれサービス名とサービスの実装クラスを定義します。Tapestryの基本機能は、org.apache.tapestryにおかれたFramework.libraryで定義されています。このファイルに「page」が「PageService」であることが以下の記述でなされています。

<service name="page" class="org.apache.tapestry.engine.PageService"/>

この定義に従って、リクエスト時にサービスが見つけられ、サービスにサービスコンテキストが渡されます。PageServiceはシンプルな実装です。

public void service(IEngineServiceView engine, IRequestCycle cycle,
    ResponseOutputStream output) throws ServletException, IOException
{
    RequestContext context = cycle.getRequestContext();
    String[] serviceContext = getServiceContext(context);
    if (Tapestry.size(serviceContext) != 1)
        throw new ApplicationRuntimeException(
            Tapestry.format("service-single-parameter", Tapestry.PAGE_SERVICE));
    String pageName = serviceContext[0];
    IPage page = cycle.getPage(pageName);
    cycle.activate(page);
    engine.renderResponse(cycle, output);
}

これがPageServiceリクエスト時挙動の全実装です。唯一のサービスコンテキストを取得してページ名と解釈し、そのページ名で、IRequestCycle#activate()を呼び出します。その後にIEngine#renderResponse()です。このrenderresponse()ではじめて出てくるResponseOutputStreamは、Tapestryが提供するjavax.servlet.http.HttpServletResponseのラッパークラスです。
サービスへの入口がURLの記述であることは説明しましたが、そのURLはTapestryが生成したHTMLページにURLリンクとして記述されます。すなわち、<a>タグのhref属性や<form>タグのaction属性などです。この属性値(サービスに対するURL)もサービスが生成します。(つづく)