じゃう゛ぁとかよくわからないし的なレベルではじめようとすると前段階で躓くので、Rack とか HTTP::Engine 的に、あとはハンドラを書けばokみたいな状態にするまでのメモ
Java なウェブアプリは WAR とかいう形式にしてやると、サーブレットコンテナ (Jetty とか TomCat とか?) というものがよしなに起動してくれるようになるらしいです。GAE/J もそう。なので、それに沿ったものを作ります。
.
|-- src
| |-- META-INF
| | `-- jdoconfig.xml
| `-- net
| `-- lowreal
| `-- skirts
| `-- HttpRequestDispatcher.scala
`-- war
|-- WEB-INF
| |-- classes
| | |-- META-INF
| | | `-- jdoconfig.xml
| | `-- net
| | `-- lowreal
| | `-- skirts
| | `-- HttpRequestDispatcher.class
| |-- lib
| | `-- scala-library.jar
| |-- logging.properties
| `-- web.xml
|-- css
| `-- base.css
|-- images
|-- index.html
|-- js
`-- staticwar ディレクトリ以下が公開される (WEB-INF を除く) ディレクトリで、WEB-INF 以下にアプリケーション実体があり、WEB-INF/web.xml でルーティング設定をします。
web.xml ではふつう、URI -> Servlet の対応を XML で書くっぽいですが、そこらへんのことをむしろ自分でやりたいわけなので
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<filter>
<filter-name>HttpRequestDispatcher</filter-name>
<filter-class>net.lowreal.skirts.HttpRequestDispatcher</filter-class>
<init-param>
<param-name>foo</param-name>
<param-value>hogehoge</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HttpRequestDispatcher</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>というふうにフィルタで全部横取りします。
あとはフィルタ書けばいいだけなので
package net.lowreal.skirts
import javax.servlet._
import javax.servlet.http.{HttpServlet, HttpServletResponse, HttpServletRequest}
class HttpRequestDispatcher extends Filter {
var static = """^/(?:css|js|images|static).*""".r
val through = """^/_.*""".r
var router:HttpRouter = null
def init (filterConfig: FilterConfig) = {
println("initializing...")
val config_foo = filterConfig.getInitParameter("foo")
println("initialized config: " + config_foo)
}
def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) = {
(request, response) match {
case (req: HttpServletRequest, res: HttpServletResponse) =>
val path = req.getRequestURI
val statics = static
path match {
case statics() =>
chain.doFilter(request, response)
case through() =>
chain.doFilter(request, response)
case _ =>
}
case _ => chain.doFilter(request, response)
}
}
def destroy () = {
println("destroy")
}
}
アプリケーション起動時に init がよばれ、リクエストごとに doFilter がよばれてくるので、doFilter で request, response を適当にいじくればいいことになります。ここで chain.doFilter(request, response) をすればデフォルトのハンドラが呼ばれるっぽいので、普通は war 以下の static なものがそのまま返されます。
throught() は GAE/J のテストログインハンドラのためのやつです。(/_login? とかを GAE/J 側がハンドルしてる)