2011年5月18日水曜日

JSF(Teeda) フェーズリスナでセッション存在チェック

JSFを用いたWEBアプリケーションの作成において、
セッションの存在チェックをどのタイミングで行うのが
正解なのか。

まず、Actionにインターセプターを設定してセッション存在チェックを
行おうと考えたが、rendererやConverter、Validatorを
拡張実装してスコープやセッションから値を取得している場合に、
チェックより前なので、ヌルポ等の予期せぬエラーが発生する可能性がある。

次に、filterでセッションチェックを行おうと考えていたが、
filterはTeeda管理外なので、エラー発生の場合Teedaで設定した
エラー画面とならず、HTTPステータスエラー画面になってしまう
(web.xmlのerror-pageで設定していれば別)。

今回はrendererのdecode処理でもセッションを使用する拡張等を
行っていたので、リクエスト適応フェーズ前にチェックを
行う必要があるため、フェーズリスナーでセッション存在チェックを
実装しようと思います。

JSFではフェーズごとにリスナーで処理をいれることができ、
フェーズリスナーの下記タイミングでチェックを行うことで
renderer、Converter、Validatorより前にチェックできる。

POST
1.RESTORE_VIEW(Page状態復元 スコープ管理機能中間モデルの復元)
→→→ ここでセッションチェック ←←←
2.APPLY_REQUEST_VALUES(中間モデルにリクエスト値の適応)※renderer(decode)
3.PROCESS_VALIDATIONS(バリデーション) ※Converter、Validator実行
4.UPDATE_MODEL_VALUES(Pageクラスのプロパティ更新)
5.INVOKE_APPLICATIONS(アクション実行)
GET
6.RENDER_RESPONSE(レンダリング)※renderer(encode)→initialize(初回)→prerender



 <lifecycle>
  <phase-listener>
   test.listener.SessionCheckListener
  </phase-listener>
 </lifecycle>


package test.listener;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.http.HttpSession;
・・・

public class SessionCheckListener implements PhaseListener {

    public void beforePhase(PhaseEvent event) {
        //リクエスト適応フェーズ前にセッションチェック処理
        ・・・
    }
    
    //リクエスト適応フェーズ後は何もしない
    public void afterPhase(PhaseEvent event) {}

    public PhaseId getPhaseId() {
        //リクエスト適応フェーズ
        return PhaseId.APPLY_REQUEST_VALUES;
    }
}    


あと、リクエストが違うので念のため
「6.RENDER_RESPONSE(レンダリング)」前
にもセッション存在チェックを入れました。

JPA(Kuina-Dao) リレーション関係を持ったテーブルの更新、追加時の注意点

例)
親テーブル(1)と関係する子テーブル(N)を関係性を持たせ新規登録

// 親テーブル用Dao
private ParentDao parentDao;
// 子テーブル用Dao
private ChildDao childDao;

protected void doLogic() {
    // 親テーブルを登録
    Parent parent = new Parent();
    parent.setParentid("999");
    parentDao.persist(parent);

    // 子テーブルを登録 数分繰り返し処理
    for (int i = 0; i < 10; i++) {
       Child child = new Child();
       child.setChildid("ABC" + i);
       
       // 親テーブルPkeyを直に設定しない
       // child.seParent_pkey(11111);
       
       // 親entitiyをセット
       child.setParentt(parent);
       childDao.persist(child);                                                        
    }                                                         
}                                                         
子entity(N側)の親entityPkeyは、個別に設定しないようにする。 個別に設定しないように制約を付けるには、Columnアノテーションで insertable、updatableにfalseを設定することによって、 リレーションentitiyによる追加、更新以外を防ぐことが可能。
@javax.persistence.Entity
@javax.persistence.Table(name = "child")
public class Child {

・・・

@javax.persistence.ManyToOne(targetEntity = Parent.class ,fetch = FetchType.LAZY)
private Parent parent;


@javax.persistence.Column(name = "parent_pkey", insertable = false, updatable = false)
private Integer parent_pkey;

・・・
}