Wicketによるアプリ開発事始め


# 匿名内部クラスについて
Javaには、__匿名内部クラス__ というものがあります.  
これは、クラス(またはインタフェース)を継承したクラスを作成すると同時に、オブジェクトを生成するものです.  

次に例を示します.  

```java
Object o = new Object() {
    public Strign toString() {
        return "匿名内部クラスのオブジェクトです.";
    }
};
```

```new Object() {}```の、中括弧({})がポイントです.  
これを付けることで、Objectクラスを継承したクラスを作ったことになり、それをnewしているのでオブジェクトを生成していることになります.  


匿名内部クラスはWicketを使うときには頻出するため、ぜひ慣れておきましょう.  

下記のサイトで構文と効果を学習しておきましょう.  

[匿名内部クラス] (http://java.keicode.com/lang/anonymous-inner-class.php)

# Pageクラス実装基礎

## コンポーネントの初期化
Pageクラスには、通常、画面を動的に編集するためのコンポーネントが載ります.  
コンポーネントを使うには、次のようなスタイルでコーディングすることをおすすめします.  

* コンポーネントはインスタンス変数に宣言
* getterを作る
* getterの中は遅延初期化
* コンポーネントのインスタンスが必要なときは、必ずgetterを通して得る（そのインスタンスのgetterの中は例外）

サンプルを示します  

```java:SomePage.java
private Form<?> form;
private TextField<String> description;

private Form<?> getForm() {
    if (this.form == null) {
        this.form = new Form<Object>("form");
        this.form.add(getDescription()); // コンポーネントの入れ子. getterを使って子コンポーネントにアクセスする.
    }
    return this.form;
}

private TextField<String> getDescription() {
    if (this.description == null) {
        this.description = new TextField<String>("description", Model.Of(""));
    }
    return this.description;
}
```

# コンポーネントいろいろ

## サブミットするコンポーネント(Buttonクラス/SubmitLinkクラス/Formクラスなど)
これらのコンポーネントは、サブミット時の処理を```onSubtmit```メソッドに記述します.  
ここで匿名内部クラスを使うと、ソースがコンパクトになります.  

```java
private Button submitter;
private Button getSubmitter() {
    if (this.submitter == null) {
        this.submitter = new Button("submitter") {
            public void onError() {
                // エラー時の処理. 一般的にはあまりやることがない
            }
            public void onSubmit() {
                // 入力値検証が全てOKの場合にここが実行される.
                // 小さい処理はここに直接書いてもいいが、大きい処理は別にメソッドを作るのが良い.
            }
        };
    }
    return this.submitter;
}
```

## Ajaxでサブミットするコンポーネント(IndicatingAjaxButtonクラスなど）
これらのクラスも、サブミットしたときの処理は```onSubmit```メソッドに記述します.  
ただし、通常のButtonクラスなどによるサブミットはPage全体が再描画されることに対し、Ajaxの場合は再描画するコンポーネントを限定するのが一般的です.  
(これによりデータ転送量を抑え、ユーザビリティの向上が望める)  

ということは、Ajaxでサブミットした場合は、何らかの方法で再描画するコンポーネントをプログラム側で指定する必要がある、ということになります.  
ここで登場するのが```AjaxRequestTarget```クラスです.  

### AjaxRequestTarget
実は、```AjaxButton```などのAjaxでサブミットするコンポーネントの```onSubmit```メソッドは、引数に```AjaxRequestTarget```を取ります.  
下記は```AjaxButton```クラスの```onSubmit```メソッドのシグニチャです.  

```java
/**
 * Listener method invoked on form submit with no errors, before {@link Form#onSubmit()}.
 * 
 * @param target
 * @param form
 */
protected void onSubmit(AjaxRequestTarget target, Form<?> form)
{
}
```


AjaxRequestTarget#addメソッドにコンポーネントを与えると、そのコンポーネントは再描画対象になります.  


```java
protected void onSubmit(AjaxRequestTarget pTarget, Form<?> pForm) {
    pTarget.add(getDescription());
}
```

### 注意点・再描画するコンポーネントはsetOutputMarkupId(true)を呼んでおく必要がある！

### AjaxRequestTargetのその他の機能
#### appendJavaScriptメソッド
Ajaxのレスポンスをブラウザが受け取ったときに実行するJavaScriptを指定します. 

#### focusComponentメソッド
Ajaxのレスポンスをブラウザが受け取ったときにフォーカスを移すコンポーネントを指定します.  

## ループの実現(ListViewクラス)

## Ajaxによるページング

# モデルいろいろ

## AbstractReadOnlyModel
## PropertyModel
## CompoundPropertyModel

# 小ネタ
## Pageクラスが保持する可能性のあるクラスにはSerializableを実装するべし

## 状態のないページ(Stateless)
### ブックマーク可能なページはステートレスにするべき
### ログイン画面が実は難易度高い(正直、困る)
### Ajaxコンポーネントが載っているページをステートレスにするのは難しい.


## Pageクラス階層
共通のレイアウトを定義するために、基底クラスを作りましょう.  
レイアウトを変更可能にしておく必要がある箇所は、PanelやModelを返すような抽象メソッドを作ることで対処します.  

```java:WebPageBase.java
public abstract AppPageBase extends WebPage {

    private Label titleLabel;
    private Panel headerPanel;

    public AppPageBase() {
        this.add(getTitleLabel());
        this.add(getHeaderPanel());
    }


    /**
     * @return titleタグの中のテキストとなるモデルを返して下さい.
     */
    protected abstract IModel<String> getTitleModel();

    /**
     * @return headerタグの中身となる任意のPanelオブジェクトを生成して返して下さい.
     */
    protected Panel createHeaderPanel(String pPanelId);

    private Label getTitleLabel() {
        if (this.titleLabel == null) {
            this.titleLabel = new Label("titleLabel", new AbstractReadOnlyModel<String>() {
                @Override
                public String getObject() {
                    return getTitleModel().getObject() + " - App"; // 全てのページのタイトルの末尾にアプリ名を付与する.
                }
            });
        }
        return this.titleLabel;
    }

    private Panel getHeaderPanel() {
        if (this.headerPanel == null) {
            this.headerPanel = this.createHeaderPanel("headerPanel");
        }
        return this.headerPanel;
    }
}
```

```java:IndexPage.java
public class IndexPage extends AppPageBase {

    @Override
    protected IModel<String> getTitleModel() {
        return Model.Of("目次");
    }

    @Override
    protected Panel createHeaderPanel() {
        // 特に表示するものがない場合はEmptyPanelが利用できる
        return new EmptyPanel();
    }
}
```

# 推奨クラス構成
## レイヤ構造
階層の基本は次の通り.

```
  ＜ブラウザ寄り＞

     Pageクラス
        ↓
    Serviceクラス
        ↓
      Daoクラス

     ＜DB寄り＞
```

大原則は __上のクラスは直下のクラスしか参照出来ない__ ということ.


## クラスの種類
* Pageクラス：WicketのPageクラス
* Serviceクラス：ビジネスロジック
* Daoクラス：DBアクセス担当. JPAを使う場合はEntityManagerがここに該当
* Entityクラス：DBスキーマをマップ
* Modelクラス：Entityでは表現出来ない状態を保持

## Pageクラスが参照してよいクラス
* Serviceクラス
* Entityクラス
* 他のPageクラス（相互参照は極力避ける）
* Modelクラス

__要はDaoクラス以外__

## Serviceクラスが参照してよいクラス
* Entityクラス
* 他のServiceクラス（相互参照は極力避ける）
* Modelクラス

## Daoクラスが参照してよいクラス
* Entityクラス

## WicketでのDIコンテナ
Guiceが楽. 

```java:AppWicketApplication.java
// GuiceによるDI機能をWicketに対して有効にする仕込み.
// これによりDaoBaseクラスを継承したクラスのpublicメソッドはトランザクションが自動ではられるようになる.
getComponentInstantiationListeners().add(new GuiceComponentInjector(this, DI.getGuiceInjector()));
```

なおGuiceによるトランザクション制御のサンプルは以下を参照のこと. 
[jabara-jpa-guice](https://github.com/jabaraster/jabara-jpa-guice/)