Tuesday, 25 November 2014

Aspera File Transfer Integration with Liferay and Alfresco


About Aspera:

Many a times, we have requirement for transferring large amount of files. 

  • Aspera software solutions helps us to move large volumes of data over public and private IP networks efficiently.
  • Aspera works on fasp™ transfer technology.
  • This technology delivers maximum transfer speed regardless of network conditions and transfer distance. 
  • It eliminates the inherent weaknesses of conventional file transfer technologies such as FTP, HTTP and dramatically speeds transfers over public and private IP networks securely. 
  • Also it tracks down failed file transfers. And if destination server is down, Aspera automatically resumes partial transfers and retries failed transfers.

For more Information : AsperaSoft




 Liferay Portal can be used as front end and AlfrescoECM as backend technology for File Transfers:

1. Download Aspera Connect Plugin from http://downloads.asperasoft.com
2. Create a custom portlet in Liferay that allows users to upload files. 
3. Configure Aspera API to upload multiple files to Aspera Connect (Aspera Server).  
4. Aspera server is configured to inject the files into Alfresco repository using REST based API.


Alfresco Server:
The content ingestion is performed using importer script. The importer can be deployed by copying the 'webscripts' directory (and all its contents ) to [Alfresco_HOME]/ tomcat/shared/classes/alfresco/extension/templates. The 'templates' directory shall not be existing so create it prior to copying.


Note that in [ALFRESCO_HOME]/tomcat/shared/classes/alfresco-global.properties, 
"dir.root" property is set to an absolute path. This path will also be used for Aspera Server as docroot directory.

Create a new site in Alfresco repository via Alfresco Share. Create a folder in the site, eg. uploadsFromAspera. 
This folder will be the root directory for all the uploads that will be done.
It also is the root directory for all the contents that will be ingested into the Alfresco CMS.
From Alfresco view point, this folder will referenced using either its nodeRef or its path. Both values can be fetched using the administration console.

We can use the Repository Browser - http://HOSTNAME:PORT/share/page/repository - to navigate and get the path of the newly created folder:
eg. Sites/siteName/documentLibrary/uploadsFromAspera

Aspera Server:
In [ASPERA_HOME]/etc/aspera.conf, configure the docroot directory to be at least a sub-directory of Alfresco ${dir.root}/contentstore.
Eg. FILE: [ALFRESCO_HOME]/tomcat/shared/classes/alfresco-global.properties
dir.root=C:/Alfresco/alf_data
FILE: [ASPERA_HOME]/etc/aspera.conf

Liferay:
There is metadata information needed by Alfresco importer (name, title,
description, mime-type, encoding, locale of file to be uploaded).
 There is a front end directory provided by Aspera which contains several Javascript files:
- e.g. - asperaweb-2.js : the Aspera Connect plugin API

Custom portlet developed in Liferay, needs to provide below information:

- a transfer specification object

transferSpec = {
"paths": [],
"remote_host": remoteAsperaServer,
"remote_user": remoteUser,
"remote_password": remotePassword,
"direction": "send",
"target_rate" : 5000,
"resume_check" : "sparse",
"create_dir":true
};

- a call to perform the upload

asperaWeb.startTransfer(transferSpec, aspera_connect_settings, callbacks = {
error : function(obj) {
console.log("Upload failed to start : " +
JSON.stringify(obj, null, 4));
},
success:function () {
console.log("success ...");
disableButton("#upload_form
#upload_button");
}
});

Encode the content’s metadata as cookie for the transfer specification. Cookie format:

COOKIE="mimetype":" encoding":"locale":"cm:title":"cm:name":"cm:description";
Example:
cookie="video/mp4 : UTF-8: en_US_: My Title:my_file.mp4: My description"
The metadata can also be encoded using tags attributes of transferSpec. Tags convention for transfer specification is tags.company or tags.domain. 


Aspera Pre/Post Processing
The uploaded file are available in the docroot path configured in aspera.conf (configuration file of Aspera Server). To make the link with Alfresco CMS, the content will be ingested in CMS when the upload is completed. Aspera pre/post processing offers the possibility to run programs on the occurrence of events during the lifetime of transfer session and transfer files. When a file is successfully uploaded (two conditions TYPE is file and STATE is success), a script (ingest.pl - perl script ) is called to perform the ingestion into CMS. The ingestion is done using the REST API supplied by Alfresco.

Thanks for reading. Happy Learning! 


Thursday, 18 September 2014

Custom AUI Validation in Liferay 6.1


Implementing a custom rule for non-alphabets using AUI Validator:
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<aui:form action="/abc" method="post" name="form">
<aui:input name="textitemname" label="Text Item Name" class="aui-field-required" value="" size="40">
</aui:input>
<br/><br/><aui:button cssClass="save" value="Save" type="submit"></aui:button>
</aui:form>
<script type="text/javascript" charset="utf-8">
AUI().ready('aui-form-validator', 'aui-overlay-context-panel', function(A) {
A.mix(
YUI.AUI.defaults.FormValidator.RULES,
{
alphaRule: function(val, fieldNode, ruleValue) {
if(val != ""){
var arr = val.match(/^[a-zA-Z0-9_]*$/);
if(arr == null){
return false;
}else{
return true;
}
}
return true;
}
},
true
);
var validator2 = new A.FormValidator({
boundingBox: document.<portlet:namespace/>form,
rules: {
<portlet:namespace />textitemname:{
required: true,
alphaRule:true
}
},
fieldStrings: {
<portlet:namespace />textitemname: {
required: 'TextName Required',
alphaRule: 'None other than alpha characters'
}
},
on: {
validateField: function(event) {
},
validField: function(event) {
},
errorField: function(event) {
},
submitError: function(event) {
alert("submitError");
var formEvent = event.validator.formEvent;
var errors = event.validator.errors;
},
submit: function(event) {
alert("Submit");
var formEvent = event.validator.formEvent;
return false;
}
}
});
});
</script>

A simple program to compare Start Date and End Date using AUI Validator:

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<aui:form action="/abc" method="post" name="form">
<div class="aui-field-content" id="datePicker">
<table>
<tr>
<td><aui:input label="Start Date" name="startDate" size="20">
<aui:validator name="required" errorMessage="Start Date is required. Select a value." />
</aui:input>
</td>
<td valign="top" style="padding-top: 18px">
<div class="aui-datepicker-button-wrapper">
<button class="aui-buttonitem-content aui-widget aui-component aui-buttonitem aui-state-default aui-buttonitem-icon-only"
id="startDate" type="button">
<span class="aui-buttonitem-icon aui-icon aui-icon-calendar"></span>
</button>
</td>
</div>
</tr>
</table>
</div>
<div class="aui-field-content" id="datePicker1">
<table>
<tr>
<td><aui:input label="End Date" name="endDate" size="20">
<aui:validator name="required" errorMessage="End Date is required. Select a value."/>
<aui:validator name="custom"
errorMessage="Leave blank or enter a date greater than the begin date.">
function(val, fieldNode, ruleValue)
{
var startDateObj = document.getElementById("<portlet:namespace />startDate");
var startDate;
var result=false;
//case when end date is blank
//no validation required then
if(val == ""){
return true;
}
if(startDateObj) {
startDate = new Date(startDateObj.value);
}else{
result = false;
}
var endDate = new Date(val);
if(startDate && endDate){
result = endDate.getTime()>startDate.getTime();
}else{
result = false;
}
return result;
}
</aui:validator>
</aui:input>
</td>
<td valign="top" style="padding-top: 18px">
<div class="aui-datepicker-button-wrapper">
<button class="aui-buttonitem-content aui-widget aui-component aui-buttonitem aui-state-default aui-buttonitem-icon-only" id="endDate" type="button">
<span class="aui-buttonitem-icon aui-icon aui-icon-calendar"></span>
</button>
</td>
</div>
</tr>
</table>
</div>
<br/><br/><aui:button cssClass="save" value="Save" type="Submit"></aui:button>
</aui:form>
<script type="text/javascript" charset="utf-8">
AUI().ready('alloy-node','aui-form-validator', 'aui-overlay-context-panel', 'aui-datepicker', function(A) {
var startDate = new A.DatePicker({
trigger: '#<portlet:namespace />startDate',
calendar: {
dateFormat: '%m/%d/%Y',
},
yearRange: [1990, (new Date).getFullYear()]
}).render('#datePicker');
A.one("#startDate").on("click", function () {
startDate.show();
});
var endDate = new A.DatePicker({
trigger: '#<portlet:namespace />endDate',
calendar: {
dateFormat: '%m/%d/%Y',
},
yearRange: [1990, (new Date).getFullYear()]
}).render('#datePicker1');
A.one("#endDate").on("click", function () {
endDate.show();
});
});
</script>
Many a times it is required, that we want to provide rules to dynamically added fields.
We can use current validator and iterate over rules by passing rowId:

var rules = validator2.get('rules'); // get current validator
rules['<portlet:namespace />info' + dynamicRowId] = {required: true};
rules['<portlet:namespace />desc' + dynamicRowId] = {required: true, maxLength: 255};

Tuesday, 2 September 2014

Flickr Integration with Liferay


Many a times, we work with clients who like to maintain their account using several Social Media Tools. We might require to display them in the form of feeds by pulling data from one of their accounts.

I have taken an example of Flickr here. We can create a Liferay portlet and show public contents by configuring flickr feed id and number of feeds on web page.



Create a  Liferay portlet eg. FlickrApp Portlet. 

In liferay-portlet.xml specify your configurationAction class let say FlickrConfigurationActionImpl.

In FlickrConfigurationActionImpl, you need to add code for storing preferences. 
Below is sample code:
package com.test.flickr.portlet.controller;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletPreferences;
import javax.portlet.ReadOnlyException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ValidatorException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.portlet.ConfigurationAction;
import com.liferay.portal.kernel.servlet.SessionErrors;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.util.Constants;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portlet.PortletPreferencesFactoryUtil;
public class FlickrConfigurationActionImpl implements ConfigurationAction {
private static Log log = LogFactoryUtil.getLog(FlickrConfigurationActionImpl.class);
public String render(PortletConfig portletConfig,
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException,PortalException {
return "/html/configuration.jsp";
}
public void processAction(PortletConfig portletConfig,
ActionRequest actionRequest, ActionResponse actionResponse)
{
String portletResource = ParamUtil.getString(actionRequest, "portletResource");
PortletPreferences preferences = null;
try {
try {
preferences = PortletPreferencesFactoryUtil.getPortletSetup(actionRequest, portletResource);
} catch (PortalException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String flickrFeed = ParamUtil.getString(actionRequest, "flickrFeed");
String numberFeed = ParamUtil.getString(actionRequest, "numberFeed");
String cmd = ParamUtil.getString(actionRequest, Constants.CMD);
if(cmd.equalsIgnoreCase(Constants.UPDATE)){
preferences.setValue("flickrFeed", flickrFeed);
preferences.setValue("numberFeed", numberFeed);
if (SessionErrors.isEmpty(actionRequest)) {
preferences.store();
SessionMessages.add(actionRequest, "success");
}
}
} catch (SystemException e) {
log.info("System exception");
}catch (IOException e) {
log.info("Io exception");
}
catch (ReadOnlyException e) {
log.info("Error while setting value in preferences");
}
catch (ValidatorException e) {
log.info("Error in storing value in preferences");
}
}
}
In configuration.jsp, you need to write logic for providing preferences i.e. showing inputs for feeds.
<%
PortletPreferences preferences = renderRequest.getPreferences();
String portletResource = ParamUtil.getString(request, "portletResource");
if (Validator.isNotNull(portletResource)) {
preferences = PortletPreferencesFactoryUtil.getPortletSetup(request, portletResource);
}
String flickrFeed = preferences.getValue("flickrFeed","12037949754@N01"); // default Id in Feed
String numberFeed = preferences.getValue("numberFeed","3");
%>
<liferay-ui:success key="success" message="Successfully saved" />
<liferay-portlet:actionURL portletConfiguration="true" var="configurationActionURL" />
<form action="<%= configurationActionURL %>" method="post" name="fm">
<input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.UPDATE %>" />
<fieldset class="block-labels">
<legend><liferay-ui:message key="Configuration for Flickr" /></legend>
<aui:input label="Flickr Feed Id" name="flickrFeed" type="text" value="<%= flickrFeed %>" />
<aui:input label="No of Feed" name="numberFeed" type="text" value="<%= numberFeed %>" />
</fieldset>
<br/>
<input name="submit" type="submit" value="Save" />
</form>


In view.jsp, you need to add logic for storing preferences:
<%
String ctxPath = request.getContextPath();
if (ctxPath != null && ctxPath.length() == 1)
{
ctxPath = "";
}
PortletPreferences preferences = renderRequest.getPreferences();
String portletResource = ParamUtil.getString(request, "portletResource");
if (Validator.isNotNull(portletResource)) {
preferences = PortletPreferencesFactoryUtil.getPortletSetup(request, portletResource);
}
String flickrFeed = preferences.getValue("flickrFeed", StringPool.BLANK);
String numberFeed = preferences.getValue("numberFeed", StringPool.BLANK);
if(flickrFeed.equals(null)|| flickrFeed == "" ){ flickrFeed = "64933450@N05"; }
if(numberFeed.equals(null)|| numberFeed == "" ){ numberFeed = "3"; }
%>
<div class="seperator"></div>
<input id="flickrSearch" value="<%= flickrFeed %>" type="hidden">
<input id="flickrFeedList" value="<%= numberFeed %>" type="hidden">
<div class="sidebar_widget">
<h3 class="widget_head"><img alt="img" title="Photos from Flickr" src="<%=ctxPath%>/images/flickr_icon.png">Photos from Flickr</h3>
<div class="widget_content">
<ul id="flickrId">
</ul>
</div>
<div class="widget_footer">
<a href="http://www.flickr.com/photos/<%=flickrFeed %>">More Photos on Flickr</a>
</div>
</div>
view raw flickrview.jsp hosted with ❤ by GitHub


You need to add the FlickrFeedAPI for accessing these feeds.
1. Download latest Jquery min js file
2. Download Flickr feed js file from Jquery Feed Plugin
3. Create a flickr-setup.js file which takes feed count and feed id as input and displays feeds as shown below:
$(document).ready(function(){
$('#flickrId').flickr({
limit: $("#flickrFeedList").val(),
qstrings: {
id: $("#flickrSearch").val() // flickr - ID
},
itemTemplate: '<li>'+'<img alt="img" src="{{image_s}}"><br/><a href="{{link}}"> {{title}} </a><div><small>Uploaded on {{date_uploaded}} <br> </small><br/></div>'+'</li>'
});
});
view raw flickrSetup.js hosted with ❤ by GitHub

For FlickrServices, you can refer : Feeds

Thanks for reading! Happy Learning !

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

Tuesday, 15 July 2014

Display Dockbar based on Roles in Liferay


Below code can be used to check logged in user is Admininstrator then display Dockbar:#if ($permissionChecker.isOmniadmin())#dockbar()#end

Below code snippet is used to show/hide dockbar based on custom Role. If logged in user has custom Role assigned, then dockbar shall be visible to him. It shall be hidden for rest of users.

#if ( $is_signed_in )        #set ($roleService = $serviceLocator.findService("com.liferay.portal.service.RoleService"))    #set ($listOfUserRoles = $roleService.getUserRoles( $user_id ))    #foreach( $userRole in $listOfUserRoles)       #if ($userRole.getName() == "Custom-Role")          #dockbar()       #end    #end#end