Scala and Scalatra

I’ve been using Ruby on Rails almost exclusively for my web projects over the last year or two. Recently, when I had an idea for a new project, I decided to try something a little different.

My current Rails project, Rhino SchoolTracker, is a traditional CRUD-type web application that is fairly well suited to the Rails way of doing things. For this new project, however, I wanted to completely decouple my server side code from my front-end web application.

My idea is to create a simple REST API for the back-end services, and build the web UI using Backbone and Bootstrap. This also has the benefit of providing significant flexibility for possible mobile clients later. For the server side stuff, I could have turned to Rails again, but that seemed like overkill when I would only be using a subset of its features.

I stumbled upon Scala while researching alternative server-side languages. While I would never use Java if I had a choice in the matter, the idea behind Scala is a good one. Fix the basic problems with Java (the language) and add functional programming support, all while retaining compatibility with the vast Java ecosystem and the ability to run on the mature (mostly, after all these years/decades) JVM. It should also be significantly faster and scale better than anything written in interpreted languages like ruby or python.

Scalatra

Scala has a number of web frameworks available to it.  Lift and Play are probably the most popular.  However, I wanted something lightweight, so I looked and found a minimalistic framework called Scalatra, which attempts to mimic the excellent Sinatra framework over in Ruby-land.  So, I decided to give it a shot.

Scalatra relies on the Simple Build Tool (sbt), and setting up a new project is fairly simple using g8:

g8 scalatra/scalatra-sbt

Firing up the build system is not difficult either, just execute the following in the project root directory:

g8 scalatra/scalatra-sbt

starting the build system is done by running the following in the project directory:

./sbt

I’m using IntelliJ IDEA for my development environment, and it just so happens there’s a helper plugin for sbt called gen-idea that generates all of the proper project files. I believe there is a similar plugin for eclipse users, if you’re one of those people.

Adding dependencies to the project is surprisingly easy compared to say, maven, or ivy.  And when I say easy, I mean NO XML.  To add support for my database and json, for example, I add the following lines to my project’s build.scala file:

"org.scalatra" %% "scalatra-json" % "2.2.1",
"org.json4s"   %% "json4s-jackson" % "3.2.4",
"org.json4s"   %% "json4s-ext"     % "3.2.4",
"org.squeryl"  %%  "squeryl" % "0.9.5-6",
"postgresql"   % "postgresql" % "9.1-901.jdbc4",
"c3p0"         % "c3p0" % "0.9.1.2",

squeryl is an ORM for Scala.  Not quite as easy to work with as ActiveRecord, but at least it’s not Hibernate.  C3p0 handles connection pooling.

Scalatra Routes

Scalatra handles routes much like Sinatra. Pretty easy actually, here’s a simple controller for a hypothetical record called “Person”:

import org.scalatra._
import org.json4s.{DefaultFormats, Formats}
import com.caffeinatedrhino.db.DatabaseSessionSupport
import com.caffeinatedrhino.testproj.models.Person
import org.scalatra.json.JacksonJsonSupport
import org.json4s.JsonAST.JValue

class PersonsController extends ScalatraServlet with DatabaseSessionSupport with JacksonJsonSupport {

  protected implicit val jsonFormats: Formats = DefaultFormats

  before() {
    contentType = formats("json")
  }

  get("/") {
    Person.allPersons
  }

}

What does it do? all requests to “/” — the servlet’s root, not necessarily the web root, result in a request to our Person model for all of the “Person” objects in the database. One thing that may not be obvious is that the response is sent as JSON… the before() filter automagically runs before all requests, setting the output type for each controller action to JSON. To enable this we have to mixin JacksonJsonSupport (it’s a Scala trait) and tell json4s which formats we want it to use when doing its serialization by setting that implicit variable (jsonFormats).

If you’re wondering how we register all of our servlets(i.e., controllers), Scalatra projects have a single ‘ScalatraBootstrap.scala’ file, that goes something like this:

import com.caffeinatedrhino.testproj.controllers.PersonsController
import org.scalatra._
import javax.servlet.ServletContext
import com.caffeinatedrhino.db.DatabaseInit

class ScalatraBootstrap extends LifeCycle with DatabaseInit {
  override def init(context: ServletContext) {
    configureDb()
    context.mount(new PersonsController, "/persons")
  }

  override def destroy(context: ServletContext) {
    closeDbConnection()
  }
}

So our Persons servlet is mounted at “/persons” — so a request to http://example.com/persons should result in retrieving our “Person” objects.

Database Support

