Double seven, Vaadin 7 with Liferay 7

Technical Blogs 5. August 2015 Von Sampsa Sohlman Staff

First of all announcement for Vaadin developers:

As from issue LPS-57525 we are not shipping Vaadin with Liferay core anymore. But no worries, Vaadin can be deployed to Liferay 7 as a set of OSGi components.

Preface:

So as everyone who follows Liferay product development knows that Liferay 7 is a big step towards of modularity and this modularity is achieved with OSGi framework.

Vaadin on the other hand has been supporting OSGi for quite a while and you can find blogs and articles around that. 

Why modularity? When you think modular way you - you think light. Your solution is not a heavy war bundle containing all the necessary dependencies (jars), but web of light weight interconnected bundles and using API's and services from each other. 

So for Liferay 7 it would be natural to develop Vaadin 7 applications with OSGi modularity in mind. So I decided to create proof of concept and try it out.

Proof of consept

Platform

As platform I did use Liferay 7 milestone 6 and Vaadin 7.5.1 and build tool I used maven so you can easily to build the PoC and deploy it.

Actual development

When you start developing Vaadin application, first step is to configure Vaadin portlet, which job is to initialize the UI object. This is normally done at portlet.xml, but I decided to take the OSGi component approach, where you do this by creating portlet component and at property configuration to tell where is the Vaadin's UI class is located.

@Component(
        immediate = true,
        property = {
                "com.liferay.portlet.display-category=category.vaadin",
                "com.liferay.portlet.instanceable=true",
                "javax.portlet.display-name=Vaadin OSGi PoC Portlet",
                "javax.portlet.init-param.UI=com.liferay.vaadin.poc.ui.PortletUI",
                "javax.portlet.security-role-ref=power-user,user"
        },
        service = Portlet.class
)
/**
 * @author Sampsa Sohlman
 */
public class VaadinPortlet extends com.vaadin.server.VaadinPortlet {

}

Then we need our UI class, but there is nothing really special. Just plain old Vaadin UI class, nothing OSGi specific.

@Theme("valo")
@SuppressWarnings("serial")
/**
* @author Sampsa Sohlman
*/
public class PortletUI extends UI {
    @Override
    protected void init(VaadinRequest request) {
            // Full implementation here : click the link
    }
 }

As we are creating an OSGi module we need to add the necessary entries to MANIFEST.MF, which we can do with maven-bundle-plugin.

<plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>2.5.4</version>
    <extensions>true</extensions>
    <configuration>
        <instructions>
            <Private-Package>com.vaadin.portlet,com.liferay.vaadin.ui</Private-Package>
            <Import-Package>
                javax.portlet;version="[2.0,3)",
                javax.servlet;version="[2.5,4)",
                com.vaadin.ui;version="[7.4.6,8)",
                com.vaadin.server;version="[7.4.6,8)",
                com.vaadin.annotations;version="[7.4.6,8)",
                com.vaadin.data.util;version="[7.4.6,8)",
                com.vaadin.data;version="[7.4.6,8)</Import-Package>
            <_dsannotations>*</_dsannotations>s
        </instructions>
    </configuration>
</plugin>

Trouble

Everything up to this point went as I planned, but then I ran into trouble. Even though all the required Vaadin jars did deploy nicely to Liferay's OSGi container, the vaadin-server.jar was missing the required MANIFEST import entries to work properly with Liferay's portlets. Luckily, the problem was solved by adding missing manifiest import entries. So the fix was easy and I did repackage vaadin-server.jar with new manifest entries with maven shade plugin

Second problem was how to serve required widgetset and theme resources. This I did accomplish by adding OSGI servlet, which is serving content from classpath, which I feel kind of hack, but was sufficient for the PoC. 

Finally my PoC application was working at Liferay 7's OSGi container.

Resources

You can find example project from github. It should be deployable to Liferay 7 m6 (and self compiled master).

https://github.com/sammso/liferay-vaadin7-osgi

Future

Of course, I started discussion with Vaadin guys and that did result ticket https://dev.vaadin.com/ticket/18561 so future Vaadin versions of Vaadin will include correct manifest entries and we will figure out also how fix serving resources at Liferay 7.

