Search form

You are here

Tutorial: Getting started with scala and scalatra - Part IV

By jos.dirksen on Fri, 10/05/2012 - 14:07

Welcome to the last part of this series of tutorials on scala and scalatra. In this part we'll look at how you can use Akka to handle your requests using an asynchronous dispatcher, how to use subcut for dependency injection and finally how you can run the complete API in the cloud. In this example I've used openshift from JBoss to run the API on JBoss Application Server 7.1. Now what have we seen in the previous tutorials:

The examples in this tutorial assume you've completed the previous three tutorials. We won't show all the details, but focus on adding new functionality to the existing application (from part III). To be precise in this example we'll show you the following steps:

First, we'll introduce subcut to the application for dependency injection

Next, we'll make our requests asynchronous by using Akka's futures

Fiinally, we'll enable CORS, package the application and deploy it to openshift

And we'll have an API we can call on the openshift cloud.

Let's start with subcut

Adding dependency injection to the application

In java there are many dependency injection frameworks. Most people have heard of Spring and Guice and dependency injection even has its own JSR and specifications. In scala, however, this isn't the case. There has been lots of talk whether scala application need a DI framework, since these concepts can also be applied using standard Scala language constructs. When you start investigating dependency injection for Scala you'll quickly run into the cake pattern (see here for a very extensive explanation). I won't go into the details why you should or should not use the cake pattern, but for me personally it felt like it introduced too much cruft and glue code and I wanted something simpler. For this article I'm going to use subcut. Subcut is a really small and simple to use framework, which makes using DI in scala very easy and unobtrusive.

Nothing works like examples. So what do you need to do have subcut manage your dependencies. First of, we of course need to nicely separate our implementation from our interface/trait. In part III we create a set of repositories which we used directly from the scalatra routes by creating them as class variables:

This not only adds the subcut dependencies, but also the akka onces we'll see further in this article.

Bind implementations to a trait

Bindings in subcut are defined in a binding module. So by extending a module you create a configuration for your application. For instance you could define a configuration for test, one for QA and another one for production.

// this defines which components are available for this module// for this example we won't have that much to inject. So lets// just inject the repositories.
object ProjectConfiguration extends NewBindingModule(module =>{importmodule._// can now use bind directly// in our example we only need to bind to singletons, all bindings will// return the same instance.
bind [BidRepo] toSingle new BidRepository
bind [ItemRepo] toSingle new ItemRepository
// with subcut however, we have many binding option as an example we bind the keyrepo and want a new// instance every time the binding is injected. We'll use the toProvider option for this
bind [KeyRepo] toProvider {new KeyRepository}})

Without diving too deep into subcut. What we do in this code fragment is that we bind an implementation to a trait. We do this for all the resources we want to inject, so subcut knows which implementation to create when it encounters a specific interface. If we want to inject different implementations of a specific trait we can also add an id to the binding, so we can uniquely reference them.

Configure classes that need to have resources injected

Now that we have a set of traits bound to an implementation we can let subcut inject the resources. For this we need to do two things. First we need to add an implicit val to the HelloScalatraServlet class.

This needs to be added to all classes that want to have there resources injected by subcut. With this implicit value subcut has access to the configuration and can use it to inject dependencies. We've defined our routes in the RESTRoutes trait, so lets look at how we configure this trait to work with subcut:

trait RESTRoutes extends ScalatraBase with Injectable {// simple logger
val logger = Logger(classOf[RESTRoutes]);// This repository is injected based on type. If no type can be found an exception is thrown
val itemRepo = inject[ItemRepo]// This repo is injected optionally. If none is provided a standard one will be created
val bidRepo = injectOptional[BidRepo] getOrElse {new BidRepository};
...
}

We added the Injectable trait from subcut so we can use the inject functions (of which there are multiple variants). In this example the itemRepo is injected using the inject function. If no suitable implementation can be found an error message is thrown. And the bidRepo is injected using injectOptional. If nothing was bound, a default is used. Since this trait is used by the servlet we just saw (the one with the implicit bindingmodule) it has access to the binding configuration and subcut will inject the required dependencies.

Bootstrap the 'root' object with our configuration

All we need to do now is tell our root object (the servlet) which configuration it should use, and everything will be wired together. We do this from the generated Scalatra listener, where we add the following:

Here we create the bindingModule, which is implicitly passed into the constructor of the HelloScalatraServlet. And that's it, when you now start the application, subcut will determine which dependency needs to be injected. And thats it. If we now start the application subcut will handle the dependencies. If all goes well, and all dependencies are found, the application will start up successfully. If one of the dependencies can't be found an error will be thrown like this:

Add asynchronous processing with Akka

Akka provides you with a complete Actor framework you can use to create scalable, multi-threading applications. Scalatra has support for Akka out of the box, so getting it to work is very easy. Just add the correct trait, wrap functions with the Future function and you're pretty much done. All the action happens in the RESTRoutes trait where we've defined our routes. Lets enable a couple of these methods to use Akka.

Not much too see here. We just added the AkkaSupport trait and wrap our method body with the Future function. This will run the code block asynchronously. Scalatra will wait until this block is done, and return the result. One thing to note here, is that you don't have access to the request context variables provided by scalatra. So if you want to set the response content-type you need to do this outside the future. The same goes for instance for accessing parameters or the request body.
All you need to do now is setup an Akka ActorSystem. The easiest way to do this, is by just using the default actor system. See the Akka documentation for the advanced options.

class HelloScalatraServlet(implicit val bindingModule: BindingModule)extends ScalatraServlet with Authentication
with AkkaSupport
with RESTRoutes {// create a default actor system. This is used from the futures in the web routes
val system = ActorSystem()}

Now when you run the servlet container you'll be using Akka futures to handle the requests.

Add CORS and deploy on the cloud

As a final step lets add CORS. with CORS you can open up your API for use from other domains. This avoids the need for JSONP. Using this in scalatra is suprisingly simple. Just add the trait CorsSupport and you're done. You'll see something like this, when you start the application:

You can fine tune what you support by using a set of init parameters explained here.

Now all that is left is to package everything up, and deploy it to openshift. If you haven't done so already, register on openshift (it's free). For my example I use a standard "JBoss Application Server 7.1" application, without any cartridges.

I didn't want to configure postgresql, so I created a dummy repo implementation:

You'll probably see something similar, and now you're done. Or at least, almost done. Cause what happens when you access a resource:

Hmm.. something went wrong. This is the message that's interesting to us:

java.lang.IllegalStateException: The servlet or filters that are being used by this request do not support async operation

Hmmm.. apparently JBoss AS handles servlets a bit different from Jetty. The reason we see this message is that by default, according to the servlet 3.0 spec, servlets aren't enabled to support async operations. Since we use Akka Futures as a result for our routes, we need this async support. Normally you enable this support in a web.xml or using annotations on a servlet. In our case, however, our servlet is started from a listener:

override def init(context: ServletContext){// reference the project configuation, this is implicatly passed into the // helloScalatraServlet
implicit val bindingModule = ProjectConfiguration
// Mount one or more servlets, this will inject the projectconfiguration
context.mount(new HelloScalatraServlet, "/*")}

Context.mount is a convenience method provided by scalatra that registers the servlet. However, this doesn't enable async support. If we register the servlet ourself we can enable this async support. So replace the previous function with this function:

About me

My name is Jos Dirksen. I'm an enterprise architect, working for Malmberg. My focus areas are HTML5, SOA, governance, ESBs, integration, REST and quality. I've written three books. Two for Manning and one for Packt. I frequently talk about my interests on conferences and workshops.