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
- 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


