Enterprise Java

Play framework modules: Divide and conquer

It’s usually the case that you start developing an application and go on fulfilling requirements. When your application grows bigger you start to realize the convenience of separating it into different components. Moreover, when you develop your second or third application, your begin to recognize certain features that could be reused across different applications.

These are two good reasons to modularize an application. Ideally we should aim at components with high cohesion and low coupling.

The Java language has proven itself quite fit to accomplish this kind of tasks. It provides general means to enforce the use of well defined API thru interfaces, abstract classes, etc.
Play framework developers think that this is perfectly fine for developing a general purpose library, but in the case of a web application reusability and modularization could be best achieved by other means. Have a look at this excerpt taken from play framework’s FAQ:

Java itself is a very generic programming language and not originally designed for web application development. It is a very different thing to write a generic and reusable Java library and to create a web application. A web application itself doesn’t need to be designed to be reusable. You need less abstraction, less configuration. Reusability does exist for web applications, but through web service APIs rather than language-level integration.

So when it comes to reusability, play provides us with a solution better suited for web applications.

Play modules

A module is just another Play framework application. The only difference is that a module is not meant to be run on his own, it needs to be included into a containing application.
Nevertheless, there area a couple of differences between a module and a regular application, mainly that a module has no conf file (it has to be provided by the main application) and everything in a module is optional.
Doing is better than saying, so as usual we will look for a fine opportunity to make a simple module to show how it works.

Creating a new play framework application and deploying it to the cloud

As many of you already know, we are working on the spanish translation of play framework site. We wanted to add web analytics to it so that we can see how people were using it.
So in order to follow this example, we’ll need a play framework app deployed somewhere on the Internet. Nowadays there are lots of Java hosting options available for free. Here you have a couple of tutorials for deploying on openshift, google application engine and heroku.
First let’s create a play framework application, I’ll create the app at ~/devel/apps/module-test, you can choose whatever location you like, just be sure to update the commands appropriately.
To create the app, run the following command at an os prompt:

sas@ubuntu:~/devel/apps/module-test$ play new analytics-app

~        _            _ 

~  _ __ | | __ _ _  _| |

~ | '_ \| |/ _' | || |_|

~ |  __/|_|\____|\__ (_)

~ |_|            |__/   

~

~ play! 1.2.4, http://www.playframework.org

~

~ The new application will be created in /home/sas/Dropbox/Public/devel/play/apps/module-test/analytics-app

~ What is the application name? [analytics-app] 

~

~ OK, the application is created.

~ Start it with : play run analytics-app

~ Have fun!

Now it would be a good time to deploy it somewhere. For this tutorial we will deploy it at openshift, you can use any host you want (For more information on setting up your environment for openshift deployment follow this tutorial)
Create a new directory at ~/devel/apps/module-test/openshift, go to that directory and run:

rhc-create-app -l mymail@mail.com -p mypassword -t jbossas-7.0 -a analyticsapp



Attempting to create remote application space: analyticsapp

Now your new domain name is being propagated worldwide (this might take a minute)...

Pulling new repo down



[...]



Successfully created application: analyticsapp

Next, we’ll get rid of the demo app:

cd ~/devel/apps/module-test/openshift/analyticsapp

rm -fr pom.xml src

And we’ll compile and package the newly created app as an exploded war. Go to ~/devel/apps/module-test folder and run:

cd ~/devel/apps/module-test

play war analytics-app -o openshift/analyticsapp/deployments/ROOT.war

~        _            _ 

~  _ __ | | __ _ _  _| |

~ | '_ \| |/ _' | || |_|

~ |  __/|_|\____|\__ (_)

~ |_|            |__/   

~

~ play! 1.2.4, http://www.playframework.org

~

JPDA port 8000 is already used. Will try to use any free port for debugging

Listening for transport dt_socket at address: 53978

00:22:38,021 INFO  ~ Starting /home/sas/Dropbox/Public/devel/play/apps/module-test/analytics-app

00:22:39,891 INFO  ~ Precompiling ...

00:22:49,075 INFO  ~ Done.

~ Packaging current version of the framework and the application to /home/sas/Dropbox/Public/devel/play/apps/module-test/openshift/analyticsapp/deployments/ROOT.war ...

~ Done !

~

~ You can now load /home/sas/Dropbox/Public/devel/play/apps/module-test/openshift/analyticsapp/deployments/ROOT.war as a standard WAR into your servlet container

~ You can't use play standard commands to run/stop/debug the WAR application...

~ ... just use your servlet container commands instead

~

~ Have fun!

~

Now we just need to commit the application and push it to our git repo on openshift:

cd ~/devel/apps/module-test/openshift/analyticsapp

touch deployments/ROOT.war.dodeploy

git add -A

git commit -m "deploy play framework app"

git push origin

Note: The first time it will take a couple of minutes to push the application, because of play framework libraries. Later pushes will be much quicker, git is smart enough to only send updated files.
And that’s it, you’ve just deployed your first app to red hat’s cloud. You can see it running at http://analyticsapp-opensas.rhcloud.com/ (of course, you’ll have to replace “opensas” with your own openshift user name).

Google web analytics & play framework

Adding Google web analytics to a play app is really easy. You just need a gmail account, then go to Google Analytics web site, click on “sign up”, login with your gmail account, and complete all the required data.
In the account name enter “analytics-app”, in the website’s url enter http://analyticsapp-opensas.rhcloud.com, agree to the terms and conditions and click on “Create account”.
You’ll be taken to your analytics-app account page, there you can see the tracking code. You’ll just have to paste it in your app. So open the file at ~/devel/apps/module-test/analytics-app/app/views/main.html and paste the tracking code before the closing head tag, like this:

