トップ 差分 一覧 ソース ヘルプ RSS ログイン

Controls

Clickのコントロール

Clickでは、クライアントサイドの出力およびサーバサイドの処理を行う数々の豊富なコントロールを提供しています。ここでは、以下の話題について述べていきます。

ここでは、コントロール全般についての概略を扱います。個々のコントロールについてはClickが提供するコントロールの一覧Javadocexamplesを参照してください。

 コントロールのインターフェース

Clickのコントロールは、ユーザーの入力を処理するサーバサイドのコンポーネントを提供し、そしてユーザーへの表示を行います。Visual BasicのコントロールやDelphiのコンポーネントに相当するものなのです。

コントロールは、onProcessメソッドでユーザーの入力を処理し、toString()メソッドで、表示用HTMLを生成します。コントロールが処理され出力される一連の流れは以下の図1のようになります。

図1 ポストされたときの処理の流れ - created with Enterprise Architect courtesy Sparx Systems

Clickにおけるコントロールは、全てControlインターフェースを実装しなければなりません。このControlインターフェースは下図2になります。

図2 Control インターフェース図 - created with Enterprise Architect courtesy Sparx Systems

Controlインターフェースのメソッドには以下のものがあります。

  • getContext() - リクエストのContextが取得できます。
  • getHtmlImports() - コントロールを使う際に必要となるHTMLヘッダーのimport文を定義します。
  • getId() - HTML要素のid属性値を定義します。
  • setListener() - コントロールのコールバックリスナーをセットします。
  • getMessages() - コントロール用のローカライズされたメッセージマップを定義します。
  • getName()/setName() - ページモデルやフォームフィールドでの名前を定義します。
  • getParent()/setParent() - コントロールの親コントロールを定義します。
  • onDeploy() - Clickの起動時にコントロールに必要なファイルなどのリソースを配置するための設定を行います。
  • onInit() - イベントハンドラーの初期化を行います。
  • onProcess() - リクエストのイベントハンドラを処理します。
  • onDestory() - イベントハンドラーの破棄処理を行います。
  • onDestory() - コントロールのHTML表現を生成します。

 コントロールのコールバック

Clickのコントロールは、java.awt.ActionListenerコールバックに似たイベントコールバックの機構を提供します。

Clickは2つの方式のアクションリスナーをサポートします。1つ目はActionListenerインタフェースを利用してコンパイル時タイプセーフを行う方式、二つ目はsetListener(Object,String)メソッドでコールバックメソッドの名前を指定する方式です。2つ目の方式はコード量が少なくなりますがタイプセーフではありません。

これら2つのアクションリスナー方式は以下のようになります:

すべてのコールバック関数はbooleanかjava.lang.Booleanを返す必要があります。コールバック関数がtrueを返すと、他のコントロールの処理へと処理が続行されます。対してコールバック関数がfalseを返した場合、他のコントロールの処理はこれ以上実行されません。falseを返すことによってあなたは処理を中断し、別ページへのリダイレクトやフォワードによる遷移を効果的に行うことができます。この実行の仕組みに関しては、ページが実行される処理の流れを参照してください。

処理の続行を停止し、別の処理をすることは非常に簡単です。例えばonRender()で非常にコストのかかるデータベースの処理を実行するとしましょう。イベントハンドラでfalseを返すことで、この処理をスキップし別のページへフォワードすることができます。

 コントロールのクラス構成

コントロール関連の主要なクラスは、org.apache.click.controlパッケージで定義されています。このパッケージは、主要なHTML要素に対応するコントロールが含まれています。

拡張コントロール関連のクラスは、org.apache.click.extras.controlパッケージで提供されています。Click Extrasのクラスは、サードパーティのフレームワークへの依存性を含むものもあります。

これらコントロールクラスのサブセットは下図3のように表すことができます。

図3 パッケージのクラス図 - created with Enterprise Architect courtesy Sparx Systems

このなかでも特に要となるのが以下のコントロールです。

  • ActionLink - リスナを呼び出すことが可能なリンク
  • Field - フォームのフィールドのためのabstractなコントロール.
  • Form - 入力フォーム
  • Submit - リスナを呼び出すことが可能な送信ボタン
  • TextField - リスナを呼び出すことが可能なテキストボックス

これらのコントロールクラスは、動作をカスタマイズするために派生することを考慮に入れて設計されています。コントロールの全てのフィールドはprotectedとなっており、アクセサメソッドはpublicになっています。

またこれらのコントロールを組み合わせて、より複雑なコントロールを構築することも可能です。例えばCreditCardFieldは、Selectコントロールを利用して複数のカードの種類を出力しています。

 メッセージプロパティ

コントロールで使用するフィールドバリデーションメッセージとHTML整形文字列はプロパティファイルに切り出されます。このプロパティファイルを使用することによって、Clickアプリケーションを個々の言語用にローカライズすることができます。

メッセージの解決

メッセージは、状況にあわせて取得できるよう、特定の順番で探索されます。そのコントロールのもの、そのページのもの、アプリケーション全体のものとがあります。

その取得の順序は以下のようになります。

ページのメッセージ

まずページクラスに紐付けされているメッセージを探します。Loginページの場合、そのメッセージプロパティは以下のファイルで定義されます。

   /com/mycorp/page/Login.properties 

特定のページでメッセージを調整したい場合には、ここに記述します。

ページ全体のメッセージ

次にアプリケーション全体のページに対して設定されているメッセージを探します。

    /click-page.properties 

アプリケーション全体のページで使いたいメッセージがあれば、ここに記述します。

コントロールのメッセージ

次にコントロールに対して紐付けされているメッセージを探します。CustomTextFieldコントロールに対するメッセージは、以下のファイルに記述します。

   /com/mycorp/control/CustomTextField.properties 

アプリケーション全体のコントロールのメッセージ

ここまでのもので見つけられなかった場合、最後にアプリケーション全体のコントロールに対して紐付けされているメッセージを探します。アプリケーション全体のコントロールに対するメッセージは、以下のファイルに記述されます。

   /click-control.properties 

コントロールのプロパティ

click-control.propertiesをカスタマイズする には、クラスパスにこのファイルを追加し、値を設定していくだけです。

このメッセージプロパティをカスタマイズする時には、設定したい値だけでなく、既定で設定してある以下の項目すべてを記述する必要があります。

メッセージへのアクセス

Fieldクラス及びその派生クラスは階層化されたバリデーションエラーメッセージなどの表示用メッセージに紐付けされるメッセージリソースをサポートしています。これらのローカライズされたメッセージは、以下のFieldのメソッドを通じてアクセス可能です。

これらのメソッドは、リクエストのLocaleを利用して、紐付けされた文字列リソースを探します。そしてMessageFormatで文字列の整形を行います。

 Container

Containerは他のコントロールを包含することができるコントロールで、コンポーネントの階層をまとめるものです。

Containerではコンポーネントを追加、削除したり他のコントロールを検索したりできます。

以下の一覧はContainerの例です:

  • Form - デフォルトのフィールドレイアウトやエラーフィードバックを提供するHTMLフォーム。
  • Panel - ページに類似してこのContainerは自身のテンプレートとモデルを提供します。
  • FieldSet - 子コントロールの周りにボーダーを描画します。

これらのContainerは図4のように描かれます。

次に示すクラスはカスタムコンテナを作成するための便利な拡張ポイントを提供します:

AbstractContainer

カスタムコンテナを簡単に作成することが出来ます。例としてHTML divまたはspan要素を挙げます。

新しく作成したコンテナを試すには以下のようにします:(このテストで使用しているMockContextについてはモックテストサポートドキュメンテーションに記述されています)

この例を実行すると以下のような出力になります:

AbstractContainerField

AbstractContainerFieldはFieldを継承しContainerインタフェースを実装しています。これはFieldとContainerの両方が必要な場合に便利な基底クラスとして提供されます。

以下はAbstractContainerFieldを使用した例です:

作成した新しいクラスのテストは以下のようなコード断片になります:

