Tutorial: Scala, SBT, Servlets, IntelliJ, ScalaTags

Note, this tutorial describes the steps that I performed, but I don’t know whether these steps are *the best way* to do it.

Introduction

IDE

IntelliJ and Scala IDE are probably the best known Scala IDEs. Scala IDE is a preconfigured version of Eclipse, and is freely available.
Over the years, IntelliJ gained a lot in popularity and has surpassed NetBeans. IntelliJ comes in two editions: Community Edition (free) and Ultimate Edition (commercial, only free for educational purposes).

SBT

SBT (officially written in lowercase) stands for “Simply Build Tool“, but according to some people, SBT is every but simple, but it is considered to be very powerful.

Although it is possible to use Maven for Scala projects, SBT is considered The Build tool for Scala. Internally SBT uses Apachy Ivy, a tool that has dependency management like Maven and integrates with Apache ANT.

Scala & ScalaTags

Although Scala has a high learning curve, the power/flexibilty of the Scala language makes it suitable to create nice api’s. Some api’s are such clean that instead of creating a text based template framework to write web pages, you can write the web page directly in Scala without sacrificing readability. A big drawback of text based template frameworks is that they usually aren’t object oriented: you pass data from a web controller to a template. Passing data around in code isn’t considered object oriented but more a procedural style of programming. Also, text based template frameworks limit your flexibility in creating all kinds of code structures. ScalaTags is a small and fast library to write HTML is plain Scala, giving you all the flexibility to create your own code structures.

Servlets & Tomcat

Servlets is the standard technology in the Java enterprise world to create web applications. Many Java webframeworks are written upon servlets. Servlets can run in special servlet containers, such as the Tomcat webserver. Jetty is another popular servlet webserver, especially when it comes to embedding webservers in applications instead of the more standalone Tomcat. Note that a relatively high number of Scala web frameworks don’t support servlets, and instead run on embedded fast lightweight webservers, such as Spray and Netty.

Specs/Test setup

The versions of some components probably don’t matter much. But this tutorial might differ for IntelliJ 13. If possible try to have a good combination of Scala, xsbt-web-plugin, Scala plugin. (Not sure which ones are “good” but this one works for me.)

I don’t know if this process differs for IntelliJ Community Edition instead of the Ultimate Edition.

About the tutorial

This tutorial assumes that you haven’t installed Java, Scala, SBT and IntelliJ yet.

If you get strange Scala code warnings, try: “File” > “Invalidate Caches/Restart“.

Light gray indented text in this blog post is background information and is not required to read to follow this tutorial steps.

Install Java

IntelliJ by itself doesn’t require Java to be installed, but your IntelliJ projects do if you want o compile, debug and run them.

Download and install Java SE JDK from the Oracle website.

Install Tomcat

Download and unzip Tomcat as a zip file from from http://tomcat.apache.org. You don’t need a Windows Service, just the zip is enough.

If you want to use a service, then the deployment steps to put your project into Tomcat, differs.

Start IntelliJ

Download and install IntelliJ.

Start IntelliJ. On first run, it will ask you to customize IntelliJ (skin, ui Theme, plugins etc.). I choose “Skip All and Set Defaults” (for the sake of this tutorial).

Configure Java in IntelliJ and info about defaults settings

