Jetty+Velocityを実験してみた

ScalaXMLモードは少々癖がある

<br />が<br></br>になる

ので。
Velocityを使ってみた。以下はそのコード、

import java.io.PrintWriter

import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

import org.mortbay.jetty.Connector
import org.mortbay.jetty.Server
import org.mortbay.jetty.nio.SelectChannelConnector

import org.mortbay.jetty.servlet.ServletHandler
import org.mortbay.jetty.NCSARequestLog
import org.mortbay.jetty.handler.RequestLogHandler

import org.apache.velocity.app.Velocity;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.Template;


//------------------------------------
class ServletServer extends HttpServlet {
  override protected def doGet(request:HttpServletRequest, response:HttpServletResponse) {
    common(request, response)
  }
  override protected def doPost(request:HttpServletRequest, response:HttpServletResponse) {
    common(request, response)
  }
  override protected def doPut(request:HttpServletRequest, response:HttpServletResponse) {
    common(request, response)
  }
  override protected def doDelete(request:HttpServletRequest, response:HttpServletResponse) {
    common(request, response)
  }

  //------------------------------------
  def common(request:HttpServletRequest, response:HttpServletResponse) {
    val reader = request.getReader

    var body = ""
    var line = reader.readLine
    while(line != null) {
      body += line
      body += "\n"
      line = reader.readLine
    }
    reader.close

    val templateFile = "example.vm"
    val template = Velocity.getTemplate(templateFile);

    val context = new VelocityContext();
    context.put("request", request);
    context.put("body", body);
    setContext(context)

    val out = response.getWriter
    response.setContentType("text/html")
    template.merge(context, out);
  }
  
  //------------------------------------
  def setContext(context:VelocityContext) = {
    context.put("array", Array("10","20"));

    val ar = Array("10","20")
    context.put("array1", ar);

    val lst = List("30","40")
    context.put("list1", lst.toArray);

    val ar2 = lst.toArray
    context.put("array2", ar2);
  }
}

//------------------------------------
object httpd extends Application {
  Velocity.init("velocity.properties");

  //------------------------------------
  val server            = new Server
  val connector         = new SelectChannelConnector
  val requestLog        = new NCSARequestLog
  val requestLogHandler = new RequestLogHandler
  connector.setPort(8080)
  server.addConnector(connector)
  requestLog.setExtended(false)
  requestLogHandler.setRequestLog(requestLog)
  server.addHandler(requestLogHandler)

  //------------------------------------
  val servletHandler    = new ServletHandler
  servletHandler.addServletWithMapping(classOf[ServletServer], "/hoge/*")
  server.addHandler(servletHandler)

  //------------------------------------
  server.start
  server.join
}

これは、以下のJarにclasspathが通っていると動く。

jetty-6.1.7.jar
jetty-util-6.1.7.jar
servlet-api-2.5-6.1.7.jar
velocity-dep-1.5.jar

velocity.propertiesは

runtime.log = velocity_example.log

で、example.vm

<?xml version="1.0" encoding="iso-2022-jp"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Velocity Test</head>
</head>
<body>

<hr />
#set( $this = "Velocity")
$this is great!

<hr />
    context.put("array1", Array("10","20"));<br />
    --------------------------<br />
    #foreach( $name in $array1 )
        $name<br />
    #end

<hr />
    val ar = Array("10","20")<br />
    context.put("array2", ar);<br />
    --------------------------<br />
    #foreach( $name in $array2 )
        $name<br />
    #end

<hr />
    val lst = List("30","40")<br />
    context.put("list1", lst.toArray);<br />
    --------------------------<br />
    #foreach( $name in $list1 )
        $name<br />
    #end

<hr />
    val ar2 = lst.toArray<br />
    context.put("array2", ar2);<br />
    --------------------------<br />
    #foreach( $name in $array2 )
        $name<br />
    #end

<hr />
    #set( $condition = true)
    #if ($condition)
        The condition is true!
    #else
        The condition is false!
    #end

<hr />
    $request.method<br />
    $request.pathInfo<br />
    $request.requestURI<br />

<body>
<html>

これの実行結果は

<?xml version="1.0" encoding="iso-2022-jp"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>Velocity Test</head>
</head>
<body>

<hr />
Velocity is great!

<hr />
    context.put("array", Array("10","20"));<br />
    --------------------------<br />

<hr />
    val ar = Array("10","20")<br />
    context.put("array1", ar);<br />
    --------------------------<br />
            10<br />
            20<br />

<hr />
    val lst = List("30","40")<br />
    context.put("list1", lst.toArray);<br />
    --------------------------<br />
    
<hr />
    val ar2 = lst.toArray<br />
    context.put("array2", ar2);<br />
    --------------------------<br />
            30<br />
            40<br />
    
<hr />
                The condition is true!
    
<hr />
    GET<br />
    /piyo<br />
    /hoge/piyo<br />

<body>
<html>

となる。その時のログは、

2008/01/24 22:19:19 org.apache.velocity.runtime.log.JdkLogChute log
情報: FileResourceLoader : adding path '.'
2008-01-24 22:19:19.802::INFO:  Logging to STDERR via org.mortbay.log.StdErrLog
2008-01-24 22:19:19.880::INFO:  jetty-6.1.7
2008-01-24 22:19:19.982::INFO:  Started SelectChannelConnector@0.0.0.0:8080
127.0.0.1 -  -  [24/1/2008:13:19:21 +0000] "GET /hoge/piyo HTTP/1.1" 200 0 
2008/01/24 22:19:21 org.apache.velocity.runtime.log.JdkLogChute log
情報: Could not determine type of iterator in #foreach loop at example.vm [line 0, column 0]
2008/01/24 22:19:21 org.apache.velocity.runtime.log.JdkLogChute log
情報: Could not determine type of iterator in #foreach loop at example.vm [line 0, column 0]

となる。
上記のログの中で「Could not determine type of iterator...」となっている行が2行あるが、
それが、実行結果中の

<hr />
    context.put("array", Array("10","20"));<br />
    --------------------------<br />
<----------------------------------------------------------------(1)
    
<hr />
    val ar = Array("10","20")<br />
    context.put("array1", ar);<br />
    --------------------------<br />
            10<br />
            20<br />

<hr />
    val lst = List("30","40")<br />
    context.put("list1", lst.toArray);<br />
    --------------------------<br />
<----------------------------------------------------------------(2)
    
<hr />
    val ar2 = lst.toArray<br />
    context.put("array2", ar2);<br />
    --------------------------<br />
            30<br />
            40<br />

の、(1)(2)にあたる。
ここは、想定では、それぞれ、1つ下のセクションと同じ出力結果となるはずが
何も表示されていない。
つまり、foreachが実行できないでいる。

これは、なぜ?