Alfresco webscripts support the MVC pattern where the ‘C’, the controller, can be implemented in Java or in JavaScript. By reading a recently published book on Alfresco webscripts I found out that a webscript can have both a Java and a JavaScript implementation working together.

It works this way: the Java controller is executed first, the JavaScript controller is executed second, and finally the freemarker template is applied. A requirement is that the Java class must extend DeclarativeWebScript.

But why on earth one might want to have two implementations for one webscript? A few days after reading the book, Douglas C.R. Paes and I were improving one of the webscripts of the uploader-plus plugin and found a situation that perfectly fits the Java+JavaScript scenario. The webscript needs to access the DictionaryService, which is much easier to implement in Java, and to read the webscript’s config.xml file, which is much easier to implement in JavaScript.

In this post I’d like to explain a specific point: how the model (the ‘M’ of the MVC pattern) is passed from the Java controller to the JavaScript controller and finally to the Freemarker template. It’s not trivial, it wasn’t discussed in the book and caused me a good hour of head-scratching.

How the model is NOT passed

In a Java controller the model is created and populated like this:

Map<String, Object> model = new HashMap<>();
model.put("var1", "var1 from Java");
return model;

I was expecting that the JavaScript controller could simply access var1 with:

model.var1

Unfortunately this is not the case as model.var1 evaluates to Undefined. However, if a Fremarker template references $var1 its value is var1 from Java as one would expect.

How the model is passed

I had to look at DeclarativeWebScript’s source code to understand what’s going on.

First, the attributes of the Java model are passed to JavaScript as root objects. So in the previous example, in JavaScript I should have used simply var1 instead of model.var1

Second, JavaScript has its own model accessible through the usual model root object. This model is completely separate from the Java model.

Third, the Java and JavaScript models are merged just before the Freemarker template is invoked, with the JavaScript model’s attributes taking precedence over same name attributes in the Java model.

Fourth, if JavaScript overwrites the root objects from the Java model, the Java model is not affected and the original values are used during the merge of the two models.

An example

So let’s write an example that tests all cases. Here is the Java controller to start:

protected Map<String, Object> executeImpl(WebScriptRequest req,
                                          Status status,
                                          Cache cache) {
    Map<String, Object> model = new HashMap<>();
    model.put("var1", "var1 from Java");
    model.put("var2", "var2 from Java");
    model.put("var3", "var3 from Java");
    return model;
}

The JavaScript controller:

// Java model's attributes are accessible
// as root objects var1, var2, var3

// try to overwrite var2 in the Java model
var2 = "var2 from JavaScript";

// set var3 in the JavaScript model
model.var3 = "var3 from JavaScript";

logger.log("var1: " + var1);  // "var1 from Java"
logger.log("var2: " + var2);  // "var2 from JavaScript"
logger.log("var3: " + var3);  // "var3 from Java"

logger.log("model.var1: " + model.var1); // "null"
logger.log("model.var2: " + model.var2); // "null"
logger.log("model.var3: " + model.var3); // "var3 from JavaScript"

The freemarker template:

{
"var1" : "${var1}",
"var2" : "${var2}",
"var3" : "${var3}"
}

which generates the following output:

{
"var1" : "var1 from Java",
"var2" : "var2 from Java",
"var3" : "var3 from JavaScript"
}

You can see that:

  • var1 is taken directly from the Java model
  • var2 is the original value from the Java model despite JavaScript tried to overwrite it
  • var3 is taken from the JavaScript model which takes precedence over the same name attribute from the Java model

Conclusions

Every Alfresco developer has his own preferences regarding Java vs JavaScript webscripts. However there are cases where something is significantly easier in one of two languages. Now you know that you don’t have to choose one over the other, you can use both.