After starting IntelliJ, it will show the “Welcome to IntelliJ IDEA” start screen, where you can open projects. (If you don’t see the welcome screen, but immediately get a full blown IDE, you can go back to the welcome screen via: “File” > “Close Project“.

JVM based IntelliJ projects usually need a SDK assigned to be able to compile, debug and run applications as well as for “the standard SDK classes resolution“. SDK stands for Software Development Kit. JDK is an SDK.

First we need to add JDK as a SDK to IntelliJ at global (IDE) level. (This is even needed for Scala projects.)

Choose “Configure” > “Project Defaults” > “Project Structure“.

This window shows settings that are by default shared by all projects.

Choose “SDKs” > “+” > “JDK” > and select the root of the directory where you have installed the JDK that you want to use.

(Note that you don’t select a “JRE” but a “JDK“. When installing a JDK, Java by default also installs a JRE.)

Install Scala Plugin

By default, IntelliJ doesn’t install Scala support, so we first have to install the Scala plugin.

Go back to the welcome screen > Choose “Configure” > “Plugins“.

IntelliJ will show all installed plugins.

Choose “Browse repositories” > search for a plugin named “Scala” and install that plugin.

According to the “Scala” plugin description, it also supports SBT. There also exists a third party “SBT” plugin (version 1.6.1, 2014-05-14), but we don’t use that one in this tutorial.

Restart IntelliJ.

(This will probably activate the plugin.)

Creating a SBT project

Choose “Create new Project” > select “Scala” then “SBT” (this will create a “SBT-based Scala project“) > “next” > Choose a “Project name” and “Project location“, for example “scalaweb” and “c:scalaweb“. The “Project SDK” setting should have a JDK selected, if not, select one. In my case ‘1.8 (java version “1.8.0_25”)‘ is selected. Then choose “Finish” and IntelliJ opens the IDE and the project.

You would probably expect that the project would configure Scala and SBT for you, otherwise it would ask for it, right? Wrong. At this moment, it’s a bit clear what the *correct* workflow is. Currently, the project only consist of some files and has project structure settings with no Scala or SBT configured, and you have access to the “SBT” window (via icon in the lower left > “SBT“).
There are multiple ways to configure SBT/Scala in the project, but each can have different outcomes with possible Scala version conflicts and project errors etc.What works for me is this:

Open /build.sbt and DON’T CLICK in the “Import project: File ‘C:/scalaweb/build.sbt’ seems to be SBT build file, but there is no external project related to it. Import the corresponding project?“. Just leave the “Import project” prompt open for the moment, otherwise it might configure your project to a random Scala version (2.10.4 in my case).

SBT is able to automatically download a specific Scala for you. SBT stores Scala somewhere in the C:UsersYOUR_USER_NAME.ivy2 directory.

Now write the Scala version in build.sbt, so that SBT will use that version and subsequently, the Scala plugin will use that version. In my case, I changed build.sbt to:

name := "YOUR_PROJECT_NAME"

version := "1.0"

scalaVersion := "2.11.4"

(Note that the empty lines are required in SBT.)

After setting the Scala version, click “Import project” button/link from the “Import project” dialog.

The Scala plugin will then perform a lot of magic (see progress in the bottom of IntelliJ), such as letting SBT download the correct Scala version using Ivy. The Ivy repository located in C:UsersYOUR_USER_NAME.ivy2.

Wait till the process is finished.

After the plugin is finished with your project, a number of things have changed in the Project Structure settings:
-A second module was added: “scalaweb-build“, next to the already existing “scalaweb” module. “scalaweb-build” contains SBT specific configuration, while “scalaweb” contains more Scala/Java specific configurations.
-For the modules: source locations were added, compilation output paths changed, SBT Scala libraries added and SBT plugins as library dependencies were added.
-scala-libary was added as a “libary“.
-“Scala compile server” was enabled.

Next, Scala source files should be put in /src/main/scala/, so manually create that directory via IntelliJ.

Enable Servlets for SBT

Next, we need to add the required library dependencies to work with servlets, and we need to configure SBT to generate a war content structure.

While Maven officially supports Java war/web projects, SBT relies on third party plugins. A SBT plugin that is listed at the official SBT website and able to generate war files is “xsbt-web-plugin“.

Install xsbt-web-plugin:

Open /project/plugins.sbt and modify the file to:

logLevel := Level.Warn

addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "1.0.0")

(Empty new line is required.)

Next, add Servlet libary dependencies:

Open /build.sbt and modify the content to:

name := "YOUR_PROJECT_NAME"

version := "1.0"

scalaVersion := "2.11.4"

libraryDependencies ++= Seq(
  "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided"
)

Everytime you modify /build.sbt, you need to refresh the IntelliJ project:

Hover on the lower left square symbol in IntelliJ > “SBT” > click the refresh button to refresh the SBT project.

Next, we need to configure an IntelliJ “artifact” so that later, we can add the artifact to Tomcat:

