前回までに,サブミットの受け付け方法が分かりましたので,実際にonSubmit()を実装してTwitterにログインする処理を記述したいところです。ですが,サンプルプログラムのコードを理解するには,Wicketにおけるユーザセッションの取り扱いについて理解する必要があります。
そこで今回は,このユーザセッションの取り扱いについて解説します。
ユーザセッションにアクセスする
サーブレットでプログラムを作るとき,ユーザごとに用意されるデータ格納領域としてHttpSessionオブジェクトを使用することができました。Wicketでも,同様の仕組みがあります。
とはいえ,Wicketではページ自身がフィールドを持つことができ,Wicketがページの状態を保存してくれます。あるページオブジェクトはユーザ固有のもので,同じページクラスから作られたページでも,ユーザが異なれば,別のオブジェクトが割り当てられます。このようなページの割り当てと保存は,Wicketが裏側で行います。
この仕組みがあるために,サーブレットに比べて,ユーザセッションの用途は限られています(必要な情報はページ自身に持てばよいのですから)。
しかしながら,アプリケーションにはページ内で完結する情報と,複数のページにまたがって,ユーザがログインしている間はずっと使いたい情報とがあります。後者の情報を扱うには,HttpSessionのような機能は便利です。
Wicketのユーザセッションは,Sessionクラスのサブクラスとして作成します。このサブクラスには,プログラマが自由にメソッドやフィールドを追加できます。サーブレットのHttpSessionはただ使うことができるだけで,情報の保存・取得はsetAttribute(),getAttribute()メソッドで行いました。どんな情報であれ,これらのメソッドで保存・取得していたため,アプリケーション全体でHttpSessionにどのような情報を格納しているのかを調べることは大変でした。
Wicketでは独自のSessionサブクラスに,自由にメソッドを追加できます。自分で作ったサブクラスを一瞥すれば,アプリケーション全体でSessionにどのような情報が保存されているのか,一目瞭然です。また,メソッドを定義することで,データの出し入れがJavaらしい型安全性を持つことになります。
独自のセッションクラスを設定する
サンプルプログラムでは「jp.gihyo.wicket.AppSession」という,Sessionクラスのサブクラスを用意しています。この独自のサブクラスをWicketに使わせる設定を行う必要があります。
Wicketでは,この設定もプログラムで行います。jp.gihyo.wicket.WicketApplicationクラス内に,次のメソッドを記述しています。
リスト1 newSessionメソッドのオーバーライド
@Override
public Session newSession(Request request, Response response) {
return new AppSession(request);
}
WicketApplicationクラスは,今回のサンプルアプリケーションにおけるWebApplicationサブクラスです(※1)。WebApplicationクラスについては,第1回でもご紹介しました。
Wicketはユーザセッションをはじめて使用する時に,WebApplicationクラスのnewSession()メソッドを呼び出すことで,セッションオブジェクトを作成します。newSession()メソッドをオーバーライドすることで,独自のSessionサブクラスを生成することができます。
- ※1
- Wicketが使用するWebApplicationクラスの指定は,web.xmlファイルにて行われています。Wicketが使用する,唯一のXML定義がWebApplicationクラスの指定です。
ログイン状態を保存する
ユーザがTwitterにログインできた場合,その状態はページをまたがって維持されるでしょう。そのため,Twitterへのログイン処理は,AppSessionクラスにプログラムします。HttpSessionと違って,ユーザセッションにメソッドを定義できる利点を生かします。
ユーザがログイン成功すると,twitter4jのTwitterオブジェクトをユーザセッション内に保存し,いつでもAppSessionから取り出せるようにします。次のコードがログイン処理です。
リスト2 Twitterオブジェクトの作成とログインチェック
private Twitter twitterSession;
private User twitterUser;
private String lastUnauthorizedMessage;
(中略)
public boolean login(String userName, String password) {
Twitter client = new TwitterClient(userName, password);
try {
User user = client.verifyCredentials();
if(user != null) {
twitterUser = user;
twitterSession = client;
return true;
}
} catch (TwitterException ex) {
if(ex.getStatusCode() == HttpServletResponse.SC_UNAUTHORIZED) {
lastUnauthorizedMessage = ex.getMessage();
return false;
}
}
return false;
}
Twitterクラスは,今回Twitterにアクセスするために使うtwitter4jが用意しているクラスです。このオブジェクトを介して,Twitterのステータス情報を取得できます。
ここでは,Twitterクラスの代わりにTwitterクラスを独自にサブクラス化したTwitterClientクラス(完全修飾クラス名はjp.gihyo.wicket.TwitterClient)を生成しています。本記事の執筆段階ではtwitter4jのTwitterクラスにはシリアライズに関するバグがあり,セッションがシリアライズされた場合に正しく復元されません。TwitterClientクラスはそのバグを回避するために今回用意したサブクラスです。正しくシリアライズから復元できるようにしたこと以外には、もとのTwitterクラスと機能上の違いはありません。
Twitterへのログインチェックは,TwitterオブジェクトのverifyCredentials()メソッドで行います。ユーザ名とパスワードが正しければ,Userオブジェクトが返されます。逆にログインに失敗すれば,TwitterExceptionがスローされます。
login()メソッドはUserオブジェクトを取得できればログイン成功と見なしてtrueを返します。逆に,TwitterExceptionがスローされればログイン失敗と見なしてfalseを返します。
ポイントとして,ログイン成功時にも失敗時にも,生成された情報をAppSessionのフィールドに保存していることです。成功すればUserオブジェクトを保存しますし,失敗すれば失敗理由を保存します。
AppSessionには,保存された情報にアクセスするためのメソッドも用意されています。
お仕着せのHttpSessionをただ使うだけでなく,独自のオブジェクトとして作ることができることで,ユーザセッションのイメージがサーブレットから大きく変わっていることが分かるでしょうか。Wicketでは,ユーザセッションはHttpSessionのような,ただの入れ物ではありません。ユーザセッションはオブジェクトです。それはプログラム可能であり,メソッドを持つことができ,メソッド呼び出しによって状態が変化するのです。

