Liferay DXP Configuration Portlet

Posted on 15/09/2017 by

Author: Dimos Kitsios (trainee in Technopolis SA)

*This example is a case study and the code it's not in his final form!*

This article is about my intership in [Technopolis S.A.]( . It was my first summer working in a company and it was pretty interesting.I was 2 months there and my superior told me to develop a project based on gitlab that company uses. I had to learn to use the Gitlab API, more specific, i had to use the USERS API and PROJECTS API. My goal was to create a portlet with a setup configuration.This setup,was the options behind the portlet that the user make the changes and setup the portlet in his way.Then, when the user has set up the portlet's configuration, a table about the projects and the users that was part of each chosen project will be shown on screen with the number of commits and comments each user has made to each project. Let's get started!!


The first thing i had to do was to create 3 modules *, two for the rest client and one for the portlet*:

1. First was the api.

2. Second was the module that implements the methods of first.

3. Third was the one that run the portlet and control the configuration system.


Lets talk about the first one: The API has 5 methods:

1. The first one was to get the users from gitlab.

2. The second one was to get the projects from gitlab.

3. The third one was to get only the names of projects from gitlab.

4. The fourth one was to get the number of commits from each project.

5. The fifth one was to get the comments for each commit the user has made.



Also,this module has two Objects, USER and PROJECT.


Lets talk about the second one: We will see one of those 4 methods and speak a little about it


public List<Project> getProjects() {
        HttpClient client = new HttpClient();
        String urlProjects = "{{TOKEN_KEY}}&per_page=100";
        GetMethod methodProjects = new GetMethod(urlProjects);
                new DefaultHttpMethodRetryHandler(3, false));
        try {
            int statusCode = client.executeMethod(methodProjects);
            if (statusCode != HttpStatus.SC_OK) {
                System.err.println("Method failed: " + methodProjects.getStatusLine());
        } catch (IOException e) {
        List<Project> projects = new ArrayList();
        try {
            String responseBody = methodProjects.getResponseBodyAsString();
            JSONArray allProjects = JSONFactoryUtil.createJSONArray(responseBody);
            for (int i = 0; i < allProjects.length(); i++) {
                JSONObject project = allProjects.getJSONObject(i);
                int id = project.getInt("id");
                String name = project.getString("name_with_namespace");
                Project p = new Project(id, open_issues_count, name, null, null);
        } catch (IOException e) {
        } catch (JSONException e) {
        return projects;


Lets take it from the beggining. The gitlab api has some characteristics about how to access it and that is a `private token` and this `/api/v4/`. So the first thing we have to do is to create a token.Tokens are in two categories, for simple users and admins.The admin tokens have much more info, so we have created an admin one!The other thing about the url is that we dont need to make many http requests,with that i mean that we want to have all projects in one tab,other way for example,if the projects are 50 and each tab has 10 then we had to make 5 http requests,so we use `&per_page=100` to make one http request. All this about the url...

Next we try to execute of the method and try to check the result of it,if it failed then we retry 3 times.After this step finishes with success we have to get the info as String so we get handle it with more ease.

This is an example of the data of a project.

json [ { "id": 4, "description": null, "default_branch": "master", "visibility": "private", "ssh_url_to_repo": "", "http_url_to_repo": "", "web_url": "", "tag_list": [ "example", "disapora client" ], "owner": { "id": 3, "name": "Diaspora", "created_at": "2013-09-30T13:46:02Z" }, "name": "Diaspora Client", "name_with_namespace": "Diaspora / Diaspora Client", "path": "diaspora-client", "path_with_namespace": "diaspora/diaspora-client", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, "jobs_enabled": true, "wiki_enabled": true, "snippets_enabled": false, "resolve_outdated_diff_discussions": false, "container_registry_enabled": false, "created_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z", "creator_id": 3, "namespace": { "id": 3, "name": "Diaspora", "path": "diaspora", "kind": "group", "full_path": "diaspora" }, "import_status": "none", "archived": false, "avatar_url": "", "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, "runners_token": "{{TOKEN_KEY}}", "public_jobs": true, "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, "request_access_enabled": false, "statistics": { "commit_count": 37, "storage_size": 1038090, "repository_size": 1038090, "lfs_objects_size": 0, "job_artifacts_size": 0 }, "_links": { "self": "", "issues": "", "merge_requests": "", "repo_branches": "", "labels": "", "events": "", "members": "" }, }, { "id": 6, "description": null, "default_branch": "master", "visibility": "private", "ssh_url_to_repo": "", "http_url_to_repo": "", "web_url": "", "tag_list": [ "example", "puppet" ], "owner": { "id": 4, "name": "Brightbox", "created_at": "2013-09-30T13:46:02Z" }, "name": "Puppet", "name_with_namespace": "Brightbox / Puppet", "path": "puppet", "path_with_namespace": "brightbox/puppet", "issues_enabled": true, "open_issues_count": 1, "merge_requests_enabled": true, "jobs_enabled": true, "wiki_enabled": true, "snippets_enabled": false, "resolve_outdated_diff_discussions": false, "container_registry_enabled": false, "created_at": "2013-09-30T13:46:02Z", "last_activity_at": "2013-09-30T13:46:02Z", "creator_id": 3, "namespace": { "id": 4, "name": "Brightbox", "path": "brightbox", "kind": "group", "full_path": "brightbox" }, "import_status": "none", "import_error": null, "permissions": { "project_access": { "access_level": 10, "notification_level": 3 }, "group_access": { "access_level": 50, "notification_level": 3 } }, "archived": false, "avatar_url": null, "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, "runners_token": "{{TOKEN_KEY}}", "public_jobs": true, "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, "request_access_enabled": false, "statistics": { "commit_count": 12, "storage_size": 2066080, "repository_size": 2066080, "lfs_objects_size": 0, "job_artifacts_size": 0 }, "_links": { "self": "", "issues": "", "merge_requests": "", "repo_branches": "", "labels": "", "events": "", "members": "" } } ]


From all this we need 2 values:the "id" and "name_with_namespace" ,then create one object for each project and add them to an array of Projects.


Now lets talk about the third one and the most troublesome!!This portlet has 2 classes,one to control the page in which the final table has to display and the other was necessary for the configuration system. Lets start with the first from above,the role of this class is to get the data that user has chosen from the configuration setup and just display that info,its simple right?. No,every guide i found and i tried was missing just one thing,a property! If you know how liferay works,liferay works with modules, modules have properties each one for a difference reason. It was missing this property:

The other class is a class which extends the "DefaultConfigurationAction". In this class we have to care about just 3 things,the first is the property of the module,it must be the same with the property from the previous class


The second one is

target = (osgi.web.symbolicname=test)

The valute "test" is a value of mine,you can find this value and change it at

``bnd.bnd`` file at field ``Bundle-SymbolicName``

Last is the name of jsp file for configuration system,for some reason it must me named


All we have to do now is to run the 3 modules localhost,when the modules have loaded we have to add the portlet to our page,the we have to go to the right side of portlet and press the 3 bullets. After then,press Configuration,setup the portlet and press Save. All we have to do now is Refresh the page and the table will be displayed!




Liferay DXP Configuration Portlet
This entry was posted in Liferay and tagged Liferay DXP, liferay 7, Configuration by

Add new comment

The gitlab api has some characteristics about how to access it, so the first thing we have to do is to create a token.