UPDATE:

  • 2015-08-21: Vaadin 7.5.4 version has been released with fix for 18561 is fixed. Also PoC has been updated to match Vaadin 7.5.4 versio.

Not so well known feature - ResourceBlock Permissions

Technical Blogs 28. April 2015 Von Sampsa Sohlman Staff

Introduction

I decided to write this blog as I did find out that this is the area of the Liferay that has not been documented at all?  So this blog post can act as documentation for this. So let's talk about entity/model permissions and especially ResourceBlock permission.

If you are not familiar with Liferay’s permission system I would suggest that you go and first read our documentation or even better to participate our wonderful Developer 1 training before continuing your journey with this blog post.

As you are ready to learn!

As now you are continuing the reading, I can assume that you now are familiar how to implement permissions checking and how to filter results with filterFindBy<..>(..).

What we teach on our courses or our documentation is mainly how to implement entity/model permissions with ResourcePermissions, but we are not talking ResourceBlock permissions at all.

As you might know ResourcePermission table is place where the permissions are stored and primKey contains information of the entity's primary key. So basically every entity/model at Liferay will generate one or more rows to ResourcePermission table.

This also means that, ResourcePermission table size grows quickly. When you look this more carefully, you find out that same permission pattern is replicated over and over again. This means that, you can expect the ResourcePermission table to be huge with large Liferay DB. So if you have 1 000 000 entity rows your resourcePermission table might easily contain 6 000 000 rows.

What ResourceBlock is bringing to this?

ResourceBlock permissioning has brought improvement for this by minimizing data duplication by introducing ResourceBlock system.

When using ResourceBlockPermissions, then these similar permissions sets are recognized as blocks,and stored only once so less duplicated information is stored. This is done automatically for you and new block is created if the new combination of permissions has been found. Permission set is recognized by calculation unique permissionHash. There is also difference how the RecourceBlock is bound to the entity/model. With ResourceBlock permissions entity/model's primary key is not used for filtering rows or checking access, but special resourceBlockId, which is required to be added to the entity/model. This causes your entity to implement PermissionedModel interface and that is also how Liferay knows that you are using ResourceBlock permissions.

Let's go and see how to implement ResourceBlock permissions "step by step"

Make sure that your entity has resourceBlockId at your entity defintion at service.xml.

<!-- Permission fields -->

<column name="resourceBlockId" type="long" />

Create default.xml and register that to portlet.properties.

Run ServiceBuilder and you see that our entity is implementing PermissionedModel

public interface Foo extends FooModel, PermissionedModel {

}

Register your entity at your LocalService layer were you persist your entity.

foo = fooPersistence.update(foo);

serviceContext.setAddGuestPermissions(true);
serviceContext.setAddGroupPermissions(true);

resourceLocalService.addModelResources(foo, serviceContext);

also remember to remove resource if when you are deleting the entity/model.

resourceLocalService.deleteResource(foo, ResourceConstants.SCOPE_INDIVIDUAL);
return super.deleteFoo(foo);

Basically that's it smiley .. hopefully did remember all steps. 

See also example app below.

Where this is used?

Currently Bookmarks and Calendar are using ResourceBlocks.

Performance:

With MySQL/MariaDB adding entities with ResourceBlock permissioning is slower, but reading is hugely faster. With ResourceBlock and millions of data is unlikely that read will come a problem.

Examples:

Take a look the example application at github, which contains both example with ResourcePermission and ResourceBlockPermission implementation.

https://github.com/sammso/tester-liferay-permission

Issues:

While writing this, blog I did found out that ResourceBlock has little hickup and seems to leave orphan rows to ResourceBlockPermission table, but that does not effect performance. Issue: LPS-55244

Trying the AngularJS with Liferay

Company Blogs 3. Februar 2014 Von Sampsa Sohlman Staff

One of the current front-end trends is seems to be AngularJS. Last week we had HelsinkiJS Meetup and again there were couple presentations talking about AngularJS. Our Developer Unconfrence at Berlin we had an unconfrence discussion about AngularJS. So AngularJS is for sure the framework that Liferay developers are keen to use.
 
