Getting JSF portlets running in Liferay 6.2

When upgrading your Liferay 6.2 you might stumble over the problem, that your JSF portlets no longer work as expected. Ajax calls are simply ignored, which means for PrimeFaces or IceFaces almost no user interaction works.

The reason is that in Liferay 6.2 it is mandatory to prefix all parameters with the portlet namespace (which is in accordance with the the JSR 286 spec, BTW).

In JSP portlets you would this fix like this:

 <input type="text" name="<portlet:namespace />inputTextName" /> 

But for JSF you have to add the following line to each JSF portlet definition in liferay-portlet.xml:

 <requires-namespaced-parameters>false</requires-namespaced-parameters>  

And your JSF portlets will run again.

Creating a Liferay portlet based on AngularJS

After my post about converting an existing AngularJS app into a portlet I’ve got a lot of requests about how to integrate the portlet with the portal backend.
So I’ve created a little demonstrator and put in on GitHub: https://github.com/nonblocking/liferay-angularjs-portlet. It uses Spring Portlet MVC and thymeleaf as template engine as backend.

Communication to the backend

The AJAX communication with the backend is based on resource requests which are originally intended to serve static resources such as images and JavaScript (see: http://www.oracle.com/technetwork/java/jsr286-2-141964.html#Serving_Resources).

To pass the resource URL (which is generated and quite complicated) to the AngularJS app the demonstrator uses thymeleaf’s Script Inlining support. Within the head section of index.html:

<script type="text/javascript" th:inline="javascript">
  var angularJsPortletAjaxURL = /*[[${ajaxURL}]]*/ "/testdata/";
  var angularJsPortletStandalone = /*[[${standalone}]]*/ true;
  var angularJsPortletAuthenticatedUser = /*[[${authenticatedUser}]]*/ "anonymous";
</script>

And within the controller method responsible for the View phase:

@RenderMapping
public String view(RenderRequest request, RenderResponse response, ModelMap model) {
  User user = (User) request.getAttribute(WebKeys.USER);
  String userScreenName = user != null ? user.getScreenName() : "anonymous";

  ResourceURL baseResourceUrl = response.createResourceURL();

  model.addAttribute("ajaxURL", baseResourceUrl.toString());
  model.addAttribute("standalone", false);
  model.addAttribute("authenticatedUser", userScreenName);

  return "index";
}

To invoke a specifc controller method and fetch some data a POST request is sent to the resource URL extended by the resource id (&p_p_resource_id={myResourceId}).
The code within AngularJS looks like this:

var method = 'users';
var params = { "startIndex": startIndex, "limit": limit };

$http({
  url: angularJsPortletAjaxURL + "&p_p_resource_id=" + method,
  method: 'POST',
  params: params
})
.success(function(data) { 
/* ... */ 
});

And the AJAX call will invoke the controller method with the corresponding ResourceMapping annotation:

@RenderMapping
@ResourceMapping("users")
public void users(@RequestParam int startIndex, 
  @RequestParam int limit, ResourceResponse response) throws Exception {
    UserList users = /* fetch the users */

    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");

    //Automatic JSON serialization doesn't work yet in Protlet MVC
    //See: https://jira.spring.io/browse/SPR-7344
    JSON_MAPPER.writeValue(
      response.getPortletOutputStream(), users);
}

Javascript and CSS resources

The JavaScript and CSS resources are not directly added to the HTML, but rather declared in liferay-portlet.xml like this:

<portlet>
  <!-- ... --> 
  <header-portlet-css>/css/app.css</header-portlet-css>
  <footer-portlet-javascript>/js/vendor.js</footer-portlet-javascript>
  <footer-portlet-javascript>/js/app.js</footer-portlet-javascript>
</portlet>

Standalone Mode

A very interesting opportunity when developing a HTML5 portlet is that you can run it standalone. This greatly accelerates the development. Since thymeleaf templates are pure HTML it’s no big deal at all.

In the demonstrator I’ve added the JavaScript and CSS resources, which are normally added by the portal, to the HTML (index.html) too. But only in the case the app runs in standalone mode. If the standalone property is set within the portlet controller the script tag is not rendered:

 <script type="application/javascript" src="js/app.js" 
   th:if="${standalone}">
</script>

Secondly I’ve created a test backend which delivers test data (JSON) when the portal is not available. There actual implementation is selected based on the global angularJsPortletStandalone variable which will also be rewritten by thymeleaf:

.factory('backend', function($http) {
  var portletBackend = /* ... */;

  var testBackend = /* ... */;

  if (angularJsPortletStandalone) {
    return testBackend;
  } else {
    return portletBackend;
  }
});

The test backend also comes in handy when you use Jasmine to unit test your JavaScript code (something you should definitely consider).

I hope the demo portlet is helpful. Don’t hesitate to post remarks and comments.

Book Review: Liferay 6.2 User Interface Design

Liferay6_2_UI_Design
Liferay 6.2 User Interface Design is a good reference book if you’re going to write a Theme for Liferay or Portlets. I was especially interested in responsive design with Liferay and found what I was looking for: A decent introduction how to create flexible grids in a Layout and how to use Bootstrap for responsive Themes. The responsive capabilities of Liferay’s UI framework AUI (which is based on YUI) are also well described.
Since I’ve a lot of experiences with Liferay versions prior to 6.2 I was disappointed that nowhere was clearly stated what’s new in this version and which features and capabilities are specific for 6.2 and which are not. I’m pretty convinced most of the examples in this book would work with 6.1 as well.
I was also a bit surprised that JSF is not mentioned as a possible technology for Portlets, since it is the standard in JEE (not that I would like JSF too much). On the other hand there is a guide how to generate a Portlet with OpenXava, which is a very interesting framework for rapid application development.