Reading LiftFilter Request
さて。起動部分は大雑把に見たので、実際のリクエストに対する処理を見てみる。
サーブレットフィルタはリクエストを捉え、LiftFilter#doFilterを通してリクエストを処理させる。
ということで、LiftFilterの親クラス、 net.liftweb.http.provider.servlet.ServletFilterProviderのdoFilter から見てみることにする。
ServletFilterProvider#doFilter
/** * Executes the Lift filter component. */ def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) = { if (LiftRules.ending) chain.doFilter(req, res) else { LiftRules.reqCnt.incrementAndGet() try { TransientRequestVarHandler(Empty, RequestVarHandler(Empty, (req, res) match { case (httpReq: HttpServletRequest, httpRes: HttpServletResponse) => val httpRequest = new HTTPRequestServlet(httpReq, this) val httpResponse = new HTTPResponseServlet(httpRes) service(httpRequest, httpResponse) { chain.doFilter(req, res) } case _ => chain.doFilter(req, res) })) } finally {LiftRules.reqCnt.decrementAndGet()} } }
net/liftweb/http/provider/servlet/ServletFilterProvider.scala
LiftRules.ending
@volatile private[http] var ending = false
/net/liftweb/http/LiftRules.scala
正確にはこの先の話になるけど、よーするにサーブレットのdestory中ではないことを確認している(と思われる)フラグ。
true、つまり終了処理中の場合、chan.doFilter(req, res)で、他のサーブレットフィルタに渡すだけにして、else以下の本体的部分にわたらないようにしている。
で、elseの場合:
LiftRules.reqCnt.incrementAndGet(); try{...} finally {LiftRules.reqCnt.decrementAndGet()}
private[http] val reqCnt = new AtomicInteger(0)
/net/liftweb/http/LiftRules.scala
java.util.concurrent.atomic
クラス AtomicInteger原子的な更新が可能な int 値です。原子変数のプロパティーの詳細は、java.util.concurrent.atomic パッケージ仕様を参照してください。AtomicInteger は、原子的に増分されるカウンタなどのアプリケーションで使用されます。
(...)
現在の値を 1 だけ原子的に増分します。
戻り値:
更新された値http://java.sun.com/javase/ja/6/docs/ja/api/java/util/concurrent/atomic/AtomicInteger.html
はい、リクエストを受け付けた回数をカウントしているわけですね。で、最後にカウンタを減らしている。
コレもサーブレットの終了処理中にいきなり終わらないように、処理中のカウンタを用意してるわけですね。たぶん。
さて、次はtryの中身。
TransientRequestVarHandler(Empty, RequestVarHandler(Empty, (req, res) match { case (httpReq: HttpServletRequest, httpRes: HttpServletResponse) => val httpRequest = new HTTPRequestServlet(httpReq, this) val httpResponse = new HTTPResponseServlet(httpRes) service(httpRequest, httpResponse) { chain.doFilter(req, res) } case _ => chain.doFilter(req, res) }))
net/liftweb/http/provider/servlet/ServletFilterProvider.scala
ややこしくなってきた。
TransientRequestVarHandlerには、引数としてEmptyとRequestVarHandlerが何かのオブジェクトを作って渡して、全体としてオブジェクトを作っている。ちなみに、こういうときはobject TransientRequestVarHanderのapply関数が呼ばれることになっている。
RequestVarHanderには、引数としてEmptyと(req, res)のmatch式の結果を与えている。
(req, res)のmatch式内部では、reqがHttpServletRequest、かつresがHttpServletResponseであるときに、service関数に両者をラップしただろうものを渡しつつ、{...}で関数ブロックを渡している。
service関数は親クラス、net.liftweb.http.provider.HTTPProvider内にあるようだ。
さて、どこから読もうか、serviceが本体っぽいので、ここから読もう。リクエストのラッパーはその中で出てくるだろー。
HTTPProvider#service
/** * Call this function in order for Lift to process this request * @param req - the request object * @param resp - the response object * @param chain - function to be executed in case this request is supposed to not be processed by Lift */ protected def service(req: HTTPRequest, resp: HTTPResponse)(chain: => Unit) = { tryo { LiftRules.early.toList.foreach(_(req)) } val newReq = Req(req, LiftRules.statelessRewrite.toList, LiftRules.statelessTest.toList, System.nanoTime) CurrentReq.doWith(newReq) { URLRewriter.doWith ( url => NamedPF.applyBox( resp.encodeUrl(url), LiftRules.urlDecorate.toList ) openOr resp.encodeUrl(url) ) { if ( !(isLiftRequest_?(newReq) && actualServlet.service(newReq, resp)) ) { chain } } } }
net/liftweb/http/provider/HTTPProvider.scala
さて、いよいよという感じがあるが、よく見ると「actualServlet.service」なんてモノがあるので、まだここは準備でしかなさそう。
tryo {...}
/** * Wraps a "try" block around the function f * @param f - the block of code to evaluate * @return <ul> * <li>Full(result of the evaluation of f) if f doesn't throw any exception * <li>a Failure if f throws an exception * </ul> */ def tryo[T](f: => T): Box[T] = tryo(Nil, Empty)(f)
net/liftweb/util/ControlHelpers.scala
(あとでかく)