Chapter 9. Play and more

This chapter covers

  • Using modules and creating your own
  • Publishing your modules
  • Using plugins
  • Deploying your application
  • Configuring the production environment

Now that we’ve taught you how to do a lot of things for yourself in Play, it’s time to show you how to use code that others have made. This chapter explains how to use Play modules, but also how to create your own and publish them so that others can use them. The second half of the chapter deals with how to deploy your application to production on your own machines or in the cloud. It also explains how to set up a front-end proxy and use SSL.

9.1. Modules

Any kind of serious software development project will use libraries to decrease the effort required from developers. JVM developers have access to a large body of libraries that can save developers a lot of time and stop them from reinventing the wheel. Play provides the same kind of thing in the form of modules. Currently available modules for Play 2 provide anything from alternate template engines to NoSQL database layers. This section will explain how to use a common module and, later on, how to build a module yourself.

9.1.1. Using modules

Play modules are, like any other library, a collection of files in a JAR. This means that you add a module to your project the same way you add any other library: you add it to appDependencies in project/Build.scala.

Let’s say we want our application’s users to log in and, later, possibly allow them to log in with OAuth. If we can find a module that allows us to do this, we won’t have to waste time writing our own code. You can find a comprehensive list of available modules in the Play 2 modules directory (www.playframework.com/documentation/2.1.x/Modules).

If we search for “social” on that page, we’ll find a module named SecureSocial, which seems to fit the bill. Each module’s entry shows a URL and a short description. We can now visit the URL to find out how to use the module. The entry for SecureSocial points you to the module’s website.[1] Once you navigate to the installation instructions, you’ll see you have to add a dependency and a resolver.

1 http://securesocial.ws/ by Jorge Aliss, a.k.a. @jaliss

Play uses sbt (www.scala-sbt.org/), which is a build tool for Scala. The play command is actually a wrapper around sbt. A resolver is how we tell sbt where to look for libraries that can’t be found in the default repositories.

Let’s get started: make a copy of the sample project in chapter 2, and add the dependency and resolver. Open project/Build.scala and add the new dependency to appDependencies and the resolver in the project settings. We’re also adding the barcode4j dependency, because we’ll need it later in this chapter. Your Build.scala should now look like listing 9.1:

Listing 9.1. The build properties—Build.scala
import sbt._
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

  val appName         = "product-details"
  val appVersion      = "1.0-SNAPSHOT"

  val appDependencies = Seq(
    "net.sf.barcode4j" % "barcode4j" % "2.0",
    "securesocial" %% "securesocial" % "2.1.0"
  )

  val main = PlayProject(appName, appVersion,
    appDependencies, mainLang = SCALA
  ).settings(

    resolvers += Resolver.url("SecureSocial Repository",
      url("http://repo.scala-sbt.org/scalasbt/sbt-plugin-releases/")
    )(Resolver.ivyStylePatterns)
  )
}

If you were already in the Play console, you’ll want to let it know about your changes by running the reload command. This will make it reread all the files that make up the project’s configuration. If you’re using an IDE with a Play-generated project, you should also regenerate the project (idea for IDEA and eclipse for Eclipse) so that your IDE knows about the module.

Now we can start using the module in our application. According to the documentation, SecureSocial provides a replacement for Action called SecuredAction. This method acts the same way as Action, except that it first checks whether the user is logged in and redirects to a login page if necessary. It also adds a user property to the request, which we can inspect to find out who the user is.

Changing our application so that the user has to log in via OAuth should be easy: just replace Action with SecuredAction in all the relevant places. This would be all the actions in the Application and Products controllers. For example,

Running the application after this change would probably fail, because we still need to provide a couple of things. First, SecureSocial requires us to provide an implementation of UserService, which is what SecureSocial delegates to in order to store and retrieve user identity details. Listing 9.2 shows a simple implementation that stores these details in memory.

Listing 9.2. UserServiceapp/utils/SimpleUserService.scala

Second, we have to provide some configuration to tell SecureSocial what we want it to do. SecureSocial comes with a bunch of optional plugins[2] that help it do its job, so we’ll have to create a conf/plugins with the following contents:

2 Plugins are classes that a module can use to run code at application startup and shutdown. Section 9.2 explains more about them.

For now, we’ll just set up SecureSocial to use email and password for logins; this is why we’re only enabling a couple of the available plugins. When you’re building your own applications, you can follow SecureSocial’s instructions to set up OAuth with one or more of the OAuth providers it supports.

Now we can create the file conf/securesocial.conf with the following contents:

userpass {
    withUserNameSupport=false
    sendWelcomeEmail=false
    enableGravatarSupport=false
    tokenDuration=60
    tokenDeleteInterval=5
    minimumPasswordLength=8
    enableTokenJob=true
    hasher=bcrypt
}

