Tuesday, September 27, 2011

Sinatra on Scala

I rewrote the Servlet in my former post, Sinatra on RedBridge using Scala. Below is the code:

package chestnut

import java.io.{File, IOException}
import java.util.{ArrayList, List}

import javax.servlet.{ServletConfig, ServletException}
import javax.servlet.annotation.WebServlet
import javax.servlet.http.{HttpServlet, HttpServletRequest => HSReq, HttpServletResponse => HSResp}

import org.jruby.embed.{LocalContextScope, ScriptingContainer => Container}

import scala.collection.JavaConversions._
import scala.collection.mutable.ListBuffer


class HelloSinatra extends HttpServlet() {
private val gemPaths = new ListBuffer[String]
private var config: ServletConfig = _
private val container = new Container(LocalContextScope.THREADSAFE)
private var config_ru_path: String = _

def addGemPaths(gem_path: String) {
val gem_dir = new File(gem_path)
val gems = gem_dir.listFiles
for (gem <- gems) {
val path = gem + "/lib"
gemPaths += path
}
}

override def init(c: ServletConfig) {
config = c
val path = config.getServletContext().getRealPath("/WEB-INF/lib/vendor/jruby/1.8/gems")
addGemPaths(path)
gemPaths += config.getServletContext().getRealPath("/WEB-INF/lib/app")
config_ru_path = config.getServletContext().getRealPath("/WEB-INF/lib/app/config.ru")
}

override def doGet(request: HSReq, response: HSResp) = processHttpRequest(request, response)

override def doPost(request: HSReq, response: HSResp) = processHttpRequest(request, response)

private def processHttpRequest(request: HSReq, response: HSResp) {
container.setLoadPaths(gemPaths)
container.runScriptlet("require 'rubygems'")
container.put("config_ru_path", config_ru_path);
container.put("request", request);
container.put("config", config);
val script =
"""require 'rack'
rack_app, options = Rack::Builder.parse_file config_ru_path
require 'jruby-rack'
require 'rack/handler/servlet'
handler = Rack::Handler::Servlet.new rack_app
request.instance_variable_set(:@context, config.getServletContext)
class << request
def to_io
self.getInputStream.to_io
end
def getScriptName
self.getPathTranslated
end
def context
@context
end
end
handler.call(request)"""
var rack_response = container.runScriptlet(script);
var body : String = container.callMethod(rack_response, "getBody").asInstanceOf[String]
body += "\n\n\nand Hello from Scala Servlet!!"
response.getWriter().print(body);
container.clear();
}

}

Also, you can see the code, https://gist.github.com/1245405.


In the above Scala version, I added a small message to the Scala servlet. When you look at the result on your browser, you'll see two lines from Sinatra and Scala. The first line is from Sinatra, and the second line is from Scala servlet.

No comments: