T2FrameworkのURLのマッピング

T2Frameworkをいじっていて、URLマッピングが重なった場合とかどうなるのか非常に気になった。

なんせ、一箇所で管理していないのだから、個別にクラスを見ていかないといけない。これはページ数が増えてくると非常に探すのが大変になってくる。重なるマッピングがいくらでも出てくるだろう。


と思っていたらMLの過去ログでそれが話題になっていたのに気がつく。


こういうのはいくら優先順位とかつけてもあんまり意味は無い。もちろん、毎回ちゃんと決められたとおりに動くのは大事なんだけれども、URLってのはわりと流動的であって例えば

/a/hoge

というマッピングで開発していたのに

/a/b/hoge

という風に変わる可能性もある。そうなったときに優先順位が変わる可能性は高い。

どんなに最善を尽くしたところでライブラリやフレームワークだけで解決は無理なのだ。



つまり解決方法としては2つ。

  • 優先順位を開発者に任せる
  • 重なるURLは作らせない

一つ目は実装は単純で、効果はでかい。例えば優先順位はpriority属性をPageアノテーションにでも追加すればよい。デフォルト値は0あたりにしておけば従来のように

@Page("/hoge")
public class Hoge {

と表記も出来るし、明示したければ

@Page(value="/hoge" , priority=10)
public class Hoge {

とでもすればよい。

1単位ではなく10単位ってのは古のBASICの行番号と同じで、かなり融通が利くから。0と10の間に5を後から挿入すれば中間の優先順位をつけられる。そして8という値をつければ5と10の間、9という値で8と10の間の優先順位と、かなりあとからの修正にも強くなる。

9と10の間をつけたいという場合はもうURLのマッピングをぜんぜん考慮していないぐちゃぐちゃの可能性が大きくてあきらめたほうが良いかもしれない。なんちて。

そんなときにはリファクタリングだ。なんと「RENUM」コマンドひとつで(ry

ハァハァ


2つ目はJAX-RSのサブリソースのように扱うということ。
つまり、例を挙げると以下のようになる。

@Page("/a")
public class A {
  @Default
  public Navigation default(){
    return SubResource.to(Hoge.class);
  }
…
}
@Page("./hoge")
public class Hoge {
  @Default
  public Navigation default(){
    ;
  }
…
}

とすると「/a/hoge」というURLでHogeクラスのリソースが実行されるとか。
もし、「/a」からはじまるリソースを作りたければ必ずAクラスに実装をして、それぞれサブリソースは別クラスに割り振るというわけ。

「/a」をマッピングする複数のクラスがあらわれたらそれは異常だということにしてWebアプリそのものを起動時にとめればよい。親切なエラーメッセージを出してあげて。

「./」から始まるパスはルートに持ってこれないとかあればさらに完璧。


個人的にはこの2つとも必要かなぁと考えてる。そうじゃないとT2はページ出力のみでリソースの扱いはJAX-RSとか他のを持ってきて連携させないといけないとかになっちゃいそうだし。スコープの連携といえばDWRのscriptスコープやICEfacesのrequestスコープみたいなものも欲しいかな。


複雑なルールを持つCoCは結構やばいと思うよ。おいらみたいな頭の悪い人がついていけなくなっちゃうから。