Choose “File” > “Project Structure” > “Artifacts” > “+” > “Web application: Exploded” > the artifact will be named “unnamed” by default. Then click the “Output Layout” tab > under “Available Elements” right-click “YOUR_PROJECT_NAME” (in my case “scalaweb“) > “Put into output Root“.
Repeat the same for “scalaweb-build“.
Finish

(Not sure if both “scalaweb” and “scalaweb-build” are required. But couldn’t get it fully working without both, the last time I tried.)

Creating an sample servlet

Under /src/main/scala, create the file “MyServlet.scala” with the following content:

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

@WebServlet(Array("/"))
class MyServlet extends HttpServlet {
  override def doGet(req: HttpServletRequest, res: HttpServletResponse) {
    val writer = res.getWriter
    writer.write("<html><body>Hello World!</body></html>")
    writer.close()
  }
}

This will create a Servlet that is mapped under the “/” uri.

Starting Tomcat via IntelliJ

Now we can start Tomcat and the project:
Choose “Run” > “Edit Configurations…” > “+” > “Tomcat Server” > “Local“.
Then “Configure” > add the Tomcat server for “Tomcat Home“.
Then “Deployment” tab > “+” of “Deploy at the server startup” > “Artifact” > finish.

Now start the server via: “Run” > “Run ‘unnamed‘” (“unnamed” is the default name of the Tomcat configuration).

Tomcat boots up and should show “Artifact unnamed: Artifact is deployed successfully” in the output.

Try http://localhost:8080/ under a browser to see if you get to see “Hello World!“.

You can close the server using the red square in the left of IntelliJ.

Using ScalaTags

First we need to add a dependency to ScalaTags.
Modify /build.sbt, change:

libraryDependencies ++= Seq(
  "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided"
)

to

libraryDependencies ++= Seq(
  "javax.servlet" % "javax.servlet-api" % "3.1.0" % "provided",
  "com.scalatags" %% "scalatags" % "0.4.2"
)

Because ScalaTags is a dependency that was built with sbt, you can use a double “%%” to let sbt get a version of ScalaTags that was built with the same version of Scala as defined in /build.sbt. If your /build.sbt Scala version is newer than the latest ScalaTags Scala version, then you need to change the version, see: http://www.scala-sbt.org/0.13/docs/Library-Management.html

Remember to reload the project using the SBT window in IntelliJ.

As a ScalaTag example, we’re going to write a Servlet that shows a list of people names (firstname and lastname) followed by a HTML form that allows us to add additional names to the list using a HTTP POST request.

Put the following code in /src/main/scala/MyServlet.scala:

import javax.servlet.annotation.WebServlet
import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import scala.collection.mutable.ListBuffer
import scalatags.Text.all._

@WebServlet(Array("/"))
class MyServlet extends HttpServlet {
  private case class Person(firstName: String, lastName: String)

  private val people = ListBuffer[Person]()

  override def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    renderPage(res)
  }

  override def doPost(req: HttpServletRequest, res: HttpServletResponse): Unit = {
    val firstName = req.getParameter("FirstName")
    val lastName = req.getParameter("LastName")

    if (firstName != null && lastName != null) {
      people += Person(firstName, lastName)
    }

    renderPage(res)
  }

  private def renderPage(res: HttpServletResponse): Unit = {
    val writer = res.getWriter
    writer.write(createTemplate.toString)
    writer.close()
  }

  private def renderPerson(person: Person) =
    div(backgroundColor:="yellow", border:="1px solid black", marginBottom:="5px",
      div("Firstname: ", person.firstName),
      div("Lastname: " , person.lastName)
    )

  private def createTemplate =
    html(
      head(

      ),
      body(
        h1("List of people"),
        for (person <- people) yield renderPerson(person),
        fieldset(legend("Add a new person"),
          form(method:="POST",
            div("Firstname: ", input(`type`:="text", name:="FirstName")),
            div("Lastname: ", input(`type`:="text", name:="LastName")),
            input(`type`:="submit")
          )
        )
      )
    )
}

Try it out and have fun 🙂