Remove Undeployed Portlets from Layouts

Hello Community,

Wanted to share the problem which our team recently faced and approach we took to solve that. It might be helpful for the users who already facing these kind of issues. Thanks to Liferay Advanced Scripting!

Problem Description:

In liferay portal there are couple of pages(around 100) and each page has couple of portlets. A portlet has multiple instances on each page with preferences and permissions. Portlet was undeployed, but the portlets information still on pages.

Observation: An undeloyed portlet from Liferay portal server only removes the portlet of visibility in the “Add Application” so that permission users can’t add that portlet to a page. But portlet instance information was not removed from layout and its preferences (user and layout level) and permissions. Still there is a mapping existed in tables from liferay schema.

When to use this Approach: Any undeployed portlet is used on layout in a group. Script will identify and remove its instance specific data from layouts.

Proposed Solution:  As Liferay provides cool feature of advanced scripting through which users can execute/call Liferay API from control panel. We can write below groovy script to identify the undeployed portltes and clean the unwanted data.

Scope: Only remove portlets information on layouts, I wll post how delete portlet information from portal permanently in next blog..

Demo

Step: 1 - Download Liferay Instance

Step: 2 - Download flashportlet (this only for example, you can deploy and underplay any custom portlet)

Step: 3 - Create 2 Liferay Pages and render Flash portlet

Step: 4 - Configure Portlet Preferences

Step-5 - Setup Portlet Permissions

Page1

Page2

Page/Layout Level Porlet Related Data

SELECT * FROM portletpreferences WHERE portletId LIKE '1_WAR_flash%';

SELECT * FROM resourcepermission WHERE NAME LIKE '1_WAR_flash%';

Step-6: Undeploy the flashportlet portlet

  1. Remove the flash-portlet webapp context from portal

cd %LIFE_HOME%\tomcat-7.0.42\webapps\flash-portlet

rm –rf flash-portlet

Step-7: Access Page1 and Page2 where you have render the portlet through admin

Note: You can disable portlet inactive alert message for normal user by using below property in portal-ext.properties layout.show.portlet.inactive=false

User can’t add the portlet from UI as it’s undeployed – working as expected

Validation: Even though portlet was undeployed still its information existed in liferay tables

SELECT * FROM portletpreferences WHERE portletId LIKE '1_WAR_flash%';

SELECT * FROM resourcepermission WHERE NAME LIKE '1_WAR_flash%';

Groovy Script Solution ( click here to download script)

import com.liferay.portal.service.PortletLocalServiceUtil

import com.liferay.portal.service.ResourceLocalServiceUtil

import com.liferay.portal.service.ReleaseLocalServiceUtil

import com.liferay.portal.model.Portlet

import com.liferay.portal.model.Layout

import com.liferay.portal.service.LayoutLocalServiceUtil

import com.liferay.portal.model.LayoutTypePortlet

import com.liferay.portal.model.LayoutType

// Param1: User ID

// Param2: Group ID

// Param2: isPrivateLayout

cleanGroupLayouts(10434, 10181, false)

def cleanGroupLayouts(userId, groupId, privateLayout){

    Set<Portlet> undeployedPortlets = new HashSet<Portlet>();

    long companyId = 0

    List<Layout> layouts= LayoutLocalServiceUtil.getLayouts(groupId, privateLayout)

    for(Layout layout: layouts){

        companyId = layout.getCompanyId();

        undeployedPortlets.addAll(deleteUndeployedPortlets(userId, layout))

    }      

}

def Set<Portlet> deleteUndeployedPortlets(userId, layout) {   

    LayoutTypePortlet layoutTypePortlet = (LayoutTypePortlet) layout.getLayoutType()

    List<Portlet> allPortlets = layoutTypePortlet.getPortlets()

    Set<Portlet> undeployedPortlets = new HashSet<Portlet>();  

    for(Portlet pagePortlet: allPortlets){

        if(pagePortlet.isUndeployedPortlet()){

            out.println pagePortlet.getPortletId()       

            layoutTypePortlet.removePortletId(userId, pagePortlet.getPortletId())

            undeployedPortlets.add(pagePortlet)

        }

    }

    LayoutLocalServiceUtil.updateLayout(layout.getGroupId(), layout.isPrivateLayout(),layout.getLayoutId(), layout.getTypeSettings())  

    return undeployedPortlets

}

Explanation

Get Group Layouts(public and private)

List<Layout> layouts= LayoutLocalServiceUtil.getLayouts(groupId, privateLayout

Identify the undeployed portlet - if(pagePortlet.isUndeployedPortlet())         

Remove Porlet - layoutTypePortlet.removePortletId(userId, pagePortlet.getPortletId())

Script Output

UI Validation (No Undeployed Portlets)

DB Validation (No Data related to page level)

SELECT * FROM portletpreferences WHERE portletId LIKE '1_WAR_flash%';

SELECT * FROM resourcepermission WHERE NAME LIKE '1_WAR_flash%';

References:

1. Groovy Script
2. Demo

 

Blogs