Nginx, Jetty, Lift and Scala

by Sebastien Mirolo on Wed, 2 Nov 2011

After setting-up a php stack, a python stack and a ruby stack for web applications in the last couple weeks, I decided to go with nginx / jetty / Lift / scala next.

The good thing about Scala is that it compiles to JVM bytecode. A lot more efforts have been put over the years to run JVM bytecode extremely fast than, say, the ruby virtual machine. Because Scala code is compiled, it is also statically checked and you will catch a lot more spelling and type errors sooner than, say, in python or ruby. I thus have big hopes to get productivity enhancements without sacrificing runtime performance by programming in Scala. A presentation of Scala use at twitter can also be informative.

Nginx and Jetty

Jetty is an HTTP server that supports webapps as .war Java archives. So first thing is to setup nginx as the front-end server and proxy dynamic requests to jetty, classic.

$ apt-get install nginx jetty
$ cat /etc/nginx/sites-available/domainname.conf
server {
          listen          80;
          server_name     domainname;

          location /app {
                proxy_pass http://localhost:8080/app
          }
  }

$ find /usr -name '*jetty*'
...
/usr/share/java/jetty-6.1.24.jar
/usr/share/jetty
...
$ ls /usr/share/jetty/webapps /etc/init.d/jetty /etc/jetty
$ diff -u prev /etc/default/jetty
- NO_START=1
+ NO_START=0

-#JAVA_OPTIONS="-Xmx256m -Djava.awt.headless=true"
+JAVA_OPTIONS="-Xmx256m -Djava.awt.headless=true -XX:PermSize=64m -XX:MaxPermSize=128m"

$ /etc/init.d/jetty restart
$ /etc/init.d/nginx restart

Later you will want to add "-Drun.mode=production" to the JAVA_OPTIONS in /etc/default/jetty but for now let's keep running in development mode.

After running jetty for a while, you might get a blank page and see java.lang.OutOfMemoryError: PermGen space exceptions in the log file. Adding "-XX:PermSize=64m -XX:MaxPermSize=128m" to the JAVA_OPTIONS many times solve the issue.

Latest versions of jetty can be downloaded from the eclipse foundation. Installation is as simple as unpacking the file and updating the different files in /etc/init.d/jetty and /etc/jetty. It is also interesting to see how to embed jetty into your application, a method also shown on Lift download page.

Installing Lift "helloworld"

The dependencies for the helloworld are quite a few versions behind and some point you will want to update the pom.xml file in order to pull newer Lift and Scala versions. It is especially useful to check the versions listed in the pom.xml in order to read the appropriate online documentation.

For now we are just interested to get the development cycle started so let's go.

$ sudo apt-get install maven2
$ mvn archetype:generate -U -DarchetypeGroupId=net.liftweb \
    -DarchetypeArtifactId=lift-archetype-blank \
    -DarchetypeVersion=1.0 \
    -DremoteRepositories=http://scala-tools.org/repo-releases \
    -DgroupId=demo.helloworld -DartifactId=helloworld \
    -Dversion=1.0-SNAPSHOT
$ cd helloword
$ mvn package
$ cp ./target/helloworld-1.0-SNAPSHOT.war /usr/share/jetty/webapps
$ wget http://hostname/app/helloworld-1.0-SNAPSHOT/

Even though you can use Maven, of course, Scala comes with its own builder tool sbt. I never had so much issues related to differences between tool versions than with sbt. None-the-less I have recently learned that a lot people keep trying to push Scala builds through sbt because of the incremental compiler feature.

Lift

Lift is a web application framework that does not use the embed-code-inside html templates implementation. Instead the templates are clean xml/html documents with code decorators. That is nodes like <div class="lift:mycode"></div> will be replaced by a DOM element generated by a mycode.scala object.

It is important to understand that historically Lift was heavily relying on well-formed xhtml. As html5 picked up a lot more steam and now is prevalent, Lift adapted. Still you will have to make sure to add the following code into your Boot.scala to switch Lift's default behavior. Otherwise you might be up for a ride figuring out why mycode never gets called and lift just outputs <div class="lift:mycode"></div> instead.

LiftRules.htmlProperties.default.set((r: Req) =>
  								new Html5Properties(r.userAgent))

Exploring Lift and Simply Lift are two different books useful to start using Lift. Later you will want to directly go to the reference APIs (Just make sure you read through the reference matching the Lift version specified in the pom.xml).

Printf debugging

A lot of times, the easiest way to get into a new framework and understand new tools is to print text into a log file. The following code will do and you should see "Creating MyService at" popping up in the jetty log.

class MyService {
  val logger = Logger(classOf[MyService])
  logger.info("Creating MyService at %s".format(new _root_.java.util.Date))
}

Accessing CGI parameters

There are a lot of fancy and powerful ways to bind Scala variables and html form parameters within Lift. None-the-less if some of your webiste is running outside Lift, you will want to use the tried and simple way.

class MyService {
  def render(in: NodeSeq): NodeSeq = {
    for {
      r <- S.request if r.post_? // make sure it's a post
      name <- S.param("name")
    }
	{
      S.notice("Name: "+ name)
    }
	error
  }
}

Sending emails

Exploring Lift - Annex F is pretty useful to get started and the Mailer reference API will help solve inconsistencies. This is also a really cool article on emailing and texting with Lift.

Authentication

Under the title How to use Container Managed Security, you will find a very good article on single sign on.

Relative paths

In many cases part of the site you implemented using the Lift framework (Great!) and some part of the site you relied on other apps (modx, redmine) that come with their own web framework using a variety of programming languages. If you are trying to keep sane while maintaining a consistent look-and-feel, you might decide to put the css, javascript and images at a central place, most likely directly accessible through the front-end web server (nginx here). As the HTTP request and response go through the whole stack, absolute paths have a tendency to be rewritten and an html file with code like:

<link type="text/css" rel="stylesheet" href="/css/style.css">

ends up looking something like this when finally making it to the browser:

<link type="text/css" rel="stylesheet" href="/app/css/style.css">

The solution that seems to work in all cases with all frameworks is to always use relative paths instead of absolute references such as for example:

<link type="text/css" rel="stylesheet" href="../css/style.css">

Scala

Once you are done copy/pasting code around and got your basic Lift application working, you will want to investigate more time in understanding Scala itself. There is a good introduction here. If you are using Lift and Scala for web applications you will most likely be required to understand XML support at some point. There are also some useful resources for being quickly productive: scala collections for the easily bored, Scala/Lift.

A lot of the Scala testing frameworks build upon the Java ones in a way or another. You can check ScalaCheck and ScalaTest for unit testing, scct for code coverage. Developers on large Scala source base recommend to shy away from Specs because of the number of class files it produces, turning testing into a data management problem.

When comes the time to seriously write Scala code, there is no alternative than installing the emacs scala-mode on my MacBook.

$ port install scala29
$ /opt/local/share/scala-2.9/misc/scala-tool-support/emacs
$ diff -u prev ~/.emacs
+(add-to-list 'load-path "/opt/local/share/scala-2.9/misc/scala-tool-support/emacs")
+(require 'scala-mode-auto)

Last piece of advice I glanced from experience Scala developers was to use tail recursion (optimizer hint: @tailrec) instead of closures whenever possible.

by Sebastien Mirolo on Wed, 2 Nov 2011


Receive news about DjaoDjin in your inbox.

Bring fully-featured SaaS products to production faster.

Follow us on