I decided to take a look AngularJS and how to use that in portlet development. Using any framework with portlets means that they should behave well in portlet world. So the first task is to see if AngularJS is up to it. Behaving well in portlet world means that the framework has to have tools so it can respect the portal environment. As a normal web application, front end developer has total freedom to create what they want, but when they are stepping into portal world, their creation has to fit in limitation of the portlet. 
 
 
As most of you already know, portlet's UI limitation is rendering area, which means that portlet should always stick to its area. See the image. Traditional portlet developers we have tools as <portlet:namespace/> to achieve this. So I want to test if AngularJS can achieve this.
 
By looking AngularJS tutorial I see that AngularJS application contains modules, which have controllers. AngularJS tutorial shows, how bind module to view:
 
<html ng-app="myapp">
..
</html>
 
By looking this, my first impression is that AngularJS is not portlet ready since portlet does not own the page. As I study further reading it is clear ng-app does not have to be bound to html tag, but it can be bound to any tag. Next question can you have multiple tags with ng-app attributes same time at page as we can have multiple portlets and also multiple portlet instances. Quick proof of concept proofs other vice, so there can be only one ng-app attribute per page. So AngularJS seems to be failing the portlet world, but I decided to dig deeper and after further study I did find out that ng-app can be replaced by API call:
angular.bootstrap(<dom element>,<list of modules>);

Finally, I could confirm that with this API call it is possible have multiple AngularJS modules at one page and be bound to multiple dom elements.

This did lead me to integrate this Liferay.Portlet.ready(..) event and I did result following framework (angular-portlet.js):

(function(Liferay, angular) {
   if (angular.portlet)
      return;

   angular.portlet = {};

   var angularPortlets = {};

   angular.portlet.add = function(pluginName, portletName, angularFunction) {
      var portletId = "_WAR_" + pluginName.replace(/[_]|[-]/g, "");

      portletId = portletName.replace(/[_]|[-]/g, "") + portletId;
      angularPortlets[portletId] = angularFunction;
   };

   Liferay.Portlet.ready(function(portletInstanceId, node) {
      var portletId = portletInstanceId.replace(/[_]INSTANCE[_].+/g, "");

      if (angularPortlets[portletId]) {
         angular.bootstrap(node.getDOMNode(), angularPortlets[portletId](
            portletInstanceId, node.getDOMNode()));
      }
   });
})(Liferay, angular);

The framework is using plugin name + portlet name to register AngularJS modules to specific portlet. During the Liferay.portlet.ready event the module is bound to the portlet's dom element.

Following example demonstrate how this is done:

(function(Liferay, angular) {
   angular.portlet.add("poc-angular-portlet", "poc-angular-portlet",
      function() {
         var myModule = angular.module("myModule", []);

         myModule.controller("MyController", function($scope) {
            $scope.mythings = [ {
               name : "Thing 1"
            }, {
               name : "Thing 2",
            } ];

            $scope.add = function() {
               $scope.mythings.push({name: $scope.newThing.name});
            };

            $scope.remove = function(index) {
               $scope.mythings.splice(index, 1);
            };
         });

         return [ myModule.name ];
      });
})(Liferay, angular);
Here you can see that code is same as AngularJS JavaScript except you just have to wrap it to function and that to angular.portlet.add(..) with plugin name and portlet-name.
 
and correseponding html:
<div ng-controller="MyController">
    <h1>My Things</h1>
    <input ng-model="newThing.name"/>
    <button ng-click="add();">Add</button>
    <div ng-repeat="mything in mythings">
        <span>{{mything.name}}</span>
        <button ng-click="remove($index);">Remove</button>
    </div>
</div>
As you can see that there is no <portlet:namespace/> tags in HTML, since AngularJS only is scanning markup inside bootstrap element. 
As you can see portlet works well also as instantiable and this seems to be a good start to AngularJS portlet development.
 
Example app:
 
Thanks to make this possible:
EDIT 11th May 2014: It seems that Liferay js minifier does not like angularjs and as on my development portal it is disabled, so it did not appeared to me. Thanks for Miika Alonen for finding this.
 
You can disable minifier from portal-ext.properties
minifier.enabled=false
 
Zeige 3 Ergebnisse.