There are a handful of articles on how to build a module for version 2.x of the Play Framework. While those articles are an excellent starting point, they were lacking information on configuration, exposing a plugin, and publishing them to maven central. This post will explain how to build, maintain, publish, and use your Play Framework 2.x module in other projects.

Create your empty module project

The root project directory will be called play-module-twitter. Inside that directory there will be two sub-directories named module and sample. First, create your root project directory:

mkdir play-module-twitter
cd play-module-twitter

To create a Java-based module, do the following in your root project directory code>play-module-twitter :

play new module
What is the application name? [module]
> mfz-play-module-twitter
Which template do you want to use for this new application?
1 - Create a simple Scala application
2 - Create a simple Java application
> 2

Your root project directory will now contain a sub-directory called module and once you open your module project in your IDE it will be named mfz-play-module-twitter.

We will now do the same for the sample project that will demo the use of your module:

play new sample
What is the application name? [sample]
> mfz-play-module-twitter-sample
Which template do you want to use for this new application?
1 - Create a simple Scala application
2 - Create a simple Java application
> 2

Now will be the time to add any root project files such as your README.

touch README.md

Your project directory structure should now look like this:

play-module-twitter/
module/
sample/
README.md

Your module project/code can include almost anything a normal Play Framework project can such as controllers, views, models, and general Scala/Java code. Its primarily important to delete all configuration files so they aren't included in the final .jar -- since they will conflict with the projects that will use your module. I also like to delete any controllers, assets, tests, or views that are generally included with a standard Play project:

cd module
rm -Rf conf/* public/* test/* app/controllers app/views

Modify project for IDE and eventual publishing

Since I use Eclipse as my IDE for Play projects, I now like to create the Eclipse project with the command play eclipse.

Since modules should be published either locally or remotely so they can be used in your other Play projects, it's important to modify the project/Build.scala file to control how your artifact is published. This is how your current Build.scala file should look like:

By default Play will publish your artifact with an organization that matches your project name to your local/remote repository. If we were to play publish-local without modifying Build.scala, the artifact would be published to {play21 dir}/repository/local/play-plugin-twitter/play-plugin-twitter_2.10/1.0-SNAPSHOT/jars/play-plugin-twitter_2.10.jar. My organization can easily be set like so:

The artifact will now be published to {play21 dir}/repository/local/com.mfizz/mfz-play-plugin-twitter_2.10/1.0-SNAPSHOT/jars/mfz-play-plugin-twitter_2.10.jar. For Java developers familiar with Maven, you may wonder what the trailing "_2.10" is on your artifact -- it is added by Play's underlying use of SBT (simple build tool) to publish your library for use by a specific Scala version.

Write your module

You are now ready to start writing your module code. I put all my module code in a specific package to prevent conflicts with other modules. In the module/app directory, I create the following package com.mfizz.play.twitter.

Our project will include a few utility classes and one Play plugin named TwitterPlugin. This is the special class that will be loaded at startup by Play and configured via the application.conf config file. All the details of each file in the project won't be covered here since you can view the source at GitHub. We will just some of the more important aspects of writing a module that includes a plugin.

Add a plugin that's configured at startup

Plugins for play extend the class play.Plugin and can override the method onStart() which is run when Play starts/restarts. This is where the code will be added to configure TwitterPlugin from application.conf. Your constructor will be passed one parameter which is of type play.Application that you will want to save in your class.

Start a periodic job to refresh tweets

The onStart method in the plugin will also start a job that runs every configured refresh-interval to pull tweets from Twitter. If the api call fails, the existing tweets pulled from Twitter will remain in memory. The job consists of a class that implements Runnable and instructing Akka to run it periodically.

In Play (or really SBT since that's what Play uses for builds), you'll add the dependencies to your Build.scala file. Expanding on the example of Build.scala above, the appDependencies section now looks like:

Note that the % symbol between the organization and artifact name is used for Java (non-Scala) Maven-based dependencies. If you use double percentage symbols such as %% then Play will append "_2.10" onto the artifact name. A double percentage symbol %% will instruct Play's build system SBT to only use dependencies compiled for a specific Scala version such as 2.10.

Since we added new dependencies and we'd like our IDE to include them as references, you'll also need to re-run the command play eclipse and refresh your project to pick up the dependency changes.

Write a sample application to demo module

To speed up the code/run development cycle, its preferable to have the sample application depend on the module project so that code changes in either project will trigger re-compilation of both projects. Your sample Build.scala project will look like:

The two important changes are val module = RootProject(file("../module")) that uses a relative path and adding .dependsOn(module) to the play.Project. When you run your sample project with the command play run, notice that both projects are loaded:

~play-module-twitter/sample $ play run
[info] Loading project definition from /play-module-twitter/sample/project
[info] Loading project definition from /play-module-twitter/module/project
[info] Set current project to mfz-play-module-twitter-sample (in build file:/play-module-twitter/sample/)
--- (Running the application from SBT, auto-reloading is enabled) ---
[info] play - Listening for HTTP on /0:0:0:0:0:0:0:0:9000

To enable the plugin, add it to a new conf/play.plugins file:

1000:com.mfizz.play.twitter.TwitterPlugin

Note that you'll need to modify conf/application.conf with your Twitter api values for the sample app to run.

Assuming you've followed those instructions and have a username, password, central sync approval, and a PGP key properly setup, enabling your Play project module isn't too complicated. A helpful start for this article was locate here.

Verify your PGP key is setup:

gpg --list-keys

In your module's project directory, add addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8") to the project/plugins.sbt file. It will now look like this:

Sonatype requires a number of properties to be set before it will approve a release. These are added to the underlying "pom.xml" maven file which Play's build system SBT creates behind the scenes. You can add them by editing the Build.scala file. The new Build.scala file:

When you're ready to publish your module to Sonatype, run the command "play publish-signed" which will sign the artifacts using the PGP plugin and publish them to Sonatype. You'll then need to follow the instructions on Sonatype to close and release your artifacts.

Final thoughts

Your play2 framework module can include any number of plugins or utility classes. It can even include views, controllers, etc. that you may want to reuse in your own projects. You also may simply want to publish your module locally as well with the play publish-local command.