securesocial {
    onLoginGoTo=/
    onLogoutGoTo=/login
    ssl=false
    sessionTimeOut=60
    assetsController=controllers.ReverseMyCustomAssetsController
}

We’re putting the SecureSocial configuration in a different file to keep it separate from the application’s normal configuration. If you prefer to keep it in conf/application.conf, that’s fine too.

In order for Play to load the settings in this file, it needs to be included from the application’s configuration file. Put the following line in conf/application.conf:

include "securesocial.conf"

Now we just need to add some routes so that our users can actually log in. For this example, we’ll add the login and logout routes:

GET /login  securesocial.controllers.LoginPage.login
GET /logout securesocial.controllers.LoginPage.logout

We now have a complete working example that shows how to use just one of a large number of useful modules. Unfortunately, you’ll have to figure out for yourself how to use any of the other available modules, if you need them.

Now that we know what a module looks like from an application developer’s perspective, let’s look at how you can build one for yourself.

9.1.2. Creating modules

Creating a Play module is as easy as making a Play application. In fact, that’s how you start with a new module—you create a new Play application as the starting point.

Let’s create a bar code module. This module will allow a user to add bar code images to any page by simply including a tag.

play new ean

You can now remove everything in app/public, app/views, and the sample controller (app/controllers/Application.scala). You should also remove conf/application.conf because configuration, if any, will be done from the application.

Write the code

We said we wanted our user[3] to be able to add a bar code image by including a template tag in a page. This means our module will need a tag that renders an HTML img element, a controller that renders a bar code, and a route that will connect the tag’s img element with the bar code controller.

3 Our user, in this case, is another developer who will add this module as a dependency to their Play application

If you followed along in chapter 2, you’re probably thinking we can use the controller and template from the application we built there. Let’s start by making a copy of the template: copy barcode.scala.html from app/views/tags in the sample application to the same place in your new module.

Including the controller is less straightforward; were we to put our controller in the controllers package, as we’ve been doing until now, things might break. Let’s make a package, com.github.playforscala.barcodes, that’s unlikely to clash with anything in a regular Play application and put the controller in it. You can create the directory structure for the package or just drop Barcodes.scala directly in app or app/controller; the Scala compiler doesn’t care that a class’s package structure doesn’t match the directory structure.

The new controller in listing 9.3 is a slight variation on the one in listing 2.22.

Listing 9.3. Controller—app/com/github/playforscala/barcodes/Barcodes.scala
package com.github.playforscala.barcodes

import play.api.mvc.{Action, Controller}
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider
import org.krysalis.barcode4j.impl.upcean.EAN13Bean
import util.{Failure, Success, Try}

object Barcodes extends Controller {

  val ImageResolution = 144

  def barcode(ean: Long) = Action {

    val MimeType = "image/png"
    Try(ean13BarCode(ean, MimeType)) match {
      case Success(imageData) => Ok(imageData).as(MimeType)
      case Failure(e) =>
        BadRequest("Couldn't generate bar code. Error: " +
            e.getMessage)
    }
  }

  def ean13BarCode(ean: Long, mimeType: String): Array[Byte] = {

    import java.io.ByteArrayOutputStream
    import java.awt.image.BufferedImage


    val output = new ByteArrayOutputStream
    val canvas =
      new BitmapCanvasProvider(output, mimeType, ImageResolution,
        BufferedImage.TYPE_BYTE_BINARY, false, 0)

    val barCode = new EAN13Bean
    barCode.generateBarcode(canvas, String valueOf ean)
    canvas.finish()

    output.toByteArray
  }
}

Clashing package names

Play encourages the use of short package names, like controllers and models in Play applications. This is perfectly fine if the source code you’re writing never leaves your premises. But this becomes a problem when you write code to be used by other developers—especially if you stick to Play’s default package names like controllers and models. Not only do you run the risk of causing name clashes with the developer’s code, but in Play particularly, developers can end up with two different controllers.routes classes, which will definitely break things in ways that make it difficult to figure out what’s wrong.

Because Scala allows relative imports,[4] you can cause the developer even more trouble. For instance, if you call your module’s top-level package data, and the developer imports play.api.data before importing your module’s code, they’re going to be confused when the compiler says object YourType is not a member of package play.api.data. In a case like this, the compiler is saying that it assumes that data is the one imported earlier. So don’t do this.

4 import java.io; import io.File imports both java.io and java.io.File.

For modules, name your packages like you’ve always done in the JVM world: use the reverse notation of a domain (and path, if necessary) that you control. This way you won’t leave your users confused or worse—annoyed because you made them waste their time.

