Not so well known feature - ResourceBlock Permissions

Technical Blogs April 28, 2015 By 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 February 3, 2014 By 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
 
Showing 2 results.