-Tapestryサービス(4)

サービスコンテキストとサービスパラメータを利用して、画面遷移間の情報送信がカスタマイズできることを説明しました。今日はケーススタディとして、サービスパラメータ付のPageLink/PageServiceを作ってみることにしましょう。同時に、Tapestryのページの状態保全についての考察も行っていきます。まず作成するのは、PageServiceのパラメータ付サービスである、ValuePageServiceと、そのサービスへのリンクをレンダリングするValuePageLinkコンポーネントです。実装自体はシンプルな内容です。サービスを作成するのに、AbstractServiceを継承すると、サービス実装に有用なユーティリティメソッドが用意されているので便利です。

サービスの実装-ValuePageService
package sample.valuepagelink;
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IPage;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.AbstractService;
import org.apache.tapestry.engine.IEngineServiceView;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.request.ResponseOutputStream;
public class ValuePageService extends AbstractService {
  public static final String SERVICE_NAME = "valuePage";
  public String getName() {
    return SERVICE_NAME;
  }
  public ILink getLink(IRequestCycle cycle, IComponent component, Object parameters) {
    String context = new String { (String)parameters[0], (String)parameters[1] };
    Object values = new Object { parameters[2] };
    return constructLink(cycle, SERVICE_NAME, context, values, true);
  }
  public void service(IEngineServiceView engine, IRequestCycle cycle,
      ResponseOutputStream output) throws ServletException, IOException {
    String context = getServiceContext(cycle.getRequestContext());
    Object[] parameters = getParameters(cycle);
    cycle.activate(context[0]);
    IPage page = cycle.getPage(context[0]);
    setPropertyValue(page, context[1], parameters[0]);
    engine.renderResponse(cycle, output);
  }
  private void setPropertyValue(IPage page, String name, Object value) {
    try {
      PropertyUtils.setProperty(page, name, value);
    } catch (Exception e) {
      throw new ServletException(e);
    }
  }
}

HTMLリンクが書かれるページにてgetLink()が用いられ、HTMLリンクのクリックによるリクエストに対応するのがservice()です。getLink()は以下のコンポーネントが描画されるときに用いられます。

サービスへのリンクコンポーネントの実装-valuePageLink
package sample.valuepagelink;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.link.AbstractLinkComponent;
public abstract class ValuePageLink extends AbstractLinkComponent {
  public abstract String getTargetPage();
  public abstract String getPropertyName();
  public abstract Object getPropertyValue();
  public ILink getLink(IRequestCycle cycle) {
    Object[] parameter = new Object[3];
    parameter[0] = getTargetPage();
    parameter[1] = getPropertyName();
    parameter[2] = getPropertyValue();
    return getLink(cycle, ValuePageService.SERVICE_NAME, parameter);
  }
}

リンクコンポーネントはその中核の内容をサービスに委譲していますのでとても簡素なつくりとなります。こちらも、AbstractLinkComponentを継承することによって、リンク生成をサービス側に委譲するgetLink(IRequestCycle,String,Object[])メソッドが利用できます。

コンポーネントスペックXML-ValuePageLink.jwc
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE component-specification
      PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
      "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
<component-specification
    class="sample.valuepagelink.ValuePageLink"
    allow-body="yes" allow-informal-parameters="yes">
  <parameter name="page" type="java.lang.String" required="yes"
    property-name="targetPage" direction="in"/>
  <parameter name="name" type="java.lang.String" required="yes" 
    property-name="propertyName" direction="in"/>
  <parameter name="value" type="java.lang.Object" required="yes" 
    property-name="propertyValue" direction="in"/>
  <parameter name="disabled" type="boolean" direction="in"/>
  <parameter name="anchor" type="java.lang.String" direction="in"/>
  <parameter name="renderer" 
    type="org.apache.tapestry.link.ILinkRenderer" direction="in"/>
  <reserved-parameter name="href"/>
</component-specification>

さらには、アプリケーションスペックXMLにサービスを登録します。

各アプリケーションスペックXML(.application)に記述する内容
<service name="valuePage" class="sample.valuepagelink.ValuePageService"/>

この、<service>エレメントのname属性には、リンクやサービスで用いている文字列を登録します。すなわち、ValuePageService.SERVICE_NAMEの値、「valuePage」となります。では、続いてこのサービスとコンポーネントを用いたサンプルアプリケーションを示します。