このコード断片の実行は以下のようになります:

 レイアウト

Formのようなコントロールはレイアウトとエラーレポートを自動で行います。そして多くの場合オートレイアウトは十分に良いです。

けれどもカスタムした、または複雑なレイアウトの場合、Formはいつもベストな選択肢ではありません。

カスタムレイアウトを作成するために2つのアプローチがあります。

  1. テンプレートアプローチ - Velocity、FreeMarkerまたはJSPのようなテンプレートエンジンを使用してレイアウトをHTMLマークアップのように宣言します。
  2. プログラム可能なアプローチ - Javaでカスタムレイアウトコンポーネントを構築します。このオプションはSwingを使用したコンポーネント構築と類似します。

テンプレートレイアウト

テンプレートアプローチを選択するとページとレイアウトロジックをうまく分離することが出来ます。例:

DIV<div>とHTMLリスト<ol>タグを使用したレイアウトを作成したい場合を想像してみます。以下のようなテンプレートエンジンとしてVelocityを使用したemployee.htmテンプレートを提供することが出来ます。

CSSスタイルシートを使用して上記のマークアップを装飾された見た目のFormに変換することができます。

テンプレートアプローチを使用することには賛否両論あります。

テンプレートアプローチの1つの利点は、レイアウトは明白で必要であれば調整が簡単なことです。例としてdivとオーダーリストを使用する代わりに、テンプレートを変更するだけでテーブルレイアウトに影響を与えます。

テンプレートアプローチの欠点は、冗長なことです。

上記の例ではJavaでフィールドを作成し、それらをテンプレートにマークアップで記述しています。

もし例に新しいフィールドを追加する要件が発生した場合、Pageクラスにもテンプレートにもフィールドを追加する必要があります。

大抵の場合、テンプレートエンジンを使用して汎用化されたレイアウトを利用できます。Macro.vmはVelocityを使用した汎用Formレイアウトの例です。

プログラム化レイアウト

テンプレートアプローチで紹介した冗長性と戦う場合、プログラム化アプローチを採用して、普通のJavaといくつかのClickクラス群を使用してカスタムレイアウトを構築できます。

Click extras ではHtmlFormHtmlFieldSetという名前のこの条件に当てはまる2つの役立つクラスを提供しています。

FormやFieldSetが描画で使用するTableレイアウトと違い、HtmlFormとHtmlFieldSetはそれに追加されたコントロールを順に描画し、どんな余分なマークアップも追加しません。HtmlFormの例は以下のようになります。

カスタムレイアウトを作成する場合、HTMLコンストラクトList<ul>はかなり便利です。そのためClickはこのコンポーネントを提供していません。以下のように作成してみましょう:

以下の例で使用される別のコンポーネントは、指定されたFieldのHTMLラベル要素を描画するFieldLabelです。

これでフォームを組み立てることが出来ます。

テンプレートアプローチのemployeeの例で続けると、もう一度EmployeePageを作成します。ただし、今回はHtmlFormとHtmlListをカスタムレイアウト作成のために使用します:

今回はemployee.htmテンプレートはトップレベルコンポーネントの名前だけ記述すればよく、このケースではformです。

これで以下のマークアップが提供されます。

もう一度CSSスタイルシートを使用することで、上記のマークアップを装飾された見た目のFormに変換することができます。

プログラム化アプローチのlive demoを見ることが出来ます。

プログラム化アプローチの利点は冗長でないことです。それぞれのFieldはJavaを使って生成と追加が行われます。マークアップで再度Fieldを記述する必要はありません。

新しいフィールドの追加が要求された場合、Pageクラスのみ更新する必要があります。CSSとコンポーネントにより出力されるマークアップでレイアウトが解決されるためテンプレートを変更する必要はありません。

プログラム化アプローチの欠点は描画がコンテナによって行われるため、可視化が難しいことです。

テンプレート、または、プログラム化レイアウトアプローチのどちらを使用するかはあなた次第です。それぞれ効果がありますし、お互いに対して利点と欠点を持っています。