Seamの情報

ネットを徘徊していたら偶然見つけました。

id:inabatch さんにより、Blogだけでなく、別途まとめた記事としてチュートリアル的なものが書かれています。すばらしい。


読ませて頂きましたが、ステートフルアプリケーションの記事で気になる部分が、、、

タブブラウザをお使いであれば、タブをもう一枚開いてください。そうでなければ、もう一枚ウィンドウを開いてください。そして、http://localhost:8080/sample/shopping.seam にアクセスしてみてください。そして、動作させてみてください。2つのブラウザの状態がまざっていますか?まざりませんよね?

SeamのConversationの実装はHttpSessionで実現されているため、そのままだと完璧には防げないのでは?という認識でした。
でも、Seamについて書かれた記事なり本では、そういうことは書かれていない気がする。

というわけで、記事と似たようなサンプルを作って確認してみました。
違う所は、SFSBではなく、JavaBeanとしてます(ホットデプロイが使いたいので・・・)


結果ですが、やっぱり混ざりました。例えば、以下のようになります。

  1. http://localhost:8080/sample/shopping.seamにアクセスする
  2. カートに商品を追加する
  3. 新規タブを開く(→FireFoxだと新規に開いたタブにshopping.xhtmlの画面がそのまま表示される)
  4. 開いたタブの画面からそのまま、カートに商品を追加する
  5. 最初のウィンドウでカートに商品を追加する(→1つだったのが3つになりまじっている)

上記結果のように、複数のタブで同一Conversationにアクセスしている状態になっています。
なぜそうなるかというと、、、

  • 上記手順の3番で新規タブを開くと、最初のウィンドウのキャッシュがそのまま表示される
  • つまり、hiddenで仕込まれているjavax.faces.ViewStateの値が全く同じの画面が2つできることになる
  • SeamはLong-Conversationとウィンドウの紐付けをConversationIdで行っているが、このIdはViewStateに格納されている
  • 今、両方のウィンドウは同一のVewStateと紐づいているの、Conversationも同一となってしまう

だからだと思います。

ちなみに混ざらないようにするには、新規にタブを開いた時にそのまま操作せずに、一度ナビゲーションバーに直接URLを入力して再アクセスします。
そうすると、別々のConversationとなりますので、混ざらなくなります。(でもわざわざそんなことはしないですよね、、、)
なので、Seamでマルチウィンドウは、アプリケーションとして意図的に別ウィンドウ/タブを開かせるようにしない限り使えないと思っています。
例えば、あるリンクをクリックしたときに別ウィンドウが開くとともにConversationが開始するような形です。


まとめますと、Seamのマルチウィンドウ対応に対する自分の見解としては、

  • アプリケーションとして意図的に複数のウィンドウを開き平行で処理させる場合にはConversationは有効
  • でも、Ctrl+Nなどによる新規ウィンドウ作成には弱いので、ユーザの操作次第ではデータの不整合は起きるため、別途何かしら対策は必要

です。


ちなみに、Seam1.2のころは、ConversationコンテキストをHttpSessionではなく、hiddenに保存するモード(Client-Conversation)があったのですが、2.0でいつのまにか無くなっています。まあ、これは画面遷移でRedirectを利用すると使えない代物だったの、実験的なものだったのかもしれませんが。。。

後、Seamの思想としては、PersistenceContextのスコープをConversationのスコープと同じにして、Entityのキャッシュを有効活用する考えなので、hiddenでクライアントにConversationの情報を持たせると、PersistenceContextのシリアライズに問題があったのかもしれません。