Now we add the bar code route in config/routes. We’re going to remove the /barcode prefix from the route because the importing application can provide its own prefix when it imports the route. We’ll explain that in the “Testing your module” section. The route will therefore look like this:

GET /:ean   com.github.playforscala.barcodes.Barcodes.barcode(ean: Long)

That’s it; we have a module that provides bar code rendering functionality for any Play application that needs it. We can now take a look at how to publish our module.

Publish

Because Play uses Maven or Ivy repositories to get its dependencies, we’ll have to publish to one of those. Fortunately Play can produce the necessary files for us. It uses appName in Build.scala as the artifactId and groupId. This isn’t usually what we want, so we’ll add an organization property to the build settings in the same file:

...
val main = play.Project(appName, appVersion, appDependencies).
  settings(
    organization := "playforscala"
)
...

Now we need a place to publish to. If you already have a repository that you want to publish to, you can tell Play where it is by setting the publishTo key and, if necessary, your credentials with the credentials key. Assuming your repository is at http://maven.example.com/releases and you call it My Maven repository, this is how you’d set it up:

...
val main = play.Project(appName, appVersion, appDependencies).
  settings(
    publishTo := Some("My Maven repository" at
      "http://maven.example.com/releases"),
    credentials += Credentials(Path.userHome / ".repo-credentials")
)
...

In this example, ~/.repo-credentials is a properties file with the following properties: realm, host, user, and password.

Another way of adding your credentials is to do it directly in a .sbt file with the following syntax:

credentials += Credentials("Repository Realm",
  "maven.example.com", "username",
  "hashed-password")

Replace the credentials in the example as appropriate.

Some of you won’t have a publicly accessible Maven or Ivy repository to publish to. That’s okay; you can use something like GitHub. Apart from providing a place to host your git repositories, GitHub makes it easy for anyone to have their own website, and if you don’t need anything fancy, there are just a few steps.

Setting up a repository

