-サービスパラメータ(1)

サービスパラメータは、とても強力な仕組みです。HTTPリクエストパラメータに似て、URL中に埋め込まれる文字列を介してクライアントとサーバーで情報をやり取りする機能ですが、HTTPリクエストパラメータが受け渡しできる情報が文字列のみであるのに対して、サービスパラメータはオブジェクトを交換できます。
たとえば以下のようなページがあったとします。

<page-specification class="sample.serviceparam.Home">
  <component id="direct" type="DirectLink">
    <binding name="listener" expression="listeners.click"/>
    <binding name="parameters" expression="sparam"/>
  </component>
</page-specification>

この、DirectLinkコンポーネントに設定している、"parameters"プロパティはサービスパラメータが利用されています。このプロパティはObject型ですが、基本的にList型もしくはObject配列が入ってくることを想定して作られています。サービスパラメータはObject配列を取り扱うので、DirectLinkコンポーネント内部でObjrctもしくはListの場合は、Object[]に変換して内部処理に渡しています。
対応するHTMLは以下のとおりです。

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <a href="#" jwcid="direct">click</a>
  </body>
</html>

シンプルにリンクが一つあるだけです。Javaのページオブジェクトは以下のとおりです。

public class Home extends BasePage {
  public Object getSparam() {
    Object ret = new Object[2];
    ret[0] = new Integer(999);
    Person person = new Person();
    person.setName("masataka");
    person.setAge(31);
    ret[1] = person;
    return ret;
  }
  public void click(IRequestCycle cycle) {
    Object[] params = cycle.getServiceParameters();
    int value = *1;
    System.out.println("[1].age=" + person.getAge()); 
  }
}

getSparam()では、以下のシンプルなBeanを使ってます。

public class Person implements Serializable {
  private String name;
  private int age;
  public int getAge() {
    return age;
  }
  public String getName() {
    return name;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public void setName(String name) {
    this.name = name ;
  }
}

この出力ページソースは以下のとおりです。

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <a href="(URL+シリアライズされたパラメータ文字列。長いので後述)">click</a>
  </body>
</html>

URL+シリアライズされたパラメータ文字列は以下のとおりです。

/app?service=direct/0/Home/direct&sp=999&sp=OH4sIAAAAAAAAAFvzloG1uIhBpDgxtyAnVa84E0wFpBYV5-cp3LoveoyjQ4CJgcmTgTkxPdWHgSUvMTe1hEHIJyuxLFE_JzEvXT-4pCgzL926ooCBgUG-hIEjN7E4sSQxOxEAnKgp81oAAAA.

見事に、IntegerとPersonがURLの一部になっています。「sp=」が二度URL中に出現していることに注意してみてください。一つ目の「sp=」に続く「999」はIntegerの値、二つ目の「sp=」の後に続くのはPersonオブジェクトのシリアライズ結果です。このように、サービスパラメータはObject配列を文字列化してリンクURLに埋め込む機能を提供しています。クリック後のサーバーの受け取りは文字列からObject配列に自動的に戻され、IRequestCycle#getServiceParameters()によって取得することができます。
この仕組みは、URLに情報をエンコードしてしまうので、完全にServletセッションを使わないで、Servletセッションと同様の機能を提供するものです。既存のコンポーネントではただそれまでの内容ですが、この機能は独自にサービスを実装する場合に活用することができます。(つづく)

*1:Integer)params[0]).intValue(); Person person = (Person)params[1]; System.out.println("[0]=" + value); System.out.println("[1].name=" + person.getName(

-独自の例外ページ

Tapestryではアプリケーション中で例外が発生したまま、トラップされないと、エラー情報を表示するページが出ます。これは、ExceptionDisplayというコンポーネントを用いた、「Exception」という名前のページが表示されます。この名前は予約された名前で、起源はAbstractEngine#activateExceptionPage()に見ることができます。
このエラー情報を見ることができるExceptionページは開発およびテスト時には有効ですが、リリース前には独自の飾ったエラーページにしたいものです。このページに処理が落ちるのはバグなのですが、例外発生時にユーザーにこの画面を見せることはありません。また、場合によってはこのページに処理が落ちたときに特別にログを取ったり、障害情報としてシステム管理者にメール通知したりする要件も考えられます。
独自の例外ページを作成するのは以下の手順で行います。

  1. アプリケーションスペックXML(.applicationファイル)に、name属性が"Exception"であるpageエレメントにより、"Exception"という名前でページを登録する。
  2. Exception.htmlとException.pageと、ページクラスを作るなどして、独自例外ページを用意する。
  3. ページクラスに、setException(Throwable t)を実装するなどして、exceptionプロパティを作る。TapestryはこのプロパティのSetterがあるものとして、例外オブジェクトをセットしにきます。

WEBブラウザのBackボタンを押して戻ったとき、アプリケーションの側で例外が発生してしまったときにはStaleLinkページが表示されます。こちらは、以下のようにカスタマイズします。

  1. 同様に、"StaleLink"という名前でページ作成。
  2. ページを作る。
  3. ページにmessageプロパティを作る。

セッション切れの際はStaleSessionというページがTapestryに用意されています。これは以下のように入れ替えます。

  1. 同様に、"StaleSession"という名前でページ作成。
  2. ページを作る。

ExceptionおよびStaleLink、StaleSessionは、TapestryのJARファイル中のorg.apache.tapestryパッケージに配置されている、Framework.libraryに定義されているページです。ユーザーアプリケーションで同一名を設定すると、Tapestryエンジンはページを探すのに、アプリケーション設定を優先して検索するためにきちんと独自ページのほうが検出されます。