Skip to main content

My first Play Framework application

My first Play Framework application has recently gone live. This time it was the Java version of the framework, next time I may move on to Scala finally. Nevertheless, I've learned a lot and will try to share some knowledge here. The application is meant for managing the data stored in the Dydra graph database (RDF & SPARQL). It's a thick client application meaning that the data loading happens in the client JavaScript layer via JSON requests, while routing and user authentication is done by means of Play Framework. Also I've made use of the RequireJS support in Play Framework for dynamic JS module loading. For the UI I've chosen a well-known YUI library. More details are following below.
  1. Application architecture.
  2. User model and authentication.
  3. Dydra database layer and SPARQL client.
  4. JavaScript logic and YUI.
  5. RequireJS module loading.
Application architecture
As any web application, this one can be described in terms of MVC pattern. Play Framework encourages following this pattern by introducing Ebean ORM with support for JPA annotations, Model/Controller class hierarchies and the powerful Scala-based template engine. Having played enough with Spring MVC's request mapping annotations, I've found it awesome that Play Framework introduces the central configuration file for all the HTTP routing in the application - conf/routes file.

This was a generic Play Framework-based application design. However, my application deviates with most of the controller logic written in JavaScript, while only the user authentication is implemented with the default approach. BTW, for this purpose Play Framework provides security helpers with Java annotations that you'll see below.

User model and authentication
I've borrowed the implementation of the user model and authentication from the sample application Zentasks. That official sample application tutorial is a great way for a quick start. Then I've customized it for my case. For example, I've added Unsecured authenticator to allow anonymous users to preview the home page without redirection to the unauthorized page.
public class Unsecured extends Security.Authenticator {
    @Override
    public String getUsername(Context ctx) {
        String name = ctx.session().get("name");
        // Returns "" to avoid redirection to unauthorized page
        return name == null ? "" : name;
    }
}
Then the home page controller class looks like:
@Security.Authenticated(Unsecured.class)
public class Home extends Controller {
    // Action handlers here
}
Finally, I've benefited from the database evolutions support. They allow managing database changes in a simple way. Moreover, you can configure the evolutions to be applied automatically without pressing "Apply this script now!" button. So my database configuration looks like:
# Using default H2 database in the embedded mode
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:db/play"
# Database evolutions are applied automatically
applyEvolutions.default=true

Dydra database layer and SPARQL client
Main functional part of the application's model is based on Dydra RDF database. Although there already exists a JPA-like Play Framework plugin for RDF databases called Imperium, I've decided it's an overkill for my use case and have opted for the client-side JavaScript SPARQL client. For this purpose I've borrowed sparql-client.js implementation (a part of SKOSjs application).

So I've ended up using cross-domain JavaScript requests to interact with the database. By default their usage is forbidden due to security reasons, so the browsers will complain. However, as long as the server sends a Access-Control-Allow-Origin response header (that is done by Dydra database), such requests will work with some restrictions. First, I could not make HTTP POST requests working cross-domain, so I used HTTP GET for SPARQL 1.1 Update queries. Second, although there are several authentication ways in Dydra, I've ended up using "API Authentication Key as a Query String Parameter".

JavaScript logic and YUI
I've reused the YUI3-based Transaction utility again and have built a number of child transaction classes that encapsulate sending SPARQL requests to the RDF database and rendering the results to the user. Here I'll show just a basic SparqlTransaction that builds the SPARQL query from the template and parameters, then sends the SPARQL request to the RDF database and returns the resulting JSON data for further processing. Afterwards, the data can be represented in a YUI data table or in any other way. However, that code still requires a lot of refactoring so I may show some examples later in another post.
// Basic SPARQL transaction extends ContainerTransaction
function SparqlTransaction(config) {
    Y = config.Y;
    Y_transaction.ContainerTransaction.call(this, config);

    // this function is called when the SPARQL request returns some data
    // to be overriden
    this.onDataLoad = function(config, data) {};

    // override the onComplete function
    this.onComplete = function (txId, response) {
        // response already contains SPARQL query
        // but it needs to be parametrized
        var query = formatQuery(response.responseText, config.queryParams);
        // sending SPARQL query HTTP GET request with success/failure callbacks
        config.client.select(query, function (data, caller) {
            hideLoadingImage(config.containerId);
            caller.onDataLoad(config, data);
        }, function () {
            hideLoadingImage(config.containerId);
            alert("Connectivity issue occurred")
        }, this);
    };

    function hideLoadingImage(containerId) {
        if (containerId) Y.one("#" + containerId).get('childNodes').remove();
    }
}

// Substitutes the placeholders {n} with corresponding parameters
function formatQuery() {
    var queryString = arguments[0];
    var parameters = arguments[1] || [];
    for (var i = 0; i < parameters.length; i++) {
        queryString = queryString.replace(
            new RegExp('\\{'+i+'\\}', 'g'), parameters[i]);
    }
    return queryString;
}
Here is how I've created and invoked the SPARQL transaction to show some response to the user:
var transaction = new Common.SparqlTransaction({
    "Y": Y,
    "uri": query_url,
    "queryParams": [id],
    "client": client
});
transaction.onDataLoad = function(config, data) {
    var props = data.results.bindings[0];
    // showing props values to the user here
};
transaction.execute();
To conclude, the SPARQL transaction sends the AJAX request to the server to read the SPARQL query resource, then the SPARQL query is parametrized and sent to the RDF database using the SPARQL client. Finally, the JSON results of the SPARQL request are rendered to the user.

RequireJS module loading
Play Framework supports one more cool feature - JavaScript module loading based on RequireJS library. Here you can find hints and examples explaining how to make use of this feature. It can be extremely useful, especially in my case when most controller logic is written in JavaScript. However, I still have some issues to resolve as combining resources and minification do not seem to work properly yet. This is because I've made use of YUI and have tried to integrate it with RequireJS using UseYUI plugin. It will be a good topic for another post as soon as I resolve the issues.

Comments

  1. Users praised the usability, real good job Ivan :)

    ReplyDelete

Post a Comment

Popular posts from this blog

DynamicReports and Spring MVC integration

This is a tutorial on how to exploit DynamicReports reporting library in an existing Spring MVC based web application. It's a continuation to the previous post where DynamicReports has been chosen as the most appropriate solution to implement an export feature in a web application (for my specific use case). The complete code won't be provided here but only the essential code snippets together with usage remarks. Also I've widely used this tutorial that describes a similar problem for an alternative reporting library.
So let's turn to the implementation description and start with a short plan of this how-to:
Adding project dependencies.Implementing the Controller part of the MVC pattern.Modifying the View part of the MVC pattern.Modifying web.xml.Adding project dependencies
I used to apply Maven Project Builder throughout my Java applications, thus the dependencies will be provided in the Maven format.

Maven project pom.xml file:
net.sourceforge.dynamicreportsdynamicrepo…

Choosing Java reporting tool - part 2

I've provided a general overview of possible solutions to get a reporting/exporting functionality in the previous post. This is the second overview of alternatives based on JasperReports reporting engine.

Since the previous part I've done the following:
Implemented a simple report using both DynamicJasper and DynamicReports to compare them from technical side.Investigated JasperServer features and tried to implement a simple report for JasperServer instance (it appeared we already have a ready licensed installation of JasperServer that makes it unreasonable to install a fresh one).
First, the comparison results of Java libraries (DynamicJasper and DynamicReports):
Both libraries suffer from poor-quality or missing Java docs but they look a bit better in DynamicJasper.Taking into account the point 1, a developer has to use online documentation and to review the code. Here the code looks definitely nicer and more readable for DynamicReports. With respect t…

Do It Yourself Java Profiling

This article is a free translation of the Russian one that is a transcript of the Russian video lecture done by Roman Elizarov at the Application Developer Days 2011 conference.
The lecturer talked about profiling of Java applications without any standalone tools. Instead, it's suggested to use internal JVM features (i.e. threaddumps, java agents, bytecode manipulation) to implement profiling quickly and efficiently. Moreover, it can be applied on Production environments with minimal overhead. This concept is called DIY or "Do It Yourself". Below the lecture's text and slides begin.
Today I'm giving a lecture "Do It Yourself Java Profiling". It's based on the real life experience that was gained during more than 10 years of developing high-loaded finance applications that work with huge amounts of data, millions currency rate changes per second and thousands of online users. As a result, we have to deal with profiling. Application profiling is an i…