Wednesday, December 21, 2016

Scala implementation of the Glicko-2 system

I did not found a Scala realization of the Glicko-2 system as a library in a repository, so I did a new one and publish it to maven. Feel free to use it:

Github

https://github.com/andriykuba/scala-glicko2

Maven

<dependency>
  <groupId>com.github.andriykuba</groupId>
  <artifactId>scala-glicko2</artifactId>
  <version>1.0.0</version>
</dependency>

sbt

libraryDependencies += "com.github.andriykuba" % "scala-glicko2" % "1.0.0" 

Precision

The original paper has an issue with precision: https://github.com/andriykuba/scala-glicko2#precision

Wednesday, September 28, 2016

play-handlebars was published

I published play-handlebars module into the sonatype repository. It could be freely included into the project now. Maven:
<dependency>
  <groupId>com.github.andriykuba</groupId>
  <artifactId>play-handlebars</artifactId>
  <version>2.5.1</version>
</dependency>
sbt:
libraryDependencies += "com.github.andriykuba" % "play-handlebars" % "2.5.1" 

Monday, September 26, 2016

Handlebars module for Play Framework

I wrap up all my "handlebars around" code in the module play-handlebars. You can use it as easy as
public class HomeController extends Controller { 

    @Inject
    private HandlebarsApi handlebarsApi;

    public Result index() {
        // Data. 
        final Map data = new HashMap<>();
        data.put("title", "Page Title");
        data.put("header", "Header");
        data.put("main", ImmutableMap.of("article", "Main Article"));
        data.put("footer", "Footer");

        // Fill it with the data.
        final Content page = handlebarsApi.html("page", data, Context.current().lang().code());

        // Return the page to the client. 
        return ok(page);
    }
}
Or
class HomeController @Inject() (val handlebarsApi: HandlebarsApi)extends Controller with HandlebarsSupport{
  def index = Action { implicit request =>{
    val jsonData = 
      Json.obj("users" -> Json.arr(
        Json.obj(
          "name" -> "Jhon",
          "age" -> 4,
          "role" -> "Worker"
        ),
        Json.obj(
          "name" -> "Duck",
          "age" -> 6,
          "role" -> "Administrator"
        )))
    val page = render("page", jsonData)
    Ok(page)
  }}
}

Monday, May 9, 2016

Reflection loading of reverse routings

In Twirl reverse routing is as easy as the inline Scala operator - @controllers.routes.HomeController.loginSubmit. The same for the Java or Scala code. Just the routes package need to be added before the controller class name.

I implement the reves routing helper in my handlebars templates with the help of reflection.

It's no need even to add the rotes package

...
<form action="{{route "controllers.HomeController.loginSubmit"}}" method="POST>
...
{{route "controllers.HomeController.myAction()"}}
{{route "controllers.HomeController.myActionName(\"name\")"}}
{{route "controllers.HomeController.myActionAge(33)"}}
The core method of realization is the reflection of the correspond routes class:
  1. Get the class loader.
  2. Load the auto generated class routes.
  3. Get the reverse router object of the controller (it's in a static field of the routes class).
  4. Get the action of the reverse controller (do not forget about method parameters).
  5. Get the URL of the action.

Realization

private static String reverseUrl(
    final String controllerPackage,
    final String controllerClass,
    final String methodName,
    final RouteMethodArguments methodArguments) throws Exception {

  // Get the play class loader.
  final ClassLoader classLoader = Play.classloader(Play.current());

  // Load the auto generated class "routes".
  final Class routerClass = classLoader.loadClass(controllerPackage + ".routes");

  // Get the reverse router object of the controller.
  final Field declaredField = routerClass.getDeclaredField(controllerClass);
  // It's static field.
  final Object object = declaredField.get(null);
  final Class type = declaredField.getType();

  // Get the action of the reverse controller.
  final Method routerMethod = type.getMethod(methodName, methodArguments.types);
  final Call invoke = (Call) routerMethod.invoke(object, methodArguments.values);

  // Get the URL of the action.
  final String actionUrl = invoke.url();

  return actionUrl;
}
There are also some trivial code for the parsing helper parameter and for the caching. For now, I support only the String and Integer parameters for the actions. The cashe system is the guava cache.

One more thing - the RouteMethodArguments class that represents the arguments of the action

private static class RouteMethodArguments {
  final Class<?>[] types;
  final Object[] values;

  RouteMethodArguments(Class<?>[] types, Object[] values) {
    this.types = types;
    this.values = values;
  }
}

Tuesday, April 26, 2016

aggregateReverseRoutes

I put my handlebars project in to the sub-project and stucked with the problem of reverse routing.

I used it in the assets helper

public static CharSequence asset(final String url) throws Exception{
 return controllers.routes.Assets.versioned(new controllers.Assets.Asset(url)).toString();
}
controllers.routes package was missing, because it generates in the process of the root project generation, and root project depends on the handlebars sub projects.

For sure I was not the first who faced with this problem. There is a long story issue. And there is a documentation as well. So if you met this problem then aggregateReverseRoutes setting would help you. The reason for this post is that it somewhat hard to recognize that "Aggregating reverse routers" is exactly about this problem, I saw similar questions on the StackOverflow.

My project definition section of the build.sbt in the root project

lazy val handlebars = (project in file("modules/handlebars"))
 .enablePlugins(PlayJava)
 .settings(
     aggregateReverseRoutes := Seq(root)
   )

lazy val root: Project = (project in file("."))
 .enablePlugins(PlayJava)
 .aggregate(handlebars)
 .dependsOn(handlebars)
Two thing here you need to pay attention.

First, aggregateReverseRoutes := Seq(root) says that handlebars need reverse routing from the root project.

Second, lazy val root: Project implicit variable type must be used because of recursion.

Thursday, March 24, 2016

Handlebars. Module

Handlebars engine is a tread-safe, so I can initialize it only once and then compile templates using the single instance (with a cache system). So I moved all the handlebars code into the module. There were a few changes: configuration has been extracted to the handlebars.conf, handlebars cache has been used, MessagesApi now injecting into the helpers, so they are not static, and result type of the handlebars compilation is a play.twirl.api.Content.

Now I can easely inject HandlebarsApi in any component:

@Inject
private HandlebarsApi handlebarsApi;

And compile the template just with one line

Content page = handlebarsApi.html("page", data);


Configuration


First of all, I extracted the configuration. I like the include statement, so I easily created the handlebars settings.

application.conf

# configure Handlebars API
handlebars{
    include "handlebars.conf"
}

handlebars.conf in the same directory as the application.conf

directory: "/templates"
extension: ".hbs"

In the code I can read handlebars properties as easy as

configuration.getString("handlebars.directory")


Module


The creation of module in Play is simple.

Create a class. I used @Singleton because I want to initialize handlebars only ones and utilize the cache system.

package handlebars;

@Singleton
public class HandlebarsApi {
...
}

Extend the play.api.inject.Module class; bind your class.

package handlebars;

import play.api.Configuration;
import play.api.Environment;
import play.api.inject.Binding;
import scala.collection.Seq;

public class Module extends play.api.inject.Module {

  @Override
  public Seq<Binding<?>> bindings(final Environment environment, final Configuration configuration) {
    return seq(bind(HandlebarsApi.class).toSelf());
  }

}

The last step - enable the module in the application.conf

# Bind Handlebars API
play.modules.enabled += "handlebars.Module"


Cache


Handlebars has a good cache system. There is no need to build your own. I selected the Guava cache.

Add dependency to the build.sbt

libraryDependencies += "com.github.jknack" % "handlebars-guava-cache" % "4.0.4"

Initialize handlebars with the cache

...

import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

...

// Initialize the cache. Could be builded from configuration as well
// For example: CacheBuilder.from(config.getString("hbs.cache")).build()
final Cache cache = CacheBuilder.newBuilder()
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .maximumSize(1000)
    .build();

// Initialize the engine with the cache
handlebars = new Handlebars(loader)
    .with(new GuavaTemplateCache(cache));

...


MessagesApi


I use MessagesApi in the handlebars helper. Helpers are registering only once a time, fortunately MessagesApi is a singleton, so I put it in to the Helper's constructor.

Part of the Helpers class.

public final class Helpers {

  final MessagesApi messagesApi;

  public Helpers(final MessagesApi messagesApi){
    this.messagesApi = messagesApi;
  }

  ...

  public CharSequence message(final String key, final Options options) {
    // Get the current language.
    final Lang lang = Context.current().lang();
    
    // Retrieve the message, internally formatted by MessageFormat.
    return messagesApi.get(lang, key, options.params);
  }

}

Initialization of the Handlebars with the Helpers class.

...

@Inject
public HandlebarsApi(... final MessagesApi messagesApi) {
  
  ...
  
  // Add helpers. MessagesApi is a singleton so we can use it in the helpers.
  Helpers helpers = new Helpers(messagesApi);
  handlebars.registerHelpers(helpers);
  
  ...

}

...


Content


Trivial result of the template processing in the Play is the object of play.twirl.api.Content type. So I created a simple implementation of this class for the HTML template.

HTML Content wrapper:

package handlebars;

import play.twirl.api.Content;

class HtmlContent implements Content {

  private String body;
  
  HtmlContent(final String body){
    this.body = body;
  }
  
  @Override
  public String body() {
    return body;
  }

  @Override
  public String contentType() {
    return "text/html";
  }

}

Wrapping the handlebars result:

public String render(final String templateName, final Object data) throws Exception {
  return handlebars
      .compile(templateName)
      .apply(data);
}

public Content html(final String templateName, final Object data) throws Exception {
  return new HtmlContent(render(templateName, data));
}


Mocking the Http.Context


In the process of testing templates I spend a little time to beat the nasty error
java.lang.RuntimeException: There is no HTTP Context available from here.
So do not forget to mockup the Http.Context. It's easy to do.

Here is an example from the project:


// Initialize application
Application application = new GuiceApplicationBuilder().build();

// Setup an HTTP Context
Http.Context context = mock(Http.Context.class);

// Setup the language and messages
Lang langRequest = Lang.forCode(requestLang);
Lang langSession = Lang.forCode(sessionLang);
MessagesApi messagesApi = application.injector().instanceOf(MessagesApi.class);
Messages messages = new Messages(langRequest, messagesApi);

// Train the Context
when(context.lang()).thenReturn(langSession);
when(context.messages()).thenReturn(messages);
//Http.Context.current.set(context);

// Get the handlebars API
HandlebarsApi handlebarsApi = application.injector().instanceOf(HandlebarsApi.class);


Project on the Github


You can find this simple project with the Handlebars module on the github: https://github.com/andriykuba/playframework-handlebars-example

Sunday, March 13, 2016

Handlebars. i18n to @Message

The Handlebars internationalization helper {{i18n}} is not very good choice for the Play. It uses different name convention for the message files, it hard to use different language in different requests. The {{i18n}} uses the local attribute to detect the language, by default it uses default local that defines by the Locale.getDefault(). It's a little bit different from the Play philosophy where you can change the language in every request, even only for one request with the help of the setTransientLang().

So I created the {{message}} helper that does the same work as the @Message in Twirl. It takes just a few strings of code. Actually, there are only two difference from the {{assert}} helper, described in the previous post. First - I need to detect the language on an every request, so I can not use the static helper. Second - messages could have arguments, so I need to use Options parameter in the helper method. And a little bit sugar - the MessageFormat library, just like in the original @Message.

Changes in the Helper class

import java.text.MessageFormat;
import com.github.jknack.handlebars.Options;
import play.i18n.Messages;

...

private final Messages messages;

...

/**
* Creates Helpers with the given message pack.
* 
* @param messages
*          The Play message pack.
*/
public Helpers(final Messages messages) {
  this.messages = messages;
}

...

/**
* Do the same as "@Message(key)" in Twirl. It use MessageFormat for the
* formatting as well as "@Message(key)".
* 
* @param key
*          message key in the messages.** files.
* @return message
*/
public CharSequence message(final String key, Options options){
  String message = messages.at(key);
  String messageFormatted = MessageFormat.format(message, options.params);
  return messageFormatted;
}

Cahnges in the Handlebars initialization

import play.i18n.Messages;
import play.i18n.MessagesApi;

...

@Inject
private MessagesApi messagesApi;

...

Messages messages = new Messages(ctx().lang(), messagesApi);
Helpers helpers = new Helpers(messages);
handlebars.registerHelpers(helpers);

...

Template

{{message "page.header.sub" "name"}}

message.en

page.header.sub=Page Sub Header {0}
I used the new Messages(ctx().lang(), messagesApi) opposite to the ctx().messages() because I want full support of the ctx().changeLang() and the ctx().setTransientLang().

The ctx().lang() returns the current language, it is the language that was set by the ctx().changeLang() or the ctx().setTransientLang() or was taken from the PLAY_LANG cookie or taken from the Accept-Language header or taken from the default locale of the server.

The ctx().messages() returns a messages pack for the language of the current request. It is the language that was taken from the PLAY_LANG cookie or taken from the Accept-Language header or taken from the default locale of the server.

The ctx().changeLang() change the context lang field and set the PLAY_LANG cookie for the current response. So the ctx().messages() will return the message pack of the new language only in the next request. It is a tiny difference but I spend some time to catch it.

Tuesday, March 8, 2016

Custom path of the messages

The guide says "You can externalize messages in the conf/messages.xxx files.". If you have a dozen languages it will be a mess of messages files in the config folder. Fortunately, there is property in the application.conf file that somehow fell off the tutorial - play.i18n.path. You can assign this variable the value that will prefix of messages files.
play.i18n.path = messages/
Will say the Play to look into the conf/messages folder for the messages.xxx files

Thursday, March 3, 2016

Handlebars. Helpers

Handlebars easily extensible. Let's create a helper for processing the asset link.  Here is the original Twirl template:
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
<script src="@routes.Assets.versioned("javascripts/hello.js")" type="text/javascript"></script>
We need to be able to do @routes.Assets.versioned("...") with the handlebars. Let's create the helper class that will hold all our handlebars helpers. From the start, we will add only one helper, the assets helper. This one could be done even in static method:

package handlebars;

public class Helpers {

  /**
  * Do the same as "@routes.Assets.versioned" in Twirl.
  * 
  * @param url relative path to the asset
  * @return actual path to the asset
  */
  public static CharSequence asset(String url) {
    return controllers.routes.Assets.versioned(new controllers.Assets.Asset(url)).toString();
  }
}
Now we need to register it. Jut one line into the code from my previous post:
...

// Initialize the engine
Handlebars handlebars = new Handlebars(loader);

// Add helpers
handlebars.registerHelpers(Helpers.class);

// Compile the "templates/page.hbs" template
Template template = handlebars.compile("page");

...
Now we can add assets to the handlebars template:
<link rel="stylesheet" media="screen" href="{{asset "stylesheets/main.css"}}">
<link rel="shortcut icon" type="image/png" href="{{asset "images/favicon.png"}}">
<script src="{{asset "javascripts/hello.js"}}" type="text/javascript"></script>
And the result, the same as with Twirl:
<link rel="stylesheet" media="screen" href="/assets/stylesheets/main.css">
<link rel="shortcut icon" type="image/png" href="/assets/images/favicon.png">
<script src="/assets/javascripts/hello.js" type="text/javascript&qu

Handlebars

I personally prefer the logicless templates, so mustache simply The Best for me.  Unfortunately, the real world is not so simple,  therefore, I use handlebars.

Paly itself prefer Twirl. Well, it's a good thing, but I still like handlebars much more.

Fortunately,  we can use handlebars as the template engine in Play. You can find some ready to use plugins on the GitHub, like play2-handlebars. And you can easily use the original handlebars.java library by yourself. I stick with the last option. It's easy and you can always update handlebars to the last version without depending on other plugins.

It's a good idea to use a separate folder for the templates. Assume you create the templates folder in the project root. Then you will need to add two new instructions to the build.sbt file.
// Add the handlebars library
libraryDependencies += "com.github.jknack" % "handlebars" % "4.0.3"

// Copy handlebars templates to the production
mappings in Universal ++=
  (baseDirectory.value / "templates" * "*" get) map
    (x => x -> ("templates/" + x.getName))
The last thing just to use the handlebars engine. I extend trivial controller class from the play-java framework.
package controllers;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;

import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Template;
import com.github.jknack.handlebars.io.FileTemplateLoader;
import com.github.jknack.handlebars.io.TemplateLoader;
import com.google.common.collect.ImmutableMap;

import play.Environment;
import play.mvc.Controller;
import play.mvc.Result;

public class Application extends Controller {

  // We need an environment to get the template folder
  @Inject
  private Environment environment;
 
  public Result index() throws Exception {
     
    // The data
    Map data = new HashMap<>();
    data.put("title", "Page Title");
    data.put("header", "Header");
    data.put("main", ImmutableMap.of("article", "Main Article"));
    data.put("footer", "Footer");
     
    // Get the template folder
    File rootFolder = environment.getFile("/templates");

    // Put the ".hbs" as a template extension.
    TemplateLoader loader = new FileTemplateLoader(rootFolder, ".hbs");
        
    // Initialize the engine
    Handlebars handlebars = new Handlebars(loader);
        
    // Compile the "templates/page.hbs" template
    Template template = handlebars.compile("page");
     
    // Fill it with data
    String page = template.apply(data);
        
    // Return the page to the client
    return ok(page).as("text/html");
  }

}
Yea, here is the template:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>{{title}}</title>
    <meta name="description" content="{{description}}">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <header>
        {{header}}
    </header>
    <main>
     <article>
        {{main.article}}
     </article>
    </main>
    <footer>
        {{footer}}
    </footer>
</body>
</html>
And the result:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Page Title</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <header>
        Header
    </header>
    <main>
     <article>
        Main Article
     </article>
    </main>
    <footer>
        Footer
    </footer>
</body>
</html>

Wednesday, March 2, 2016

Messages API. Unable to switch the language

Assume you are using java in the controller, and the default template engine.  It will work perfectly until you want to switch the language.

Let’s look at the guide of java internationalization JavaI18N
public Result index() {
  ctx().changeLang("fr");
  return ok(hellotemplate.render()); // "bonjour"
}
Well, it will only work in the case if you use java version of the messages API in the templates i.e.
@import play.i18n._
@Messages.get("hello")
If you prefer to use shorter scala version, like
@Messages("hello")
Then switched language will not be used in the current request. Scala Messages API will use the old one – default or taken from the request cookie.  I need to admit that ctx().changeLang(“fr”) will change the PLAY_LANG cookie, so in the next request (for example after refreshing the page)  scala will take this cookie and will show the “switched” language.