Chapter 11. Modules and deployment

This chapter covers

  • Using modules and creating your own
  • Publishing your modules
  • Splitting your application into multiple sub-applications
  • Deploying your application
  • Configuring the production environment

Now that we’ve seen how to do a lot of things for ourselves in Play, it’s time to see 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.

11.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 them a lot of time and stop them re-inventing the wheel. In chapter 2, we saw how we could use build.sbt to add a dependency on any library to use any Java library, just as you normally would. But Play provides an additional form of code reuse 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 commonly used module and, later on, how to build one yourself.

We’ll show you how to use the SecureSocial module. Another module that is frequently used is the Mailer[1] module, which, as you might guess from the name, allows you to send email.

1 https://github.com/typesafehub/play-plugins

11.1.1. Using modules

Play modules are, just like any other library, a collection of files in a JAR. The difference is that there will be some Play-specific non-class files in this JAR and that the code depends on Play. This means that you add a module to your project the same way you add any other library: you add it to libraryDependencies in build.sbt.

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 modules that are available in the Play 2 modules directory.[2]

2 http://www.playframework.com/documentation/2.1.1/Modules

If we search for “social” on that page, we’ll find a module named SecureSocial which seems to fit the bill.[3] Each module’s entry shows a URL and a short description. We can now follow the URL to find out how to use the module. The entry for SecureSocial points you to the module’s website.[4] Once you navigate to the installation instructions, you’ll have to add a dependency and a resolver. A resolver is how we tell SBT where to look for libraries that can’t be found in the default repositories.

3 SecureSocial is for authentication (logging in). It works well in combination with the Deadbolt 2 module, which does authorization (permission checking).

4 http://securesocial.ws/

Let’s get started. Open build.sbt and add the new dependency to library-Dependencies and the resolver in the project settings. Your build.sbt should now look like the following listing:

Listing 11.1. The build properties—build.sbt
ame := "warehouse"

version := "1.0-SNAPSHOT"

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "com.google.guava" % "guava" % "14.0",
  filters,

  "securesocial" %% "securesocial" % "master-SNAPSHOT"
)

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

play.Project.playJavaSettings

If you were already in the Play console, you’ll want to let SBT know about your changes by running the reload command. This will make SBT 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 (using idea for IDEA, eclipse for Eclipse) so that your IDE knows about the module.

To use SecureSocial, we need to disable the CSRF filter we added in chapter 10. This is easily done by commenting out the following filters line in our Global.java file:

public <T extends EssentialFilter> Class<T>[] filters() {
//Class[] filters={CSRFFilter.class,BasicAuthenticationFilter.class};
  Class[] filters={};
  return filters;
}

Now we can start using the module in our application. According to the documentation, SecureSocial provides an annotation @SecureSocial.SecuredAction that we can use to secure our action methods. It also adds a user to the current context, which tells us the current user.

Changing our application so that the user has to log in via OAuth is now a simple matter of annotating our actions in all the relevant places. This would be all the actions in the Products controller. For example:

import import securesocial.core.java.SecureSocial;
....

public class Products extends Controller {
...
  @SecureSocial.SecuredAction
  public static Result newProduct() {
    return ok(details.render(productForm));
  }
...
}

Running the application after this change would probably fail, since there are still a couple of things we need to provide. First, SecureSocial requires us to provide an implementation of UserService; this is what SecureSocial delegates to in order to store and retrieve users. Listing 11.2 shows a simple implementation that stores everything in memory.

Listing 11.2. Simple UserService—app/utils/SimpleUserService.java

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

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=/signin
    ssl=false
}

To fully use SecureSocial, you’ll need to configure some provider such as Twitter. We’ll skip this step but feel free to refer to the SecureSocial documentation to add your tokens against Twitter, for example.

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

include "securesocial.conf"

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

GET /signin  securesocial.controllers.LoginPage.login
GET /logout securesocial.controllers.LoginPage.logout
GET /authenticate/:provider
 securesocial.controllers.
   ProviderController.authenticate(provider)
