Play Framework: Introduction to Writing Modules

Exclusive offer: get 50% off this eBook here
Play Framework Cookbook

Play Framework Cookbook — Save 50%

Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework

£16.99    £8.50
by Alexander Reelsen | July 2011 | Java Open Source

The Play framework is the new kid on the block of Java frameworks. By breaking the existing standards it tries not to abstract away from HTTP as with most web frameworks, but tightly integrates with it. Modularity should be one of the main goals, when designing your application. This has several advantages from a developer's point of view: reusability and structured components are among them. A module in Play is basically just an application which can be included in your current application. This application-in-application architecture means that there are only very few differences between your application and the included module.

In this article by Alexander Reelsen, author of Play Framework Cookbook, we will cover:

  • Creating and using your own module
  • Building a flexible registration module

 

Play Framework Cookbook

Play Framework Cookbook

Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework

        Read more about this book      

(For more resources related to this subject, see here.)

Introduction

In order to get to know more modules, you should not hesitate to take a closer look at the steadily increasing amount of modules available at the Play framework modules page at http://www.playframework.org/modules.

When beginning to understand modules, you should not start with modules implementing its persistence layer, as they are often the more complex ones.

In order to clear up some confusion, you should be aware of the definition of two terms throughout the article, as these two words with an almost identical meaning are used most of the time. The first is word is module and the second is plugin. Module means the little application which serves your main application, where as plugin represents a piece of Java code, which connects to the mechanism of plugins inside Play.

Creating and using your own module

Before you can implement your own functionality in a module, you should know how to create and build a module. This recipe takes a look at the module's structure and should give you a good start.

The source code of the example is available at examples/chapter5/module-intro.

How to do it...

It is pretty easy to create a new module. Go into any directory and enter the following:

play new-module firstmodule

This creates a directory called firstmodule and copies a set of predefined files into it. By copying these files, you can create a package and create this module ready to use for other Play applications. Now, you can run play build-module and your module is built. The build step implies compiling your Java code, creating a JAR file from it, and packing a complete ZIP archive of all data in the module, which includes Java libraries, documentation, and all configuration files. This archive can be found in the dist/ directory of the module after building it. You can just press Return on the command line when you are asked for the required Play framework version for this module. Now it is simple to include the created module in any Play framework application. Just put this in the in the conf/dependencies.yml file of your application. Do not put this in your module!

require:
- play
- customModules -> firstmodule

repositories:

- playCustomModules:
type: local
artifact: "/absolute/path/to/firstmodule/"
contains:
- customModules -> *

The next step is to run play deps. This should show you the inclusion of your module. You can check whether the modules/ directory of your application now includes a file modules/firstmodule, whose content is the absolute path of your module directory. In this example it would be /path/to/firstmodule. To check whether you are able to use your module now, you can enter the following:

play firstmodule:hello

This should return Hello in the last line. In case you are wondering where this is coming from, it is part of the commands.py file in your module, which was automatically created when you created the module via play new-module. Alternatively, you just start your Play application and check for an output such as the following during application startup:

INFO ~ Module firstmodule is available (/path/to/firstmodule)

The next step is to fill the currently non-functional module with a real Java plugin, so create src/play/modules/firstmodule/MyPlugin.java:

public class MyPlugin extends PlayPlugin {

public void onApplicationStart() {
Logger.info("Yeeha, firstmodule started");
}

}

You also need to create the file src/play.plugins:

1000:play.modules.firstmodule.MyPlugin

Now you need to compile the module and create a JAR from it. Build the module as shown in the preceding code by entering play build-module. After this step, there will be a lib/play- firstmodule.jar file available, which will be loaded automatically when you include the module in your real application configuration file. Furthermore, when starting your application now, you will see the following entry in the application log file. If you are running in development mode, do not forget to issue a first request to make sure all parts of the application are loaded:

INFO ~ Yeeha, firstmodule started

How it works...

After getting the most basic module to work, it is time go get to know the structure of a module. The filesystem layout looks like this, after the module has been created:

app/controllers/firstmodule
app/models/firstmodule
app/views/firstmodule
app/views/tags/firstmodule
build.xml
commands.py
conf/messages
conf/routes
lib
src/play/modules/firstmodule/MyPlugin.java
src/play.plugins

As you can see a module basically resembles a normal Play application. There are directories for models, views, tags, and controllers, as well as a configuration directory, which can include translations or routes. Note that there should never be an application.conf file in a module.

There are two more files in the root directory of the module. The build.xml file is an ant file. This helps to compile the module source and creates a JAR file out of the compiled classes, which is put into the lib/ directory and named after the module. The commands.py file is a Python file, which allows you to add special command line directives, such as the play firstmodule:hello command that we just saw when executing the Play command line tool.

The lib/ directory should also be used for additional JARs, as all JAR files in this directory are automatically added to classpath when the module is loaded.

Now the only missing piece is the src/ directory. It includes the source of your module, most likely the logic and the plugin source. Furthermore, it features a very important file called play.plugins. After creating the module, the file is empty. When writing Java code in the src/ directory, it should have one line consisting of two entries. One entry features the class to load as a plugin; where as the other entry resembles a priority. This priority defines the order in which to load all modules of an application. The lower the priority, the earlier the module gets loaded.

If you take a closer look at the PlayPlugin class, which MyPlugin inherits from, you will see a lot of methods that you can override. Here is a list of some of them accompanying a short description:

  • onLoad(): This gets executed directly after the plugin has been loaded. However, this does not mean that the whole application is ready!
  • bind(): There are two bind() methods with different parameters. These methods allow a plugin to create a real object out of arbitrary HTTP request parameters or even the body of a request. If you return anything different other than null in this method, the returned value is used as a parameter for controller whenever any controller is executed.
  • getStatus(), getJsonStatus(): Allows you to return an arbitrary string representing a status of the plugin or statistics about its usage. You should always implement this for production ready plugins in order to simplify monitoring.
  • enhance(): Performs bytecode enhancement.
  • rawInvocation(): This can be used to intercept any incoming request and change the logic of it. This is already used in the CorePlugin to intercept the @kill and @status URLs. This is also used in the DocViewerPlugin to provide all the existing documentation, when being in test mode.
  • serveStatic(): Allows for programmatically intercepting the serving of static resources. A common example can be found in the SASS module, where the access to the .sass file is intercepted and it is precomplied.
  • loadTemplate(): This method can be used to inject arbitrary templates into the template loader. For example, it could be used to load templates from a database instead of the filesystem.
  • detectChange(): This is only active in development mode. If you throw an exception in this method, the application will be reloaded.
  • onApplicationStart(): This is executed on application start and if in development mode, on every reload of your application. You should initiate stateful things here, such as connections to databases or expensive object creations. Be aware, that you have to care of thread safe objects and method invocations for yourself. For an example you could check the DBPlugin, which initializes the database connection and its connection pool. Another example is the JPAPlugin, which initializes the persistence manager or the JobPlugin, which uses this to start jobs on application start.
  • onApplicationReady(): This method is executed after all plugins are loaded, all classes are precompiled, and every initialization is finished. The application is now ready to serve requests.
  • afterApplicationStart(): This is currently almost similar to onApplicationReady().
  • onApplicationStop(): This method is executed during a graceful shutdown. This should be used to free resources, which were opened during the starting of the plugin. A standard example is to close network connections to database, remove stale file system entries, or clear up caches.
  • onInvocationException(): This method is executed when an exception, which is not caught is thrown during controller invocation. The ValidationPlugin uses this method to inject an error cookie into the current request.
  • invocationFinally(): This method is executed after a controller invocation, regardless of whether an exception was thrown or not. This should be used to close request specific data, such as a connection, which is only active during request processing.
  • beforeActionInvocation(): This code is executed before controller invocation. Useful for validation, where it is used by Play as well. You could also possibly put additional objects into the render arguments here. Several plugins also set up some variables inside thread locals to make sure they are thread safe.
  • onActionInvocationResult(): This method is executed when the controller action throws a result. It allows inspecting or changing the result afterwards. You can also change headers of a response at this point, as no data has been sent to the client yet.
  • onInvocationSuccess(): This method is executed upon successful execution of a complete controller method.
  • onRoutesLoaded(): This is executed when routes are loaded from the routes files. If you want to add some routes programmatically, do it in this method.
  • onEvent(): This is a poor man's listener for events, which can be sent using the postEvent() method.
  • onClassesChange(): This is only relevant in testing or development mode. The argument of this method is a list of freshly changed classes, after a recompilation. This allows the plugin to detect whether certain resources need to be refreshed or restarted. If your application is a complete shared-nothing architecture, you should not have any problems. Test first, before implementing this method.
  • addTemplateExtensions(): This method allows you to add further TemplateExtension classes, which do not inherit from JavaExtensions, as these are added automatically. At the time of this writing, neither a plugin nor anything in the core Play framework made use of this, with the exception of the Scala module.
  • compileAll(): If the standard compiler inside Play is not sufficient to compile application classes, you can override this method. This is currently only done inside the Scala plugin and should not be necessary in regular applications.
  • routeRequest(): This method can be used to redirect requests programmatically. You could possibly redirect any URL which has a certain prefix or treat POST requests differently. You have to render some result if you decide to override this method.
  • modelFactory(): This method allows for returning a factory object to create different model classes. This is needed primarily inside of the different persistence layers. It was introduced in play 1.1 and is currently only used by the JPA plugin and by the Morphia plugin. The model factory returned here implements a basic and generic interface for getting data, which is meant to be independent from the persistence layer. It is also used to provide a more generic fixtures support.
  • afterFixtureLoad(): This method is executed after a Fixtures.load() method has been executed. It could possibly be used to free or check some resources after adding batch data via fixtures.

