トップ 一覧 ヘルプ RSS ログイン

CayenneIntegrationの変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!!!Cayenneとの連携
Clickでは、[Apache Cayenne|http://cayenne.apache.org/]との連携のために、Click Extrasにおいて以下のクラスを提供しています。

*[CayenneForm|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/CayenneForm.html] - Cayenneのエンティティオブジェクトに編集フォームを提供するためのFormコントロールの拡張。
*[CayenneTemplate|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/CayenneTemplate.html] - Spring DAO テンプレートパターンによる、拡張のための基底DAO/サービスクラス。
*[DataContextFilter|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/DataContextFilter.html] - リクエストにDataContextオブジェクトをバインドするサーブレットフィルター。
*[PropertySelect|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/PropertySelect.html] - DataObjectのプロパティを選択するコントロール(<select></select>)。
*[QuerySelect|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/QuerySelect.html] - CayenneのQueryの結果を選択するコントロール(<select></select>)。
*[TabbedCayenneForm|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/TabbedCayenneForm.html] - CayenneFormのタブ版。

現在Cayenneを利用したコントロールは、数値型のひとつのカラムからなるプライマリーキーを持っているDataObjectしか扱えないことに注意してください。

それでは利用方法を順番に見て行きましょう。

!!DataContextFilterの設定
DataContextFilterは、リクエストにDataContextオブジェクトをバインドするサーブレットフィルターです。デフォルトではクラスパスのルートに存在するcayenneの設定ファイル(cayenne.xml他)を読み込みます。このフィルターは、セッションスコープにバインドされたコミットされていない変更を自動的にロールバックします。もしくは、それぞれのリクエストの最後で、コミットされていない変更を自動的にロールバックします。

web.xmlで以下のように設定し、ClickServletにフィルタを適用します。

{{code xml
<web-app>
 
  <filter>
    <filter-name>data-context-filter</filter-name>
    <filter-class>net.sf.click.extras.cayenne.DataContextFilter</filter-class>
  </filter>
 
  <filter-mapping>
    <filter-name>data-context-filter</filter-name>
    <servlet-name>click-servlet</servlet-name>
  </filter-mapping>
 
  <servlet>
    <servlet-name>click-servlet</servlet-name>
    ..
 
</web-app> 
}}

上記の設定では、データベースの変更をこのアプリケーションしかしないことを前提にしています。

対象となるデータベースへの変更が、複数のアプリケーションから行われる場合には下記のように記述しますます。

{{code xml
<web-app>
 
  <filter>
    <filter-name>data-context-filter</filter-name>
    <filter-class>net.sf.click.extras.cayenne.DataContextFilter</filter-class>
    <init-param>
      <param-name>session-scope</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>shared-cache</param-name>
      <param-value>false</param-value>
    </init-param>
  </filter>
 
  <filter-mapping>
    <filter-name>data-context-filter</filter-name>
    <servlet-name>click-servlet</servlet-name>
  </filter-mapping>
 
  <servlet>
    <servlet-name>click-servlet</servlet-name>
    ..
 
</web-app> 
}}

!session-scope: セッションスコープ vs リクエストスコープ
デフォルトでは、DataContextオブジェクトはユーザーのHttpSessionに格納されます。

もちろん、リクエスト毎に新しいDataContextを作成するよう、フィルターを設定することも可能です。データベースに対して排他的なアクセスが可能なweb アプリケーションに対しては有効な選択肢です。

しかし、複数のwebアプリケーションでデータベースを共用するような場合には、
サーブレットフィルターの初期化パラメータsession-scopeをfalseにして、リクエストごとのDataContextを使うべきでしょう。

!shared-cache: 共用キャッシュ
デフォルトでは、DataContextオブジェクトはCayenneのshared cacheを使うよう生成されます。これも、データベースに対して排他的なアクセスが可能なweb アプリケーションに対しては有効な選択肢です。

しかし、複数のwebアプリケーションでデータベースを共用するような場合には、サーブレットフィルターの初期化パラメータshared-cacheをfalseにして、shared cacheを無効にするべきでしょう。

!!CayenneFormの使用
CayenneFormは、DataObjectオブジェクトのINSERTとUPDATEをサポートしています。CayenneFormは、必須のプロパティに関してはフィールドのrequiredプロパティが自動的にtrueに設定され、max length validation制約も設定されます。

以下の例は、Organisationオブジェクトを生成/更新するためのページです。既存のOrganisationオブジェクトを編集する場合、編集対象のオブジェクトをリクエストパラメータとして渡します。それ以外の場合は[saveChanges()|http://click.sourceforge.net/docs/extras-api/net/sf/click/extras/cayenne/CayenneForm.html#saveChanges()]メソッドの呼び出しで新しいOrganisationオブジェクトが作成されます。

{{ref_image CayenneFormExample.PNG}}

{{code java
 public class OrganisationEdit extends Page {

   private CayenneForm form = new CayenneForm("form", Organisation.class);

    public OrganisationEdit() {
        form.add(new TextField("name", "Organisation Name:", 35);

        QuerySelect type = new QuerySelect("type", "Type:");
        type.setQueryValueLabel("organisation-types", "VALUE", "LABEL");
        form.add(type);

        form.add(new TextArea("description", "Description:", 35, 2);

        form.add(new Submit("ok", "   OK   ", this, "onOkClicked");
        form.add(new Submit("cancel", this, "onCancelClicked");

        form.setButtonAlign("right");
        addControl(form);
    }

    public void onGet() {
        Organisation organisation = (Organisation)
           getContext().getRequestAttribute("organisation");

        if (organisation != null) {
            form.setDataObject(organisation);
        }
    }

    public boolean onOkClicked() {
        if (form.isValid()) {
           if (form.saveChanges()) {
               Organisation organisation = (Organisation) form.getDataObject(false);
               String url = getContext().getPagePath(OrganisationViewer.class);
               setRedirect(url + "?id=" + organisation.getId());
               return false;
           }
        }
        return true;
    }

    public boolean onCancelClicked() {
        Organisation organisation = (Organisation) form.getDataObject(false);
        String url = getContext().getPagePath(OrganisationViewer.class);
        setRedirect(url + "?id=" + organisation.getId());
        return false;
    }
 } 
}}

このなかでgetDataObject(false)という呼び出しがありますが、フィールドの値をデータオブジェクトに適用することなく、DataObjectを取得しています。この手法は、既にオブジェクトがあってフィールド上の変更を適用したくない場合に大変有効です。

onOkClickedメソッドでは、サービスクラスないしDAOパターンを用いることでDataObjectを保存することもできます。

{{code java
    public boolean onOkClicked() {
        if (form.isValid()) {
           Organisation organisation = (Organisation) form.getDataObject();

           getOrganisationService().save(organisation);

           String url = getContext().getPagePath(OrganisationViewer.class);
           setRedirect(url + "?id=" + organisation.getId());
           return false;
        }
        return true;
    } 
}}

!!CayenneTemplateの使用
Spring DAO テンプレートパターンによる、拡張のための基底となるDAO/サービスクラスです。このクラスは、独自のpublicインターフェースを提供するカスタムDAOやサービスサブクラスを拡張して作成するために用意されています。多くの便利なDataContext用のメソッドを提供しており、APIドキュメントやexamplesを参考にすると良いでしょう。

!!PropertySelectの使用
PropertySelectは、DataObjectのリレーションシッププロパティ(これもまたDataObjectです)を選択するためのコントロールです。このコントロールは、CayenneForm上でしか動きません。また、今のところ単一の要素の選択しかサポートしてません。

!PropertySelect使用例
例えばPetTypeというDataObjectをプロパティに持つPetというDataObjectがあるとします。

{{code java
 public class Pet implements DataObject {
     public PetType getType() {
         ..
     }

     public void setType(PetType value) {
         ..
     }
 }

 public class PetType implements DataObject {
     public String getName() {
         ..
     }
 } 
}}

このPetTypeプロパティを編集するのにCayenneForm上でPropertySelectを利用します。この例では、PetTypeのnameプロパティが select の optionラベルとして出力されます。

{{code java
 CayenneForm form = new CayenneForm("form", Pet.class);

 PropertySelect typeSelect = new PropertySelect("type", true);
 typeSelect.setOptionLabel("name");
 form.add(typeSelect); 
}}

特にクエリを指定することなしに、コントロールはプロパティのクラスに基づき単純なSelectQueryを生成します。