[...]

        <script src="@{'/public/javascripts/jquery-1.6.4.min.js'}" type="text/javascript" charset="${_response_encoding}"></script>

        #{get 'moreScripts' /}



<script type="text/javascript">



  var _gaq = _gaq || [];

  _gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);

  _gaq.push(['_trackPageview']);



  (function() {

    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;

    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);

  })();



</script>



    </head>

    <body>

[...]

Note: Google will provide you with your own UA-XXXXXXXX-1 account code, so just copy and paste the code from your Google analytics account page, and NOT from this page!
Now you just have to generate the war folder, commit, and push it once again to openshift to deploy your changes. Every time you make a change you’ll have to follow these same steps to deploy it to openshift.

cd ~/devel/apps/module-test

play war analytics-app/ -o openshift/analyticsapp/deployments/ROOT.war

cd openshift/analyticsapp/

git add -A

git commit -m "added tracking code"

git push origin

Visit again your page at http://analyticsapp-opensas.rhcloud.com/, and see the source of the page to check that the tracking code has been added. You can also see it in action on Google’s analytics page, click on “Home”, Real-Time (BETA), and the Overview. You should have one visitor (yes, it’s you!).
So far now we created a new play application and deployed it to openshift. Then we created a Google analytic account and added the tracking code the our play application. Everything is working ok and our app is being tracked by Google. Now we are going to move that functionality to a module so that we can reuse it from other apps.

Creating a module

To create a new module you have to use the “new-module” play command, like this:

cd /home/sas/devel/apps/module-test/

play new-module analytics

Now, in order to tell our main application (in our case analytics-app) to include this module, we have to configure a local repository.
Edit ~/devel/apps/module-test/analytics-app/conf/dependencies.yml like this:

# Application dependencies



require:

    - play

    - analytics -> analytics

    

repositories:

    - My local modules:

        type:       local

        artifact:   ${application.path}/../[module]

        contains:

            - analytics

and after that run the following command to tell play to resolve dependencies.

cd ~/devel/apps/module-test/analytics-app

play dependencies

~        _            _ 

~  _ __ | | __ _ _  _| |

~ | '_ \| |/ _' | || |_|

~ |  __/|_|\____|\__ (_)

~ |_|            |__/   

~

~ play! 1.2.4, http://www.playframework.org

~

~ Resolving dependencies using /home/sas/devel/apps/module-test/analytics-app/conf/dependencies.yml,

~

~  analytics->analytics -> (from My local modules)

~

~ Installing resolved dependencies,

~

~  modules/analytics -> /home/sas/devel/apps/module-test/analytics/../analytics

~

~ Done!

~

You can now start the main application on your workstation:

cd ~/devel/apps/module-test/analytics-app

play run

You can see your app running at http://localhost:9000.

Moving the tracking code to a reusable tag

Now we will move the tracking code to a tag defined in the module, so we’ll create a file ~/devel/apps/module-test/analytics/app/views/analytics.html with the tracking code, like this:

<script type="text/javascript">

  var _gaq = _gaq || [];

  _gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);

  _gaq.push(['_trackPageview']);



  (function() {

    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;

    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);

  })();

</script>

And now, replace the tracking code in main.html with a call to the tag, like this:

[...]

        <script src="@{'/public/javascripts/jquery-1.6.4.min.js'}" type="text/javascript" charset="${_response_encoding}"></script>

        #{get 'moreScripts' /}



#{analytics /}

    </head>

[...]

Getting module configuration from the application.conf file

Our module is almost ready, there’s just one thing that’s preventing us from really reusing it on another application: the Google analytics code is hardcoded in our tag!
So we will read it from the application.conf file. Just edit the analytics.html tag like this:

%{

    String code = play.Play.configuration.getProperty("analytics.code", "")

}%

#{if code!=""}

<script type="text/javascript">

  var _gaq = _gaq || [];

  _gaq.push(['_setAccount', '${code}}']);

  _gaq.push(['_trackPageview']);

  (function() {

    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;

    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';

    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);

  })();

</script>

#{/if}

and add the following to your main application configuration file at ~/devel/apps/module-test/analytics-app/conf/application.conf

analytics.code=UA-XXXXXXXX-1

Prevent tracking in dev mode

This tag will will update the tracker every time the page is rendered, even when we are working on our development workstation!
So we will add a minor improvement to prevent the module from logging the page activity while working in development mode.
Just add the following condition to the code:

%{

    String code = play.Play.configuration.getProperty("analytics.code", "")

}%

#{if play.mode.isProd() && code!=""}

<script type="text/javascript">

  var _gaq = _gaq || [];

[...]

Troubleshooting Openshift

Openshift won’t be able to resolve the relative reference to the module location (and in fact any war deployed application will have the same problem), so you’ll have to tell play to copy the module sources to the containing application before generating the war folder. Just issue:

cd ~/devel/apps/module-test/analytics-app

play dependencies --forceCopy

And that’s it, now you can deploy to openshift in the usual way:

cd ~/devel/apps/module-test

play war analytics-app/ -o openshift/analyticsapp/deployments/ROOT.war

cd openshift/analyticsapp/

git add -A

git commit -m "added analytics module"

git push origin

Run your site locally with “play run”, and also open it from http://analyticsapp-opensas.rhcloud.com/, check the source code of both sites, you should see that the app running at openshift contains the tracking code, contrary to your local application.

Conclusion

In this post we saw how to deploy a play framework app to openshift and, more important, how to move features from your application to a module in order to reuse it from other applications.
You can learn more about modules on this article or reading the play framework documentation.
If you speak spanish you can help us with the translation, and you can also have a look at our work right here… You can be sure every click you make will be tracked!

Reference: Play framework modules: Divide and conquer   from our JCG partner Sebastian Scarano  at the Having fun with Play framework! blog

Related Articles :

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button