GitHub has a feature that allows you to publish a website as a subdomain of github.com, called Pages. Their documentation explains how to set up either a User/Organization Pages site or a Project Pages site (http://pages.github.com). Which one you choose doesn’t matter for the purposes of this book, since how we’ll be using it doesn’t change much. Which one you choose for the modules you’ll be publishing (very soon, no doubt) is wholly up to you and depends on the particulars of your situation.

Let’s get started with a User/Organization Pages site. GitHub’s instructions are to create a new repo and give it the same name as the user or organization (depending on the type of account the site is for) with .github.com appended. For this book’s Pages site, that would be playforscala.github.com.

Once you’ve pushed something to your new repo—an index.html for instance—you’ll be able to point your browser to “your” site (http://playforscala.github.com/ in our example) and see the result. You might have to wait a couple of minutes, according to GitHub’s instructions, before your site is actually up and running.

If you want to create a Project Pages site, you have to create a new branch called gh-pages in the corresponding GitHub repo and put your site’s files in that branch. These pages will show up as a new subdirectory under your .github.com site; for example, http://playforscala.github.com/some-repo if the repo is called some-repo.

Because this new branch has nothing to do with our other branches, we’ll want to start the gh-pages branch with an orphan commit. An orphan commit is a commit with no parents—we won’t see anything connected to this commit below it in the commit log. Further, there’ll be no connections between this branch and the other branches—there won’t be any shared history between them. You can make this commit with the following command:

git checkout --orphan gh-pages

git creates the new branch with the current checkout as its basis and puts its contents in the index, so we’ll want to remove everything by issuing this command:

git rm -rf .

Everything we commit to the gh-pages branch and push to GitHub will show up on the Pages site.

Now that we have a place to publish our module, we need to start thinking about testing the module in its intended environment—another Play application. We wouldn’t want to publish a buggy module, would we?

Testing your module

It’s probably a good idea to test our module, in the environment of a Play application, before we release it to the world. Fortunately, this is easy to do. If you run the publish-local command, Play will publish the module to its local repository. Note that if you’re running sbt directly (as opposed to using the play command), it’ll publish to the default local repository—normally ~/.ivy2/local for Ivy.

Let’s quickly create a new project and test our module:

play new module-test

Add a dependency to the module in project/Build.scala:

...
val appDependencies = Seq(
  "playforscala" %% "ean-module" % "1.0-SNAPSHOT"
)
...

Import the module’s route by adding the following line to conf/routes.conf:

-> /barcode barcode.Routes

Listing 9.4 shows the new version of the template

Listing 9.4. Bar code template—app/views/index.scala.html
@(message: String)

@main("Welcome to Play 2.0") {
    @tags.barcode(1234567890128l)
}

If we run our test application and point our browser to it, we can see that our module does what it’s supposed to do. Now that we know our module works, we can finally publish it.

Include a sample application

It’s a good idea to include a sample application with your module. This way the developers using your module have an example of how to use it.

Publishing your module

We’ve made a module, tested it, and set up a repository where we can publish it. The next step is actually publishing the module. In our example, we are publishing to a Git repository, so the process will consist of generating the necessary files, copying them to the repository, committing the changes, and pushing them to GitHub.

The Play console can generate the files for us, and if we configure it correctly, it can put the files in the right place for us. If we add the right publishTo setting in our project’s settings, Play will write the files to our Pages repo clone and we’ll just need to commit and push. Listing 9.5 shows what the final version of project/Build.scala looks like.

Listing 9.5. project/Build.scala
import sbt._
import Keys._
import play.Project._

object ApplicationBuild extends Build {

  val appName         = "ean-module"
  val appVersion      = "1.0-SNAPSHOT"

  val appDependencies = Seq(
    "net.sf.barcode4j" % "barcode4j" % "2.0"
  )

  val main = play.Project(appName, appVersion, appDependencies).
    settings(
      publishTo := Some(Resolver.file("Our repository",

        new File("/Users/paco/writing/playforscala.github.com"))),
      organization := "playforscala"
  )
}

Be sure to replace the path of the publishing repo with your own. Now, if we issue the publish command in the Play console, commit, and push the changes in the Pages repo, we’ll have published our module.

Note that because we never updated the version number, we’ve published a snapshot version. This has a very specific meaning in the world of Maven artifacts, and no sane project will rely on snapshot versions other than for development and testing. If you’re happy with the state of your module, update the version to 1.0 or any version number you like (without the -SNAPSHOT part) and publish that. Don’t forget to increment the version number and add -SNAPSHOT back afterward, lest you release a development version with an already existing production version number.

9.2. Plugins

Play provides a play.api.Plugin trait, specifically for modules to initialize themselves. This way you can add useful functionality to your module that’s performed at startup. Note that Plugin is only really useful for modules, because a Global object in a Play application can do anything a Plugin can do.

The Plugin trait has three methods: onStart, onStop, and enabled. The first two are called on application startup and shutdown, respectively, but only if the plugin is enabled. For a plugin to be enabled, two conditions have to be met: a line for the plugin in conf/play.plugins (either the module’s or the application’s) has to be present, and the plugin’s enabled method has to return true. This means that you can “enable” your plugin in your module’s play.plugins file and provide the user with a more convenient way to really enable the plugin, in application.conf, for instance.

Let’s build a plugin for our module. Let’s say we want to cache our generated bar codes, and for some reason we don’t want to use Play’s built-in cache. We’ll have to make our own cache and we’ll need a plugin to initialize it. In order to avoid suffering from some typical caching issues, our cache will need the features described in table 9.1.

Table 9.1. Bar code cache features

Feature

Explanation

Concurrent calls should be handled concurrently When the system is rendering a bar code for an earlier request, the next request shouldn’t have to wait for the first to be finished
Multiple calls for the same bar code should cause no more than one cache miss Two or more requests for the same bar code shouldn’t cause the system to render it more than once, even if they arrive in quick succession

In order to satisfy those requirements, we’ll use an actor. A Scala actor is an entity that has private state and can receive concurrently sent messages and act upon them sequentially. This helps us satisfy the requirement that the same bar code may not be generated more than once, even if the requests for it arrive in quick succession.

But this seems to defeat the concurrency requirement. We can solve that by making sure that the actor doesn’t render the bar codes itself but creates a Future to render each bar code. This way the actor can handle each request as quickly as possible and not be blocked while rendering the bar codes. This leads to the interesting consequence of having to store not the images themselves, but futures that will compute (or already have computed) a bar code image.

The next question is: how will we send the rendered bar code to the client once it’s been generated? We can’t have the actor wait for it to be done, because it would only be able to render one bar code at a time if we did that. The easiest solution is to have the future’s onComplete send the rendered image to the client. Note that “client” in this context isn’t the end user’s browser, but a piece of code in our module that requests the bar code to be rendered for the controller.

For clarity, let’s summarize how our cache will be implemented. Our cache will be an actor that contains a store of futures of rendered bar code images. It’ll handle each request for a bar code consecutively, retrieving the future of the image corresponding to the requested bar code from its store, or creating (and storing) it if it’s not found. Afterward it adds an onComplete function that sends the rendered image to the client. That last bit works for two reasons: you can add as many onComplete functions as you like—they will all be called when the future is completed—and you can add them even if the future is already completed.

Now we’re ready to look at the implementation; see listing 9.6.

Listing 9.6. app/com/github/playforscala/barcodes/BarcodeCache.scala

In an actor, the receive method is a partial function that’s called for each message that’s sent to the actor. As you can see, we only check for the RenderImage message; if any other message is sent to the actor, it does nothing with it and just continues. This is a normal way for actors to behave.

Another interesting thing happens at the end of the receive method. The sender method returns the current message’s sender; if this method is called outside of the context of the current invocation of receive, we’ll probably end up with the wrong sender or no sender at all. Note that the anonymous function passed to onComplete won’t be run until the future is done rendering the image and, in any case, it’s run outside of its current context by definition. This is why we store the sender for later use in client.

Now look at the anonymous function itself: client ! RenderResult(_). Yes, that’s a method with a funny name; we use a ! to send a message to an actor (or, in this case, the original sender of the message we’re processing). This method is also called tell; you can use that instead of ! if you prefer. Here we’re sending the result of the future wrapped in a RenderResult message.

You’re probably curious about the sender by now. Let’s take a look at listing 9.7.

Listing 9.7. app/com/github/playforscala/barcodes/Barcodes.scala

The Barcodes object will be our interface to the bar code cache. The barcodeCache property will contain a reference to the BarcodeCache actor once our plugin is initialized. We’ve already seen how we can send messages with !; now we want to send a message and receive a response. To do that, we use ? (which you can replace with ask if you want) to send the message. This tells Akka that we expect a response. The response is delivered as a Future.

Let’s see what this means for the controller: see listing 9.8.

Listing 9.8. app/com/github/playforscala/barcodes/

Basically, our barcode action does something similar to what the non-caching version does: it asks for the bar code to be rendered and creates an appropriate Result depending on whether rendering the bar code was successful. The main differences are that now it’s dealing with a Future that should be “mapped” into the right kind of thing for an action to return—a Result—and all the logic is encapsulated in an Async call. Async wraps the Future[Result] in an AsyncResult, which is itself a Result. This is useful because Play knows that an AsyncResult is something that’s being handled on a different thread and may or may not be ready by the time Play gets its hands on it. The result is that each AsyncResult is put aside until it’s finished, and Play can send the response back to the client. This means that an AsyncResult will never block any of the threads that are handling requests. This is one of the reasons Play scales so well.

Earlier we saw that the barcodeCache actor reference in our Barcodes object is left uninitialized. This is where our plugin comes in. It will be responsible for initializing the actor reference when the application starts up. Listing 9.9 shows what the plugin looks like.

Listing 9.9. .../playforscala/barcodes/BarcodesPlugin.scala

As you can see, a Plugin contains three methods. The first method to be called is enabled, and if this method returns false, none of the others are ever called. Our version simply returns true, but you could have it check the configuration to determine its return value. This way you could ship the plugin completely set up, but still provide the user with a convenient way of turning the plugin on or off in the application’s configuration settings.

The onStart and onStop methods are called when the application starts up and shuts down respectively. Our plugin asks Play’s Akka system for an ActorRef instance to a BarcodeCache actor and stores it in the Barcodes object.

There’s one more thing to do to make the plugin work. In order for Play to find the plugin, it must be configured in a file called conf/play.plugins. This also works in modules. In our example, it would contain one line, like this:

1000:com.github.playforscala.barcodes.BarcodesPlugin

The format is simple: one line for each plugin, with a priority and the fully qualified name of the Plugin class separated by a colon. The priority determines the order in which the plugins are initialized, with lower numbers being first. We now have a version of our module that caches the images it renders.

Be careful with this strategy

Note that this implementation of a specialized cache might not be appropriate for all circumstances. If you’re going to implement something like this, you’ll have to think about how this architecture will affect your production environment and adapt accordingly.

For instance, if your application is going to get hit with a lot of requests for different bar codes simultaneously, you’re going to fill up the default thread pool—which might slow things down in the rest of the application. You might want to use a separate thread pool for your bar code Future objects. If your application runs on multiple servers for performance reasons, you might want to use Akka’s distributed features to run one instance of the BarcodeCache actor that all application instances will talk to.

9.3. Deploying to production

Finally you’re finished. Your Play application is done, it’s great, and it’ll rule the world. That’s when you realize you’re not actually done yet. Your application still needs to be deployed to production.

There are various ways to do that. You might want to deploy your application standalone on your own server, or maybe on the infrastructure of a cloud provider. If you’re in an enterprise Java environment, chances are that you want or need to deploy on an application server.

In this section, we’ll go through the various options and help you decide which way is best for you.

9.3.1. Production mode

When you use play run, your application is started in development mode. This is unsuitable for running your application in production, because at each request Play checks whether any files are changed, greatly slowing down your application.

As a better alternative, you can use play start. This will start Play in production mode. In this mode, a new JVM is forked for your application, and it’s running separately from the play command. You can still see your application’s logging output to verify that it started correctly. When you’ve seen enough, press Ctrl-D, and the play process will terminate but leave your application running. Your application’s process ID is written to a file RUNNING_PID.

You can stop this application with play stop. This will send the SIGTERM signal to your application’s process. You can do the same manually by looking up the process ID in RUNNING_PID and then sending it the signal with the kill command.

Although play start starts your application in the proper mode, it’s often not a suitable way of starting it. It requires interaction to detach and end the play process from your application. Generally, you’ll want your application to start without human intervention. Also, you may not always have the play command available on the machine where you want to deploy.

For this situation, Play provides the stage and dist tasks. When running play stage, Play compiles your application to a JAR file, and—together with all the dependency JARs—puts it in the target/staged directory. It also creates a start script in target/start.

With this script, you can start your application without the play command. Just running target/start will start your application.

The dist task does something similar; it zips up the start script and dependencies into a file. After running play dist, you get a directory dist that contains a zip file with your application. You can transfer this zip file to the server where you want to deploy, unzip it, and run the start script that’s contained in the zip file. You might need to make the start script executable first with chmod +x start.

The stage and dist commands make extremely nice distributions. All your dependencies are packed with your application, including Play and Scala. This means that the only thing you need on the target machine is a Java installation. This makes an application packaged with the dist command extremely portable.

9.3.2. Working with multiple configurations

During development, you only need a single application configuration in the file conf/application.conf. When you deploy to production, you need to be able to use different configuration settings. This applies to settings that are either machine- or environment-specific, such as directory paths, and to sensitive information such as database passwords. In this section, we’ll look at how we can configure the production environment separately.

At first, you might expect to avoid this issue by simply deploying the application and then editing the configuration by hand. This doesn’t work, or is at least inconvenient, because the application is packaged in a JAR file. Besides, modifying the distributed application is error-prone and less convenient to automate.

Don’t use the same credentials for your production database

You might not be the first person to consider the “pragmatic” solution of just using the same settings for development, test, and production environments, to avoid the need for separate configurations. This seems like a good idea right up until a team member mistakenly thinks he’s logged into a development environment and deletes the entire production database. If you use different database credentials for each environment, perhaps adding test or dev to user names, then you have to try a lot harder to make this kind of mistake.

What you need is a default application configuration that’s “safe” for the test environment. A safe configuration is one that won’t cause unwanted side effects when you do things like run tests.

Suppose you’ve built email notifications into your application. In the test environment, it would be useful to configure the application to override the recipient email address, and use a safe email address like [email protected] instead. Put the following in conf/application.conf:

mail.override.enabled = true
mail.override.address = "[email protected]"

include "development.conf"

The first two lines of this configuration override email recipient addresses, making the application send all notifications to one address, [email protected], so that continuous integration doesn’t mean continuous spam for your system’s real users.

The last line includes settings from another configuration file in the same directory called development.conf. This allows each developer to create their own conf/development.conf and override the default test configuration. For instance, they can override the email address to send all email notifications to their own email address. Be sure to add this file to .gitignore or your source control system’s equivalent.

mail.override.address = "[email protected]"

This configuration overrides the earlier test environment configuration in application.conf. It works because if the application configuration contains the same setting twice, the second value overrides the first. Note that the developer doesn’t have to override the email.override.enabled setting, because it’s already set to true in the default test environment configuration.

A nice thing about the configuration library is that the configuration doesn’t break if the development.conf file doesn’t exist; the library just silently ignores it. This means developers don’t have to provide their own overrides if they don’t need to, perhaps because they’re not working on email notifications.

Finally, we have to set up the production environment configuration. In this case, including a file that overrides the default settings, as we just did with development.conf, isn’t such a good idea because there will be no error if the file is missing. In addition, the file location might not be known in advance, often because the production configuration file is in a different directory on the server (keeping production database passwords safe from developers).

For production, then, we can use a separate /etc/paperclips/production.conf configuration file:

include classpath("application.conf")
email.override.enabled=false

This time, the first line of the file loads the default configuration in application.conf as a resource from the deployment archive. Subsequent lines in the file are the production environment settings that override the previous settings. To use the production configuration instead of the default configuration, specify the file as a system property when starting the application:

play "start -Dconfig.file=/etc/paperclips/production.conf"

In this case, you’ll get an error if the file is missing.

(Starting server.
Type Ctrl+D to exit logs, the server will remain in background)

Play server process ID is 61819
Oops, cannot start the server.
Configuration error:
Configuration error[/etc/paperclips/production.conf:
/etc/paperclips/production.conf (No such file or directory)]

Alternatively, instead of -Dconfig.file, you can use -Dconfig.url to load the configuration file from a remote location.

9.3.3. Creating native packages for a package manager

A zip file may be pretty universal, but the operating system you intend to deploy on likely has a more advanced package management tool. If you’re using Debian or Ubuntu or a derivative, an apt package is more appropriate, whereas many other Linux distributions use rpm packages.

You can package up your application as one of these packages. The sbt plugin sbt-native-packager helps you create these deb and rpm packages as well as Homebrew packages that can be used on Mac OS X, and MSI packages for Windows. This plugin is powerful, but it’s a plugin for sbt and not specific for Play. It’ll require some thought and effort to make packages for your Play application.

There are also somewhat more specialized plugins built upon the sbt-native-packager plugin. The play2-native-packager plugin builds deb packages for Debian or Ubuntu, and the play2-ubuntu-package plugin builds lightweight deb packages designed specifically for recent versions of Ubuntu.

9.3.4. Setting up a front-end proxy

Generally, web applications are run on port 80. This is a so-called privileged port on Unix machines, which means that programs running under a regular user account can’t bind to such a port. This explains why Play doesn’t use port 80 as the default port number, but something else.

Of course, you can tweak the permissions so that it’s possible to run your Play application on port 80, and let it serve web traffic directly. But the common way to let your application be available on port 80 is to set up a front-end proxy, like HAProxy, nginx, or even Apache. This proxy will bind to port 80 and redirect all traffic intended for your Play application, which listens to an unprivileged port.

The use of a proxy isn’t limited to making the application available on a specific port. It can also provide load balancing between multiple instances of your application. You can, for example, run two instances of your application and let the front-end proxy divide traffic between the two instances. This means you’re not bound to a single machine; you can utilize multiple machines for your application.

It also gives you the ability to do upgrades without downtime. If you have a front-end proxy doing load balancing between two application instances, you can take one instance down, upgrade it, and bring it back up, all without downtime. When the upgraded instance is up, you can do the same to the other one. When done, you’ve upgraded your application with zero downtime for your clients.

HAProxy is a powerful and reliable proxy that has a plethora of advanced options, but is still easy to get started with.

Suppose we want to set up HAProxy to listen on port 80, and redirect traffic to two instances of our Play application. We’ll also use WebSockets in this application (these will be explained in chapter 10), so we must make sure that these connections are properly proxied as well.

This can be accomplished with a configuration file as shown in listing 9.10.

Listing 9.10. HAProxy configuration

Here we set up HAProxy to listen to port 80 , and use the playapp back end as the default back end for incoming traffic . The playapp back end is configured to contain two servers: one listening on port 9000 , and the second one on port 9001. The check option in the server lines causes HAProxy to periodically try to establish a TCP connection to the back-end server to see if it’s up. If it’s not up, no requests will be sent to that server.

HAProxy creates the connection to the Play applications, so from the Play application’s perspective, HAProxy is the client. It’s often useful to have the original client’s IP address as well in the Play application, such as for logging purposes. That’s why we set the forwardfor option , which makes HAProxy add a header, X-Forwarded-For, which contains the original client’s IP address, to the request.

Finally, because we want to use WebSockets, we set the http-server-close option , which makes HAProxy close the connection to Play after each request. This prevents a new WebSocket connection from being sent to the server over an existing TCP connection, which doesn’t work.

Apache is the most commonly used web server, and it also has proxy capabilities. It doesn’t support WebSockets, but that’s not a problem if your application doesn’t use them. If you’re already using Apache, it might be interesting to stick to using Apache as a proxy, to reduce the number of different components in your architecture. Listing 9.11 shows a typical Apache configuration.

Listing 9.11. Apache front-end proxy configuration
<VirtualHost example.com:80>
  ServerName example.com
  ServerAdmin [email protected]

  ErrorLog /var/log/apache2/example.com-error.log
  CustomLog /var/log/apache2/example.com-access.log combined

  ProxyRequests     Off
  ProxyPreserveHost On
  ProxyPass         / http://localhost:9000/
  ProxyPassReverse  / http://localhost:9000/


  <Proxy http://localhost:9000/*>
    Order deny,allow
    Allow from all
  </Proxy>

</VirtualHost>

This example sets up a front-end proxy for the site example.com, and proxies requests to localhost on port 9000.

Apache, like HAProxy, is also capable of load balancing between multiple back-end servers. For this, we slightly change the configuration, as shown in listing 9.12.

Listing 9.12. Apache front-end proxy and load-balancing configuration

If you’re trying to run multiple instances of your application from the same directory, you’ll get an error: This application is already running (Or delete /path/to/RUNNING_PID file). This is caused by each instance wanting to store its own process ID in the RUNNING_PID file.

You can change the file where Play stores its process ID with the pidfile.path setting. Here’s an example:

target/start -Dhttp.port=9001 -Dpidfile.path=PID_9001

If you set the pidfile.path to /dev/null, no PID file will be created.

9.3.5. Using SSL

Starting with version 2.1, Play supports SSL. It uses the libraries in java.security to read a private key and certificates from a key store.

Play can automatically generate a key store for you with a self-signed certificate, which is useful in development mode. All you need to start experimenting with SSL is to set the https.port system property:

play -Dhttps.port=9001 run

This will start your application, and it’ll listen on port 9000 for HTTP traffic, as well as on port 9001 for HTTPS traffic. If you point your browser to https://localhost:9001/, you should get a warning that the certificate isn’t trusted. This is expected, because you don’t have a certificate signed by a trusted certificate authority yet. But during development it’s safe to ignore this, and allow this certificate in your browser.

The generated key store is saved in conf/generated.keystore, and Play will reuse it if you restart your application so you don’t get the certificate warning again and again.

If you want to use SSL in production, you need to get a certificate that’s either trusted by your organization if it’s for an internal application, or one signed by an authority that’s trusted by major browser vendors if it’s to be used for a public application. These certificates can be bought from commercial vendors. The process likely involves generating a private key, creating a certificate signing request (or CSR), and sending the CSR to the certificate vendor. They’ll create a certificate and send it back to you, together with root and intermediate certificates. Finally, you’ll need to create a Java key store containing your private key, your generated certificate, and the root and intermediate certificates. Your certificate vendor should have instructions on how to do this.

Once you have a key store file with your key and certificates, you need to point Play to it. Set https.keyStore to point to your key store and https.keyStorePassword to your password:

play -Dhttps.port=9001 -Dhttps.keyStore=mykeystore.jks
  -Dhttp.keyStorePassword=mypassword run

Even though Play supports SSL, the recommended way to use SSL with Play in production is to let the front end—like HAProxy or Apache—handle it.

Configuration settings versus system properties

Note that http.port, https.port, https.keyStore, and https.keyStorePassword aren’t configuration settings but Java system properties. This is because these system properties configure the runtime, not your application.

9.3.6. Deploying to a cloud provider

Deploying a Play application isn’t hard. The target and dist commands package your application with all dependencies, and to run it you only need Java. But you’ll still need to set up a front-end proxy. You’ll also need scripts to start your application when the machine reboots, and a place to store the logs.

There are service providers that take even these concerns away. Platform as a service providers like Heroku, Cloudbees, or Cloud Foundry allow you to upload your Play application to them, and their system will manage starting it and upgrading it without downtime. Those platforms have a web interface to manage basic application properties like domain name, and they provide a range of additional services like database instances and logging systems. Finally, they can easily spawn more instances of your application when there’s a lot of traffic, and scale down when it gets quieter.

In short, if you want to minimize the effort of running and scaling your application, these providers are an excellent choice.

Each of these providers works a little differently from the others, but the main idea is the same. You install a command-line tool from your provider of choice, and you use this to upload your application to the platform. The command-line tool also allows you to check the status of your application, restart it, retrieve the logs, and so on.

9.3.7. Deploying to an application server

Play is a full-stack framework; a Play application can be deployed without the need for an application server or Servlet container, unlike most other Java web frameworks.

If you work in a big organization that uses JVM technologies, chances are that all web applications are deployed on an application server, and that the only way that your precious Play 2 application will ever be allowed to hook up to the internet is through an application server.

This poses a problem, because Play doesn’t use the Servlet API, which makes it impossible to run on an application server that expects web applications to use it. Luckily, there’s a plugin for Play 2, the play2-war-plugin, that can package your application as a WAR. It provides a layer between the Servlet API and your Play application.

Some of the more advanced features of Play, like WebSockets, don’t work with all Servlet API versions, and there are also differences in the capabilities of Play 2.0 and Play 2.1. Make sure you check the compatibility matrix on the plugin’s web page to determine whether your application and server will match.

9.4. Summary

In this chapter, we’ve seen how to include a module in our application and how to use one popular module. We’ve extracted generic functionality from our original application and turned it into a module of our own. Furthermore, we looked at how to publish a module so that others can use it.

In the second half of this chapter, we looked at different strategies for deploying our applications to production and saw how to configure front proxies and use SSL. Finally, we’ve learned that several cloud providers support Play and that we can run our Play 2 application on an application server if necessary.

The next chapter will teach you how to use Play’s web service API to consume information from (other) web services, the iteratee library to deal with large streams of data and make your application more reactive, and WebSockets to allow bidirectional communication between server and client to create highly interactive web applications.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset