Sunday, 31 August 2014

Import Roles in Liferay 6.1


In previous post, we saw how to export Roles in Liferay 6.1 via xml.

Below is the code snippet for importing Roles along with Permissions in your Liferay Portal.
import com.liferay.portal.DuplicateRoleException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.struts.BaseStrutsPortletAction;
import com.liferay.portal.kernel.struts.StrutsPortletAction;
import com.liferay.portal.kernel.upload.UploadPortletRequest;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.model.Company;
import com.liferay.portal.model.Role;
import com.liferay.portal.service.CompanyLocalServiceUtil;
import com.liferay.portal.service.ResourceActionLocalServiceUtil;
import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
import com.liferay.portal.service.RoleLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* This class is responsible for importing roles along-with permissions.
*
*
*/
public class ImportRolesAction extends BaseStrutsPortletAction {
@Override
/**
* This method is called when user clicks on import roles. It extract the file datarequest
* and calls the importRoles function to import roles.
*/
public void processAction(StrutsPortletAction aOriginalStrutsPortletAction,
PortletConfig aPortletConfig, ActionRequest aActionRequest,
ActionResponse aActionResponse) throws Exception {
try {
UploadPortletRequest uploadRequest = PortalUtil
.getUploadPortletRequest(aActionRequest);
if (uploadRequest != null) {
File xmlFile = uploadRequest.getFile("importText", true);
SAXReader reader = new SAXReader();
Document document = reader.read(xmlFile);
Element root = document.getRootElement();
long userId = PortalUtil.getUserId(aActionRequest);
importRoles(userId, root);
}
} catch (Exception e) {
e.getMessage();
}
SessionMessages.add(aActionRequest, "successMessage");
String redirect = ParamUtil.getString(aActionRequest, "redirect");
aActionResponse.sendRedirect(redirect);
}
/**
* This method used liferay roles API to save the roles details of the
* xported ids and transform the information into XML.
*
* @param userId
* @param root
* @throws PortalException
* @throws SystemException
*/
private void importRoles(long userId, Element root) throws PortalException,
SystemException {
ResourceActionLocalServiceUtil.checkResourceActions();
Element rolesElement = root.element("roles");
Map<Long, Long> roleIdMapper = new HashMap<Long, Long>();
// iterate through child elements of rolesElement\
for (Iterator i = rolesElement.elementIterator(); i.hasNext();) {
Element roleElement = (Element) i.next();
long oldRoleId = Long.valueOf(roleElement.attributeValue("roleId"));
String name = roleElement.attributeValue("name");
String title = roleElement.attributeValue("title");
String description = roleElement.attributeValue("description");
String type = roleElement.attributeValue("type");
String subType = roleElement.attributeValue("subType");
String roleCompanyId = roleElement.attributeValue("companyId");
Company company = CompanyLocalServiceUtil.getCompany(Long
.valueOf(roleCompanyId));
if (company == null) {
throw new PortalException("Compnay not found with id :: "
+ roleCompanyId);
}
Map<Locale, String> descMap = new HashMap<Locale, String>();
descMap.put(Locale.getDefault(), description);
Map<Locale, String> titleMap = new HashMap<Locale, String>();
titleMap.put(Locale.getDefault(), title);
try {
// System.out.println("Add Role " + name);
Role role = RoleLocalServiceUtil.addRole(userId,
Long.valueOf(roleCompanyId), name, titleMap, descMap,
Integer.parseInt(type));
roleIdMapper.put(oldRoleId, role.getRoleId());
} catch (DuplicateRoleException e) {
roleIdMapper.put(oldRoleId, oldRoleId);
// System.err.println("Role already in system :: " + name);
}
Element permissionsElement = roleElement.element("permissions");
for (Iterator j = permissionsElement.elementIterator(); j.hasNext();) {
Element resourcePermissionElement = (Element) j.next();
String permissionName = resourcePermissionElement
.attributeValue("name");
long roleId = Long.valueOf(resourcePermissionElement
.attributeValue("roleId"));
roleId = roleIdMapper.get(roleId);
String actionId = resourcePermissionElement
.attributeValue("actionId");
int scope = Integer.parseInt(resourcePermissionElement
.attributeValue("scopeId"));
String primKey = resourcePermissionElement
.attributeValue("primKey");
Long resourceCompId = Long.valueOf(resourcePermissionElement
.attributeValue("companyid"));
ResourcePermissionLocalServiceUtil.addResourcePermission(
resourceCompId, permissionName, scope, primKey, roleId,
actionId);
}
}
}
}

Export Roles in Liferay 6.1

Many a times, it is required to have Import/Export functionality for Roles.
This functionality is already supported in Liferay 6.2 where we can do lar import/export for roles and organizations as well.

Below is the code snippet for Exporting Roles along with Permissions in the form of xml in Liferay 6.1.

Create a hook in liferay eg, RolesMgmt hook. Create a class called as ExportRolesAction which extends BaseStrutsPortletAction.

Refer below code for the same:

import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.servlet.ServletResponseUtil;
import com.liferay.portal.kernel.struts.BaseStrutsPortletAction;
import com.liferay.portal.kernel.struts.StrutsPortletAction;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.model.ResourceAction;
import com.liferay.portal.model.ResourcePermission;
import com.liferay.portal.model.Role;
import com.liferay.portal.service.ResourceActionLocalServiceUtil;
import com.liferay.portal.service.ResourcePermissionLocalServiceUtil;
import com.liferay.portal.service.RoleLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portal.kernel.util.WebKeys;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
public class ExportRolesAction extends BaseStrutsPortletAction {
@Override
/**
* This method is called when user clicks on export roles. It extract the exported role ids from request
* and calls the exprotRoles function to generate the XML.
*/
public void processAction(StrutsPortletAction aOriginalStrutsPortletAction,
PortletConfig aPortletConfig, ActionRequest aActionRequest,
ActionResponse aActionResponse) throws Exception {
try {
long[] ids = StringUtil.split(
ParamUtil.getString(aActionRequest, "addCommIds"), 0L);
String xmlResult = exportRoles(ids);
String fileName = "roles.xml";
byte[] bytes = xmlResult.getBytes();
HttpServletRequest request = PortalUtil
.getHttpServletRequest(aActionRequest);
HttpServletResponse response = PortalUtil
.getHttpServletResponse(aActionResponse);
ServletResponseUtil.sendFile(request, response, fileName, bytes,
ContentTypes.TEXT_XML_UTF8);
setForward(aActionRequest, "/common/null.jsp");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Sets the forward key in request.
*
* @param portletRequest
* @param forward
*/
protected void setForward(PortletRequest portletRequest, String forward) {
String portletId = (String) portletRequest
.getAttribute(WebKeys.PORTLET_ID);
String portletNamespace = PortalUtil.getPortletNamespace(portletId);
String forwardKey = portletNamespace.concat("PORTLET_STRUTS_FORWARD");
portletRequest.setAttribute(forwardKey, forward);
}
/**
* It removes out all roles which are not custom.
*
* @param roles
*/
private void validateRoles(List<Role> roles)
{
// Regular roles
String[] systemRoles = PortalUtil.getSystemRoles();
List<String> systemRoleNames = Arrays.asList(systemRoles);
// Organization roles
String[] systemOrganizationRoles = PortalUtil
.getSystemOrganizationRoles();
List<String> systemOrganizationRoleNames = Arrays
.asList(systemOrganizationRoles);
// Site roles
String[] systemSiteRoles = PortalUtil.getSystemSiteRoles();
List<String> systemSiteRoleNames = Arrays.asList(systemSiteRoles);
for (Iterator iterator = roles.iterator(); iterator.hasNext();) {
Role role = (Role) iterator.next();
if (systemRoleNames.contains(role.getName())
|| systemOrganizationRoleNames.contains(role.getName())
|| systemSiteRoleNames.contains(role.getName())
|| role.getName().contains("organization content author")
|| role.getName().contains("organization content admin"))
iterator.remove();
}
}
/**
* This method used liferay roles API to get the roles details of the
* exported ids and transform the information into XML.
*
* @param ids
* @return
* @throws IOException
* @throws SystemException
* @throws PortalException
*/
public String exportRoles(long[] ids) throws IOException, SystemException,
PortalException {
List<Role> roles = RoleLocalServiceUtil.getRoles(ids);
validateRoles(roles);
Document document = DocumentHelper.createDocument();
Element rootElement = document.addElement("root");
Element rolesElement = rootElement.addElement("roles");
for (Role role : roles) {
Element roleElement = rolesElement.addElement("role");
roleElement
.addAttribute("roleId", String.valueOf(role.getRoleId()));
roleElement.addAttribute("companyId",
String.valueOf(role.getCompanyId()));
roleElement.addAttribute("name", role.getName());
roleElement.addAttribute("title", role.getTitleCurrentValue());
roleElement.addAttribute("description",
role.getDescriptionCurrentValue());
roleElement.addAttribute("type", String.valueOf(role.getType()));
roleElement.addAttribute("subtype",
String.valueOf(role.getSubtype()));
Element permissionsElement = roleElement.addElement("permissions");
List<ResourcePermission> resourcePermissions = ResourcePermissionLocalServiceUtil
.getRoleResourcePermissions(role.getRoleId());
for (ResourcePermission resourcePermission : resourcePermissions) {
List<ResourceAction> resourceActions = ResourceActionLocalServiceUtil
.getResourceActions(resourcePermission.getName());
for (ResourceAction resourceAction : resourceActions) {
if (ResourcePermissionLocalServiceUtil.hasActionId(
resourcePermission, resourceAction)) {
Element resourcePermissionElement = permissionsElement
.addElement("permission");
resourcePermissionElement.addAttribute("name",
resourcePermission.getName());
resourcePermissionElement.addAttribute("companyid",
String.valueOf(resourcePermission
.getCompanyId()));
resourcePermissionElement.addAttribute("roleId",
String.valueOf(resourcePermission.getRoleId()));
resourcePermissionElement.addAttribute("actionId",
String.valueOf(resourceAction.getActionId()));
resourcePermissionElement.addAttribute("scopeId",
String.valueOf(resourcePermission.getScope()));
resourcePermissionElement
.addAttribute("ownerId", String
.valueOf(resourcePermission
.getOwnerId()));
resourcePermissionElement
.addAttribute("primKey", String
.valueOf(resourcePermission
.getPrimKey()));
}
}
}
}
return document.asXML();
}
}



Now, you can override view.jsp from path - /portal-web/docroot/html/portlet/role_admin/view.jsp
and add code to display buttons for Import Roles and Export Roles on front end.

So in addition to the existing code of view.jsp, you can add below code snippet for the import/export:


<script type="text/javascript">
Liferay.provide(
window,
'<portlet:namespace />exportRoles',
function() {
document.<portlet:namespace />fm.<portlet:namespace />addCommIds.value = Liferay.Util.listCheckedExcept(document.<portlet:namespace />fm1, "<portlet:namespace />allRowIds");
if(document.<portlet:namespace />fm.<portlet:namespace />addCommIds.value.length)
{
document.<portlet:namespace />fm.method = "post";
submitForm(document.<portlet:namespace />fm,
"<portlet:actionURL> <portlet:param name="struts_action" value="/roles_admin/export_role" /></portlet:actionURL>&etag=0&strip=0&compress=0", false);
}else {
alert("No rows selected.");
}
},
['liferay-util-list-fields']
);
Liferay.provide(
window,
'<portlet:namespace />importRoles',
function() {
if(document.<portlet:namespace />fm.importText.value==null || document.<portlet:namespace />fm.importText.value=='')
{
alert('Please select a valid file');
return false;
}
else if (confirm('<%= UnicodeLanguageUtil.get(pageContext, "are-you-sure-you-want-to-upload-file") %>')) {
submitForm(document.<portlet:namespace />fm,
"<portlet:actionURL> <portlet:param name="struts_action" value="/roles_admin/import_role" /></portlet:actionURL>&etag=0&strip=0&compress=0", false);
}
},
['liferay-util-list-fields']
);
</script>
view raw rolesView.jsp hosted with ❤ by GitHub
You can also add code for validating the checkboxes like disabling the checkboxes of default role types. In the next post I shall be giving sample code for Roles Import.

Thanks for reading!
Happy Learning!

Wednesday, 20 August 2014

Using Custom Fields/Custom Attributes in Liferay 6.1


Some time we may come across the need for adding a property or storing data associated with OOTB portlets. We dont need to create any new service. It can be done with the help of Custom Attributes or Custom Fields. Liferay provides this feature through Expando services.

The mechanism is supported by using 4 database tables: ExpandoTable, ExpandoColumn, ExpandoRow and ExpandoValue.

Expando values can be added to liferay objects like: Users, Documents and Media, Web Contents, Bookmarks, etc. through control panel and programmatically to the custom portlets as well.

For Custom-Portlets:

Create custom-fields for custom-table:
Suppose we want to create the custom fields into custom-table. e.g Let us create a custom field named
PrimaryTag and associate it with a custom portlet named VideoManagement.
Example code:
ExpandoBridge expandoBridge = vManag.getExpandoBridge(); //vManag is obj of class
if (!expandoBridge.hasAttribute("PrimaryTag")) {
expandoBridge.addAttribute("PrimaryTag");
}
view raw Expando1.java hosted with ❤ by GitHub

It will add an entry in all 4 expando-tables mapped with VideoManagement classname.


Display custom-fields into your webpage(for custom portlet)
Liferay provides below code to display custom fields on page for all the OOTB portlets.
Same code can be used in custom-portlet to display them as text fields.

<liferay-ui:custom-attributes-available className="<%= VideoManagement.class.getName() %>">
<aui:fieldset>
<liferay-ui:custom-attribute-list
className="<%= VideoManagement.class.getName() %>"
classPK="<%= (vManag != null) ? vManag.getPrimaryKey() : 0 %>"
editable="<%= true %>"
label="<%= false %>"
/>
</aui:fieldset>
</liferay-ui:custom-attributes-available>
view raw Expandos1.jsp hosted with ❤ by GitHub

In LocalServiceImpl add following code for storing expandovalue:


The way of setting value:

private void addCustomAttribute(long _companyId, String _className, String name, long _classPK, String value){
try {
ExpandoValueLocalServiceUtil.addValue( _companyId, _className, ExpandoTableConstants.DEFAULT_TABLE_NAME, name, _classPK,value);
}
catch (Exception e) {
// e.printStackTrace();
}
}

e.g addCustomAttribute(_companyId, _className, PrimaryTag", _classPK, “primaryTagValue”);
i.e. ExpandoValueLocalServiceUtil.addValue(classNameId, tableId, columnId, classPK, data);


The way of getting value:


Expando Table:
long videoClassNameId= ClassNameLocalServiceUtil.getClassNameId(VideoManagement.class.getName());
ExpandoTable table = ExpandoTableLocalServiceUtil.getDefaultTable(companyId, videoClassNameId );

Expando Column:
ExpandoColumn column = ExpandoColumnLocalServiceUtil.getColumn(tableId, name);


Expando Value:
ExpandoValueLocalServiceUtil.getValue(tableId, columnId, classPK);

where tableId is the id of default table, columnId the id of retrieved column and classPK the primary key of entity.

For OOTB portlets e.g journalArticle, we have to first create custom attributes from control panel.

The following code sets attributes for particular article using service context.

//Fetch Article
ExpandoBridge expandoBridge = article.getExpandoBridge();
expandoBridge.setAttributes(serviceContext);
com.liferay.portal.service.ServiceContext serviceContext = null;
try {
serviceContext = ServiceContextFactory.getInstance(JournalArticle.class.getName(), actionRequest);
} catch (PortalException e1) {
e1.printStackTrace();
} catch (SystemException e1) {
e1.printStackTrace();
}

Thanks for reading! Happy Learning!

Using Asset Category in Custom Portlet of Liferay 6.1

Many a times it is required that when one of our custom content is created we need to let the asset framework know. You just need to invoke a method of the asset framework. When invoking this method we can also let the framework know about the tags and/or categories of the content that was just authored.

This is the code you can put it to any jsp page for implementing category popup.

// vManag is the object which is refering to custom portlet named VideoManagement.

In JSP

<tr><td><b>Categories</b></td>
<%
String categoryId = null,categoryIds = "";
if(Validator.isNotNull(vManag)) {
if(Validator.isNull(vManag.getCategoryIds())){
categoryId = null; // while adding record
}else{
categoryId = vManag.getCategoryIds(); // get all catgs for that record
}
if(Validator.isNotNull(categoryId)){
String id[] = categoryId.split(",");
for(int i=0;i<id.length;i++)
{
if(String.valueOf(id[i]).equals("") || String.valueOf(id[i]).equals(null)){
//return;
}else{
List<AssetCategory> assetCategory = AssetCategoryLocalServiceUtil.getCategories();
for(AssetCategory aCat : assetCategory){
if(id[i].equals(String.valueOf(aCat.getCategoryId()))){
AssetCategory asset =(AssetCategory) AssetCategoryLocalServiceUtil .getCategory(aCat.getCategoryId());
if(Validator.isNotNull(asset.getCategoryId())){
categoryIds= categoryIds.concat(String.valueOf(asset.getCategoryId()));
if(i<id.length-1)
categoryIds= categoryIds.concat(",");
// append categoryId with comma except last
}
}
}
}
}
}
} %>
<td><liferay-ui:asset-categories-selector curCategoryIds='<%= Validator.isNull(vManag) ? "" : categoryIds %>'/></td></tr>


The tag <liferay-ui:asset-categories-selector> uses AssetCategoryServiceUtil.getCategories(className, classPK) to get the list of categories and populates the curCategoryIds from this list.

All the methods that you will need to invoke are part of the AssetEntryLocalService. In particular you should access these methods using either the static methods of AssetLocalServiceUtil or by using an instance of the AssetEntryLocalService injected by Spring.

First time you are adding record in custom table so you have to select cateogry from popup.It will show all categories in the category popup by specifying empty string in curCategoryIds and At the time of editing record you have to get categoryIds [like 45326,45327] from custom table that is already stored after adding record and then assign categoryIds to curCategoryIds in asset-categories-selector tag.

So you can see the category selected and if 'select' button is clicked, the same category is shown as checked and that will be useful when you editing any record of custom-table to show default selected values in that popup.

When user select any category from that popup. It will automatically create a hidden field with name assetCategoryIds in the same page.

<input type="hidden" value="45326,45327" name="_videosmanagement_WAR_videosmanagementportlet_assetCategoryIds" id="_videosmanagement_WAR_videosmanagementportlet_assetCategoryIds" class="aui-field-input aui-field-input-hidden">

In Java class

So here you can get the values of selected categoryIds like 45326,45327[two category selected in popup]

you can make entry in custom table for adding/editing record and also in assetEntry table for that same recordId.

This is the logic for making entry in assetEntry table for that recordId.

com.liferay.portal.service.ServiceContext serviceContext = null;
String categoryIds = ParamUtil.getString(actionRequest,"assetCategoryIds");
try {
serviceContext = ServiceContextFactory.getInstance( VideoManagement.class.getName(), actionRequest);
} catch (PortalException e) {
e.printStackTrace();
} catch (SystemException e) {
e.printStackTrace();
}
AssetEntry assetEntry = null;
try {
assetEntry = AssetEntryLocalServiceUtil.updateEntry(
userId,
groupId,
VideoManagement.class.getName(),
vManag.getVideoId(),
serviceContext.getUuid(),
"".equals(StringUtil.trim(categoryIds)) ? null: categoryIds, null, true, new Date(),null, release_date, null, "text/html", video_title,description, summary, url, 0, 0, null, false);
} catch (Exception e) {
LOGGER.debug("Error while Converting StringArray to LongArray ! :"
+ e.getMessage());
// e.printStackTrace();
}

userId :- is the identifier of the user who created the content.

VideoManagement.class.getName() :- which is the class name refering to custom portlet named VideoManagement.

vManag.getVideoId() :- represent as classPK which is unique recordId for that content[specify Id of that record which is already added/updated].

assetCategoryIds :- represent the categories that have been selected by the author of the content.

Url :- which specify the url of content i.e for videomanagement portlet you can specify videoURL.

Thanks for reading! Happy Learning!

Refer more,
https://www.liferay.com/documentation/liferay-portal/6.1/development/-/ai/asset-framewo-4