POST /authenticate/:provider
 securesocial.controllers.
    ProviderController.authenticateByPost(provider)
GET /not-authorized
 securesocial.controllers.ProviderController.notAuthorized
# User Registration and password handling
# (only needed if you are using UsernamePasswordProvider)
GET /signup
 securesocial.controllers.Registration.startSignUp
POST /signup
 securesocial.controllers.Registration.handleStartSignUp
GET /signup/:token
 securesocial.controllers.Registration.signUp(token)
POST /signup/:token
 securesocial.controllers.Registration.handleSignUp(token)
GET /reset
 securesocial.controllers.Registration.startResetPassword
POST /reset
 securesocial.controllers.Registration.handleStartResetPassword
GET /reset/:token
 securesocial.controllers.Registration.resetPassword(token)
POST /reset/:token
 securesocial.controllers.Registration.handleResetPassword(token)
GET /password
securesocial.controllers.PasswordChange.page
POST /password
 securesocial.controllers.PasswordChange.handlePasswordChange

If you point your browser to http://localhost:9000/products/new or if you click on the New Product button, you should now see a login page.

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 to build one for yourself.

11.1.2. Creating modules

Creating a Play module is as easy as making a Play application. In fact, that’s how you start 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 of this module to add bar code images to any page by simply including a tag. Run the following command:

play new barcode

Now that you have a new application, can now remove everything in public and the sample controller and view. You should also remove application.conf since configuration, if any, will be done from the application using our module.

Write the code

We said we wanted our user[5] to be able to add a bar code image by including a 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.

5 Our user, in this case, is another developer who will add this module as a dependency to their project.

But first, we’ll need something to create our bar code images for us. We’ll use a library aptly named barcode4j. Go ahead and add the dependency to build.sbt:

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "net.sf.barcode4j" % "barcode4j" % "2.1"
)

Now, let’s create the controller. Though a controller for a module is just like a controller in a regular application, putting it in the controllers package isn’t a good idea: it might clash with our users’ controllers. Therefore, let’s make a package: com.github .playforjava.controllers.

Let’s start with the view. Create a file barcode.scala.html in app/views/tags and add the following:

@(ean: String)
<img class="barcode" alt="@ean" src="@routes.Barcodes.barcode(ean)">

Including the controller part is less straightforward; were we to put our controller in app/controllers, like we’ve been doing until now, things might break, because someone might add the same controller name. Let’s make a package com.github .playforjava.barcodes.controllers for our controller that’s unlikely to clash with anything in a regular Play application, and put the controller there. Create the directory structure for the package, and create the class shown in the following listing there.

Listing 11.3. app/com/github/playforjava/barcodes/Barcodes.java

Clashing package names

Play encourages the use of short package names, like controllers and models. 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, they 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.

For modules, our advice is to name your packages like we’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 with you because you made them waste their time.

The Barcodes controller contains a single action, barcodes(), that utilizes barcode4j to generate a bar code image. Of course, we need to provide a route to it. Because we provide the routes through a module, we need to create a new routes file called barcode .routes in the config directory. This will allows us to identify the routes file and import the routes from another application. We’re going to remove the “/barcode” prefix from the route, since the importing application can provide its own prefix when it imports the route. The route will therefore look like this:

GET /:ean
 com.github.playforjava.barcodes.Barcodes.barcode(ean: String)

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

Publish

Since Play uses Maven/Ivy repositories to get its dependencies, that’s what we’ll have to publish to. Fortunately SBT can produce the necessary files for us. It uses appName in build.sbt 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.

...

    organization := "playforjava"

...

Now we just need a place to publish to. If you already have a repository that you want to publish to, you can tell SBT 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:

...

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.

You might not have a publicly accessible Maven or Ivy repository to publish to. That’s okay; we 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, it only takes a few steps.

Setting up a repository

GitHub has a feature that allows you to publish a website as a sub-domain of github.com, called Pages. Their documentation[6] explains how to set up either a User/Organization Pages site or a Project Pages site. 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.

6 http://pages.github.com

Let’s get started with a User/Organization Pages site. According to GitHub’s instructions, we’re supposed 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.io appended. For this book’s Pages site, that would be playforjava.github.io. 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://playforjava.github.io/ 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 Git 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://playforjava.github.io/some-repo if the repo is called some-repo. Since this new branch has nothing to do with your other branches, you’ll want to start the gh-pages branch with an orphan commit. An orphan commit is a commit with no parents—you won’t see anything connected to this commit below it in the commit log. Furthermore, 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

Since git creates the new branch with the current checkout as its basis and puts its contents in the index, you’ll want to remove everything by issuing the following:

git rm -f .

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 the 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, SBT will publish the module to your local Ivy cache. Now it’s simple to create a new project and include our module. Let’s quickly create this project and test our module:

play new module-test

Add a dependency to the module in build.sbt:

...

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "playforjava" %% "barcode" % "1.0-SNAPSHOT"
)
...

Import the module’s route by adding the following line at the end of your conf/routes.conf file:

-> /barcode barcode.Routes

The following listing shows the template index.scala.html, which uses the tags/barcode template that we created earlier.

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

@main("Welcome to Play") {

    @tags.barcode("1234567890128")

}

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. Figure 11.1 shows a bar code generated by our application.

Figure 11.1. Generated bar code

Now that we know our module works, we can finally publish it.

Publishing the 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. Since, in our example, we have to publish to a Git repository, 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 (or SBT, if you prefer) 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. The following listing shows what the final version of build.sbt looks like.

Listing 11.5. build.sbt
name := "barcode"

version := "1.0-SNAPSHOT"

organization := "playforjava"

publishTo := Some(Resolver.file("Our repository",
        new File("/Users/sietse/playforjava.github.com")))

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "net.sf.barcode4j" % "barcode4j" % "2.1"
)

play.Project.playJavaSettings

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, since we never updated the version number, we’ve published a snapshot version. This has a 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.

11.2. Splitting your application into multiple sub-applications

When projects grow, or if the application scope requires a large team, it’s better to split your application up into several smaller applications. Having several small applications allows you to distribute the work better and helps to ensure that each single application stays simple and manageable. This is where Play sub-applications come in handy.

A sub-application is a Play application within a Play application. It’s time to give you an overview on how this works and how you can structure your project. Let’s pretend that our application needs to be handled by two different teams: Team A will take care of the product details while Team B will handle the reports. We therefore need two sub-applications inside our application: the report application and the product application.

Application dependencies are declared in the build.sbt file at the root of the project. A sub-application is also called a sub-project. Our current main application is going to be shared by both sub-applications. Both the report and product applications depend on some common libraries as well. The common libraries include the model classes that are shared between all the sub-applications. The build.sbt file with the two sub-projects and the common library have extra lines, as shown in the followng listing.

Listing 11.6. Directory structure of our application and sub-applications

The aggregate() function is important, as it tells the build system to automatically recompile a sub-application if one changes. The depends() function indicates that one project depends on another project and thus compilation of the other project must happen first. Also, the classes from the other project are made available after compilation.

Our directory structure looks like the following listing.

Listing 11.7. Directory structure of our application and sub-applications

You can switch from one sub-application to another using the Play console. For example, project report allows you to switch to the report project:

$ play
[info] Loading project definition from /ch11.2/project
[info] Set current project to warehouse (in build file:/ch11.2/)
       _
 _ __ | | __ _ _  _
| '_ | |/ _' | || |
|  __/|_|\____|\__ /
|_|            |__/

play 2.2.0 built with Scala 2.10.2 (running Java 1.6.0_65),
http://www.playframework.com

> Type "help play" or "license" for more information.
> Type "exit" or use Ctrl+D to leave this console.

[warehouse] $ project report
[info] Set current project to report (in build file:/ch11.2/)

To list all the sub-applications, use the projects command. You can then select a project using the project [name] command. Then use the normal Play commands to compile, test, or start the project (test, run, and so on).

Each sub-project contains a build.sbt file that can contain its own dependencies, as explained in chapter 2. More interesting, you can also import all the routes from your sub-applications into the main application. This works in exactly the same way as for modules, as explained in section 11.1.2.

For example, to add all the routes from the report sub-application, you’d add the following line your main routes file:

->  /report    report.Routes

This means that the sub-application routes are made available at http://localhost :9000/report from the main application. It’s also important to notice that the reversed route will be controllers.report.routes.Report.index(). The assets—the public folder from the sub-application—can also be accessed using the same pattern: controllers.report.routes.Assets.at("...").

We now have a complete overview on how we could split up our applications to satisfy larger team or application complexity.

11.3. Deploying to production

Finally you’re done. Your Play application is done, it’s great, and it’ll rule the world. That’s when you realize you’re not 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.

11.3.1. Packing up your application

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 production mode, a new JVM is forked for your application, and it runs separately from SBT. You can still see your application’s logging output to verify that it started correctly. When you’ve seen enough, type Ctrl-D, and the SBT process will terminate but leave your application running. You can stop this application with play stop.

Though play start starts your application in the proper mode, it’s often still not a suitable way of starting your app. It requires interaction to detach and end the SBT 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, 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.

Play doesn’t support Windows in dist mode

Unfortunately, Play doesn’t support Windows while working in production mode. This is because running a Windows service is not at all comparable to running a background process on a Unix-based environment. For this reason, the stage and dist tasks won’t work on Windows.

The dist task does something similar, and zips up the start script and dependencies into a file. After running play dist, you get a directory dist, which 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 particularly 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.

11.3.2. Working with multiple configurations

During development, you only need a single application configuration in the file conf/application.conf. But 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 see how we can configure the production environment separately.

At first you expect to avoid this issue by 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 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 the moment when 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 running tests.

Suppose your application sends email notifications to users. 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 override the default test configuration in their development environment, perhaps to send all email notifications to their own email address. Developers can create their own conf/development.conf and override the 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. This 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 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.

Make sure to add conf/development.conf to the .gitignore file, or whatever your version control system uses to specify files that aren’t under version control, so that one developer’s configuration doesn’t affect anyone else’s development environment.

Finally, we have to set up the production environment configuration. In this case, including a file that overrides the default settings, like 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 "application.conf"

email.override.enabled=false

This time, the file starts by loading the default configuration in application.conf as a resource from the deployment archive, which is followed by the production environment 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.

11.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. So 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.

11.3.4. Setting up a front-end proxy

Generally, web applications are run on port 80. This is a 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 do 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 that 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 are explained in chapter 9), so we must make sure that these connections are properly proxied as well.

This can be accomplished with a configuration file as shown in the following listing:

Listing 11.8. 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, for example for logging purposes. That’s why we set the forwardfor option , which makes HAProxy add a header X-Forwarded-For that 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. The following listing shows a typical Apache configuration.

Listing 11.9. 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 the following listing.

Listing 11.10. 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. So for 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.

11.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. This 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 will 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 is not 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 will create a certificate and send it back to you, together with root and intermediate certificates. Finally, you 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. You need to set https.keyStore to point to your key store, and set 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.keyStore-Password are not configuration settings but Java system properties.

11.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 or 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 the provider, 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.

11.3.7. Deploying to an application server

Play is a full-stack framework; a Play application can be deployed without the need of 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, 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. So make sure you check the compatibility matrix on the plugin’s web page to determine whether your application and server will match.

11.4. Summary

In this chapter we’ve learned how to include a module in an 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 now know how to publish a module so that others can use it.

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

In the next chapter, we’ll see how we can test our modules and applications.

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

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