Design and build a collaborative user experience for a chance to win cool prizes!
Blog

Update on Vaadin/Liferay Integration

By  
James Falkner
·
On Jun 2, 2014 12:00:00 PM
·

Liferay and Vaadin have always had good synergy (yep, I just used that word), often used together as a "best of breed" solution for portal and the frontend user experience. Vaadin 7 was released last year and introduced some changes in portal integration (including in Liferay), along with many new features, so I wanted to take a peek at the state of the art by upgrading Vaadin and then converting an existing non-Vaadin Liferay app to Vaadin 7 on the latest Liferay release (Liferay Portal 6.2). You can check out the source code, but there are several things to keep in mind when integrating Vaadin and Liferay together -- so I want to share a few details.

Upgrading Vaadin and the "Self-Contained" approach

Vaadin has been embedded within each Liferay release starting with Liferay 6.0, but the embedded version lags behind the most recent Vaadin releases (for obvious reasons -- they don't share the same release cycles). Previously, if you wanted to use the latest Vaadin release, you needed to upgrade the embedded Vaadin, but the good news is that you no longer have to worry about this if you don't want to! Vaadin has recommended a new approach for packaging Vaadin apps for Liferay, which packages Vaadin along with your app (i.e. in the same WAR file) completely independent from the embedded version of Vaadin installed globally in Liferay. This is informally referred to as the self-contained approach, and if you follow this approach (which I also now recommend in almost all cases), then you don't need to do anything to the bundled version of Vaadin. It will remain dormant and unusued by apps that follow the self-contained packaging method, or you could even delete it if you are worried about conflicts.

If you have a production environment with many Vaadin portlets spread across many WAR files, it may make sense to continue to maintain a single global embedded Vaadin installation (to save bandwidth, browser, and JVM resources), in which case you can still use this approach by upgrading the global Vaadin installation to Vaadin 7. You can then use the Vaadin Control Panel to manage the global installation, including compiled widgetsets (Note: you will need to manually compile and install the Vaadin Control Panel on Liferay 6.2).

Linking Vaadin 7 apps into Liferay

Once you have your Vaadin infrastructure set up, the fun begins actually writing Vaadin apps. There is an execellent online resource called the Book of Vaadin, and in fact has a chapter dedicated to Portlet integration (some sections are still in the process of being updated for Vaadin 7).

Typical Vaadin apps in an enterprise are data-driven applications, and will need to access Portal data, or integrate with Liferay's permissioning system, or talk to other portlets via IPC. Below is a description of the typical mechanisms used between Vaadin and Liferay.

PortletListener and PortletRequestListener

Constructing a Vaadin UI is typically done in your UI class's init() method. And often, you need access to some Liferay-specific data (e.g. the Company ID, or information about the user that is using the app). In prior versions of Vaadin, one would typically implement the PortletRequestListener interface which gives your app early access to the portal via the onRequestStart() interface. In Vaadin 7, this interface has been removed to simplify things and align with a more modern and modular architecture in Vaadin 7, but you can still get at all of the main Liferay entry points via the supplied VaadinRequest object and/or the VaadinPortletService class. Here is an example init() method in a Vaadin UI application:

@Override
public void init(VaadinRequest request) {
  // get the wrapped portlet request object
  PortletRequest req = VaadinPortletService.getCurrentPortletRequest();

  // get the companyId
  long companyId = PortalUtil.getCompanyId(req);

  // get the current User's name
  User currentUser = PortalUtil.getUser(req);
  String currentName = currentUser.getFullName();

  // ThemeDisplay
  ThemeDisplay themeDisplay = (ThemeDisplay)
      req.getAttribute(WebKeys.THEME_DISPLAY);

  // check permissions of a blog entry
  long scopeGroupId = themeDisplay.getScopeGroupId();
  PermissionChecker pc = themeDisplay.getPermissionChecker();
  if (!pc.hasPermission(scopeGroupId, BlogsEntry.class.getName(),
    entryId, "VIEW")) {
    // YOU SHALL NOT VIEW!!! 
  }
}

One thing to note: You can still use the PortletListener interface to provide custom logic as part of the different kinds of portlet requests (action, render, event, resource). However, be aware that these are usually not triggered until well after your UI's init() method, so you can't use these interfaces to get to portlet data during UI construction.

Service Builder and Data Binding

You can continue to use ServiceBuilder as you always have, and retrieve data from your services using XXXXXServiceUtil (or XXXXXLocalServiceUtil). For example, Mac shows us how to retrieve a list of all users in Liferay and populate a Vaadin table with the data. In this particular case, we just fetch the entire list of users out of Liferay, into memory, and bind it to the Vaadin component. If you have millions of users, this could run you out of memory very quickly unless you use paging parameters in a bit more intelligent manner.

One approach for large-scale data-driven applications is to bind Vaadin components directly to the database using something like Vaadin's SQLContainer. This works well for many environments, but not Liferay, as Liferay's database is essentially a private interface, with many levels of caching and consistency rules, that would be really easy to trash if one were to directly integrate to it. Instead, consider using an intermediary container interface like the LazyQueryContainer addon, allowing Vaadin components to incrementally retrieve data using a higher-level query mechanism, that can use Liferay's ServiceBuilder-generated interfaces to get at the data.

Liferay IPC and data sharing

The Liferay IPC addon is even easier to use in Vaadin 7 (you no longer have to add it to a layout, for example). In my example app, there are several places where IPC is used between portlets to update their UIs based on user interaction. The documentation for the Liferay IPC addon is in the process of being updated for Vaadin 7, but the examples on the addon homepage are enough for most use cases.

The main issue in IPC is in sharing data between portlets - often the case when portlets share large data sets that should not be passed as part of the IPC payload itself. Portlets can store large data as session attributes, getting and setting data like this:

// set the data
PortletSession portletSession =
  VaadinPortletService.getCurrentPortletRequest().getPortletSession();
portletSession.setAttribute("MyDataKey", theData,
    PortletSession.APPLICATION_SCOPE);

// get the data
PortletSession portletSession =
  VaadinPortletService.getCurrentPortletRequest().getPortletSession();
SomeType theData = (SomeType) portletSession.getAttribute("MyDataKey",
     PortletSession.APPLICATION_SCOPE);

Demo Application

Check out the source to the demo app that I showed during the webinar. It uses Vaadin Charts to visualize some sensor (iBeacon) data we collected at a Liferay event earlier this year. To use it, just add all 3 portlets to a page, and then click the Make Fake Data button to create some fake data in your Liferay deployment, and then select one of the events via the drop-down, and click around to exercise the data retrieval and IPC.

All of the above portal integration techniques are used - Vaadin-to-Vaadin IPC, Vaadin-to-Non-Vaadin IPC, data sharing via sessions, and retrieving data from Liferay. One thing that is not shown here is the use of Liferay permissioning - to see how that works, check out Sampsa's excellent video of his application - although this used Vaadin 6, the concepts are identical in Vaadin 7.

There are a lot of things happening in the Liferay+Vaadin world - stay tuned for more on this front!

Check out the recent Liferay+Vaadin Webinar

James Falkner
James Falkner is the Liferay Community Manager, and is responsible for educational outreach to other open source communities, onboarding new developers, educating existing users, and growing the Liferay ecosystem. You can follow him on Twitter – @schtool
Other posts by James Falkner