Cleaning up after creating your module

When creating a module via Play new-module, you should remove any unnecessary cruft from your new module, as most often, not all of this is needed. Remove all unneeded directories or files, to make understanding the module as easy as possible.

Supporting Eclipse IDE

As play eclipsify does not work currently for modules, you need to set it up manually. A trick to get around this is to create and eclipsify a normal Play application, and then configure the build path and use "Link source" to add the src/ directory of the plugin.

Play Framework Cookbook Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework
Published: August 2011
eBook Price: £16.99
Book Price: £27.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources related to this subject, see here.)

Building a flexible registration module

This is the first hands-on module. We will write one of the most needed functionalities of modern web applications in a module, a registration module featuring a double opt-in with a confirmation e-mail. The following tasks have to be covered by this module:

  • A registration has to be triggered by a user
  • An e-mail is send to an e-mail address including a URL to confirm registration
  • A URL can be opened to confirm registration
  • On confirmation of the registration by the user, the account should be enabled
  • A Job to remove registrations, which are older than a specified time interval

You will also see that there are some problems in keeping your application modularized, which will have to be worked around and require understanding, as to when to put code into a module and when to put it into the application.

The source code of the example is available at examples/chapter5/registration.

Getting ready

Create an application, or you possibly already have an application, where you need the registration functionality. Inside this application should be a class resembling a user, which has an e-mail address property and a property which defines that the user is active. Create a new module via play new-module registration named registration.

As there will be two applications written in this example, the module as well as the application, an additional directory name will be prepended to any file path. In case of the module this will be "registration", where in the case of the real application this will be "register-app". This should sort out any possible confusion.

How to do it...

Starting with the plugin, it will feature a simple controller, which allows confirmation of the registration. This should be put into registration/app/controllers/Registration. java:

public class Registration extends Controller {

public static void confirm(String uuid) {
RegistrationPlugin.confirm(uuid);
Application.index();
}
}

Furthermore, this module has its own routes definitions, right in registration/conf/ routes:

GET /{uuid}/confirm registration.Registration.confirm

The next step is to define an interface for the process of registration, which we will implement in the application itself. This file needs to be put in registration/src/play/modules/ registration/RegistrationService.java:

public interface RegistrationService {
public void createRegistration(Object context);
public void triggerEmail(Object context);
public boolean isAllowedToExecute(Object context);
public void confirm(Object context);
}

Now the plugin itself can be implemented. Put it into registration/src/play/modules/ registration/RegistrationPlugin.java:

public class RegistrationPlugin extends PlayPlugin {

private static boolean pluginActive = false;
private static RegistrationService service;

public void onApplicationStart() {
ApplicationClass registrationService = Play.classes.getAssignabl
eClasses(RegistrationService.class).get(0);

if (registrationService == null) {
Logger.error("Registration plugin disabled. No class
implements RegistrationService interface");
} else {
try {
service = (RegistrationService) registrationService.
javaClass.newInstance();
pluginActive = true;
} catch (Exception e) {
Logger.error(e, "Registration plugin disabled. Error when
creating new instance");
}
}
}

public void onEvent(String message, Object context) {
boolean eventMatched = "JPASupport.objectPersisted".
equals(message);
if (pluginActive && eventMatched && service.
isAllowedToExecute(context)) {
service.createRegistration(context);
service.triggerEmail(context);
}
}

public static void confirm(Object uuid) {
if (pluginActive) {
service.confirm(uuid);
}
}
}

After creating the plugin the obligatory play.plugins file should not be forgotten, which must be put into registration/src/play.plugins:

900:play.modules.registration.RegistrationPlugin

Now the module is finished and you can create it via play build-module in the module directory.

In order to keep the whole application simple and the way it works together with the module, the whole application will be explained in this example.

So including the module in the register-app/conf/dependencies.yml is the first step. Running play deps after that is required:

require:
- play
- registration -> registration

repositories:
- registrationModules:
type: local
artifact: "/absolute/path/to/registration/module"
contains:
- registration -> *

Then it needs to be enabled in the register-app/conf/routes file:

* /registration module:registration

The application itself consists of two entities, a user, and the registration entity itself:

@Entity
public class User extends Model {
public String name;
@Email
public String email;
public Boolean active;
}

The registration entity is also pretty short:

@Entity
public class Registration extends Model {
public String uuid;
@OneToOne
public User user;
public Date createdAt = new Date();
}

The controllers for the main application consist of one index controller and one controller for creating a new user. After the last one is executed, the logic of the registration plugin should be triggered:

public class Application extends Controller {

public static void index() {
render();
}

public static void addUser(User user) {
user.active = false;
if (validation.hasErrors()) {
error("Validation errors");
}

user.create();
index();
}
}

When a user registers, a mail should be sent. So a mailer needs to be created, in this case at register-app/app/notifier/Mails.java:

public class Mails extends Mailer {

public static void sendConfirmation(Registration registration) {
setSubject("Confirm your registration");
addRecipient(registration.user.email);
String from = Play.configuration.getProperty("registration.mail.
from");
setFrom(from);
send(registration);
}
}

A registration clean up job is also needed, which removes stale registrations once per week. Put it at register-app/app/jobs/RegistrationCleanupJob.java:

@Every("7d")
public class RegistrationCleanupJob extends Job {

public void doJob() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MONTH, -1);
List<Registration> registrations = Registration.find("createdAt
< ?", cal.getTime()).fetch();
for (Registration registration : registrations) {
registration.delete();
}
Logger.info("Deleted %s stale registrations", registrations.
size());
}
}

The last part is the actual implementation of the RegistrationService interface from the plugin. This can be put into register-app/app/service/RegistrationServiceImpl. java:

public class RegistrationServiceImpl implements Registration
Service {

@Override
public void createRegistration(Object context) {
if (context instanceof User) {
User user = (User) context;
Registration r = new Registration();
r.uuid = UUID.randomUUID().toString().replaceAll("-", "");
r.user = user;
r.create();
}
}

@Override
public void triggerEmail(Object context) {
if (context instanceof User) {
User user = (User) context;
Registration registration = Registration.find("byUser",
user).first();
Mails.sendConfirmation(registration);
}
}

@Override
public boolean isAllowedToExecute(Object context) {
if (context instanceof User) {
User user = (User) context;
return !user.active;
}
return false;
}

@Override
public void confirm(Object context) {
if (context != null) {
Registration r = Registration.find("byUuid", context.
toString()).first();
if (r == null) {
return;
}
User user = r.user;
user.active = true;
user.create();
r.delete();
Flash.current().put("registration", "Thanks for
registering");
}
}
}

There are only two remaining steps, the creation of two templates. The first one is the register-app/app/views/Application/index.html template, which features a registration mechanism and additional messages from the flash scope:

#{extends 'main.html' /}
#{set title:'Home' /}

${flash.registration}

#{form @Application.addUser()}
Name: <input type="text" name="user.name" /><br />
Email: <input type="text" name="user.email" /><br />
<input type="submit" value="Add" />
#{/form}

The last template is the one for the registration e-mail, which is very simple. And put the following under register-app/app/views/notifier/Mails/sendConfirmation.txt:

Hey there...

a very warm welcome.
We need you to complete your registration at

@@{registration.Registration.confirm(registration.uuid)}

Also you should configure your register-app/conf/application.conf file with a valid from e-mail address, which should be set in the sent out e-mails. Therefore, put the parameter registration.mail.from=email@example.com in your configuration.

Many things happened here in two applications. In order to make sure, you got it right and where to put what file, here is a list of each. This might help you not to be confused. First goes the module, which is in the registration directory:

registration/app/controllers/registration/Registration.java
registration/build.xml
registration/conf/routes
registration/lib/play-registration.jar
registration/src/play/modules/registration/RegistrationPlugin.java
registration/src/play/modules/registration/RegistrationService.java
registration/src/play.plugins

Note that the play-registration.jar will only be there, after you built the module. Your register application should consist of the following files:

register-app/app/controllers/Application.java
register-app/app/jobs/RegistrationCleanupJob.java
register-app/app/models/Registration.java
register-app/app/models/User.java
register-app/app/notifier/Mails.java
register-app/app/service/RegistrationServiceImpl.java
register-app/app/views/Application/index.html
register-app/app/views/main.html
register-app/app/views/notifier/Mails/sendConfirmation.txt
register-app/conf/application.conf
register-app/conf/routes

After checking you can start your application, go to the index page and enter a username and an e-mail address. Then the application will log the sent mail, as long as the mock mailer is configured. You can check the template and that the sent e-mail has an absolute URL to the configuration including an URL with /registration/ in it, where the registration module is mounted. When visiting the link of the e-mail, you will be redirected to the start page, but there is a message at the top of the page. When reloading, this message will vanish, as it is only put in the flash scope.

How it works...

The preceding list, where to find which resources, should primarily show one thing. This example plugin is far from ideal. Indeed, it is very far from that. It should make you think about when you really need a plugin, and when you should include most of the stuff inside your actual project. It's time to discuss flaws and advantages of this example.

First, when you take a look at the RegistrationPlugin in the module, you will see a loosely coupled integration. The plugin searches for an implementation of the RegistrationService interface on startup, and will be marked active, if it finds such an implementation. The implementation in turn is completely independent of the module and therefore done in the application. When you take another look at the plugin, there is an invocation of the service, if a certain JPA event occurs, like the creation of a new object in this case. Again the actual implementation of the service should decide, whether it should be invoked or not. This happens via the isAllowedToExecute() method.

In case you are wondering, why there is no concrete implementation and especially no use of the registration entity: this is a limitation of the Play framework. You cannot use models in modules currently. You cannot import them in your plugin, as they are not visible at compile time of your module. Instead you would have to get them via the Play classloader. Using an interface, which is implemented in the application itself, was a design decision to circumvent exactly this problem with models. Still this means a certain decoupling from your concrete application and is not too good either. This is also the reason, why the RegistrationCleanupJob is also in the application instead of being at the module. Otherwise, it would also have to be configurable, like adding the time, how often it should run, and what entities should be cleaned. As opposed in this example, any user who has not registered might have to be cleaned as well. As all mailer classes are enhanced, they also do not fit into the module. The same applies for the e-mail template due to its flexibility, which implies it should not be packaged in any JAR files or external module, because it cannot be changed in the application then.

So, as you can see in this example, there is no clear and implicit structure. Even though the integration and writing of the plugin is nice, as it is completely decoupled from the storing of a user entity, it would make more sense in this example, to write the logic of this plugin directly in your application instead of building an own module with own packaging, as you could use all your models easily.

So when does writing a module make more sense? It makes more sense whenever you provide infrastructure code. This code is like your own persistence layer, specific templating, specific parsing of incoming data, external authentication or general integration of external services like a search engine.

A last important note and weakness of modules are currently the test capabilities. You have to write an application and use the module inside the applications tests. This is currently the only way to ensure the functionality of your module.

There's more...

Hopefully, this example gave you a glimpse of how to write a first module, but more importantly explains there is not always a use case for a module.

Think about when to write a module

If you sacrifice readability and structure of your application in favor of reuse, you should think about whether this is the way to go. Make sure your application is kept as simple as possible.

Summary

In this article we saw how to create and use our own module. We also took a look at building a flexible registration module.


Further resources related to this subject:


Play Framework Cookbook Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework
Published: August 2011
eBook Price: £16.99
Book Price: £27.99
See more
Select your format and quantity:

About the Author :


Alexander Reelsen

Alexander Reelsen is a software engineer living in Munich, Germany, where he has been working on different software systems, for example a touristic booking engine, a campaign management and messaging platform and a b2b ecommerce portal. He has been using the play framework since 2009 and was immediately astonished by the sheer simplicity of this framework, while still being pure java. Other interests include scaling shared-nothing web architectures and nosql databases.

Being rather a system engineer most of the time when he started playing around with Linux at the age of 14, Alexander got to know software engineering during his studies and decided web applications are more interesting than system administration.

If not doing something hacky, he enjoys playing a good game of basketball or streetball.
Sometimes he even twitters at http://twitter.com/spinscale and can be reached anytime at alexander@reelsen.net

Books From Packt


Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5

Python 3 Web Development Beginner's Guide
Python 3 Web Development Beginner's Guide

AJAX and PHP: Building Modern Web Applications 2nd Edition
AJAX and PHP: Building Modern Web Applications 2nd Edition

Building Dynamic Web 2.0 Websites with Ruby on Rails
Building Dynamic Web 2.0 Websites with Ruby on Rails

Google Web Toolkit 2 Application Development Cookbook
Google Web Toolkit 2 Application Development Cookbook

Ext GWT 2.0: Beginner's Guide
Ext GWT 2.0: Beginner's Guide

Grok 1.0 Web Development
Grok 1.0 Web Development

Apache Wicket Cookbook
Apache Wicket Cookbook


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software