In our ScalatraBootstrap class, you’ll also notice we call configureDb() in the init method (and a corresponding closeDbConnection() in the destroy method).  The appliction is stood up and torn down here, so this is the natural place to set up our database (and close it).  There’s a trait mixed into our ScalatraBootstrap class called DatabaseInit that provides these methods.  Here it is:

import org.slf4j.LoggerFactory
import java.util.Properties
import com.mchange.v2.c3p0.ComboPooledDataSource
import org.squeryl.adapters.PostgreSqlAdapter
import org.squeryl.Session
import org.squeryl.SessionFactory

trait DatabaseInit{

  val logger = LoggerFactory.getLogger(getClass)
  var cpds = new ComboPooledDataSource

  def configureDb() {
    val props = new Properties
    props.load(getClass.getResourceAsStream("/c3p0.properties"))
    cpds.setProperties(props)
    SessionFactory.concreteFactory = Some (() => connection)

    def connection = {
      logger.info("Creating connection with c3p0 connection pool")
      Session.create(cpds.getConnection, new PostgreSqlAdapter)
    }
    logger.info("Created c3p0 connection pool")
  }

  def closeDbConnection() {
    logger.info("Closing c3p0 connection pool")
    cpds.close
  }

}

The usual properties needed to connect to the database are stored in a separate c3p0.properties file:

c3p0.driverClass=org.postgresql.Driver
c3p0.jdbcUrl=jdbc:postgresql://localhost:5432/testdb
user=testuser
password=testpass
c3p0.minPoolSize=1
c3p0.acquireIncrement=1
c3p0.maxPoolSize=50

Easy enough, but what about the DatabaseSessionSupport trait that we mixed into the controller? Oh, here it is, lifted almost verbatim from the scalatra documentation:

package com.caffeinatedrhino.db

import org.squeryl.Session
import org.squeryl.SessionFactory
import org.scalatra._

object DatabaseSessionSupport {
  val key = {
    val n = getClass.getName
    if (n.endsWith("$")) n.dropRight(1) else n
  }
}

trait DatabaseSessionSupport { this: ScalatraBase =>
  import DatabaseSessionSupport._

  def dbSession = request.get(key).orNull.asInstanceOf[Session]

  before() {
    request(key) = SessionFactory.newSession
    dbSession.bindToCurrentThread
  }

  after() {
    dbSession.close
    dbSession.unbindFromCurrentThread
  }

}

Finally, if you’re curious about our “Person” model, here it is:

package com.caffeinatedrhino.testproj.models

import com.caffeinatedrhino.db.DBRecord

import org.squeryl.PrimitiveTypeMode._
import org.squeryl.{Query, Schema}
import org.squeryl.annotations.Column

import java.sql.Timestamp

class Person(val id: Long,
             @Column("USER_ID") val userID: Long,
             @Column("LAST_NAME") var lastName: String,
             @Column("FIRST_NAME") var firstName: String,
             @Column("DATE_OF_BIRTH") var dateOfBirth: Timestamp,
             @Column("CREATED_AT") val createdAt: Timestamp,
             @Column("UPDATED_AT") var updatedAt: Timestamp) extends DBRecord{
  def this() = this(0, 0, "NO_NAME", "NO_NAME", new Timestamp(0), new Timestamp(0), new Timestamp(0))
}

/**
 * Kind of a cross between a Schema and a DAO really.  But I'll call it a Dao anyway
 * because it pleases me to do so.
 */
object PersonDao extends Schema {
  val persons = table[Person]("PERSONS")

  on(persons)(p => declare(
    p.id is(autoIncremented, primaryKey)
  ))
}

object Person{
  def create(person: Person):Boolean = {
    inTransaction {
      val result = PersonDao.persons.insert(person)
      if(result.isPersisted){
        true
      } else {
        false
      }
    }
  }
  def allPersons = {
    from(PersonDao.persons)(p => select(p)).toList
  }
}

You’ll notice we’re using a Java type here, java.sql.Timestamp, as if it belonged in our scala code.  Neat, eh?  You also might have noticed that we have both a class and a singleton object named ‘Person’ in the same source file.  In Scala, the object ‘Person’ would be said to be the companion object of class ‘Person.’  A class and its companion object can access each other’s private members (and they must both be defined in the same source file).

Well, that’s enough code for one blog entry.  That wasn’t nearly as bad as I feared it would be.  I’ve definitely seen more convoluted ways of accomplishing much the same thing in other languages/frameworks (*cough* Java/Spring/Hibernate *cough*).  I’m enjoying Scala so far, hopefully it continues to grow on me.

One thought on “Scala and Scalatra

  1. this is lovely, I heard the same spirit as you, but I am coming for the PHP world and Im very happy coming to scala and scalatra.
    thanks

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: