Thursday, December 26, 2013

Whats new in liferay 6.2 API - Part 1

In this post we will cover the changes that comes along with Liferay Portal 6.2 in liferay-portlet.xml DTD file.


<ddm-display>
The ddm-display value must be a class that implements com.liferay.portlet.dynamicdatamapping.util.DDMDisplay and is called when displaying the portlet.
<requires-namespaced-parameters>
Set the requires-namespaced-parameters value to true if the portlet will only process namespaced parameters. The default value is true.
<staged-model-data-handler-class>
The staged-model-data-handler-class value must be a class that implements com.liferay.portal.kernel.lar.StagedModelDatahandler and is called to handle export and import logic for a staged model entity.
<template-handler>
The template-handler value must be a class that implements com.liferay.portal.kernel.template.TemplateHandler and is called when displaying the portlet.
<trash-handler>
The trash-handler value must be a class that implements com.liferay.portal.kernel.trash.TrashHandler and is called to manage trash entries.
<user-notification-definitions>
The user-notification-definitions points to the XML file that defines the user notifications for this portlet. This file is read by the class loader.
<user-notification-handler-class>
The user-notification-handler-class value must be a class that implements com.liferay.portal.kernel.notifications.UserNotificationHandler is called to interpret requests into friendly messages that are easily understandable by a human being.

Friday, November 29, 2013

Kaleo Workflow Configuration for Custom Portlet in Liferay 6.1

1. Make sure you have deployed kaleo workflow war in your liferay portal.

2. Create the service.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_1_0.dtd">
<service-builder package-path="com.sample.harish">
<author>harish.kumar</author>
<namespace>harish</namespace>
<entity name="Feedback" uuid="true" local-service="true" remote-service="false">
<column name="feedbackId" type="long" primary="true" />
<column name="feedbackDate" type="Date" />
<column name="feedbackText" type="String" />
<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
<column name="companyId" type="long" />
<column name="groupId" type="long" />
<column name="userId" type="long" />
<order>
<order-column name="feedbackId" order-by="asc" />
<order-column name="feedbackDate" order-by="desc" />
</order>
<finder name="GroupId" return-type="Collection">
<finder-column name="groupId" />
</finder>
<finder name="CompanyId" return-type="Collection">
<finder-column name="companyId" />
</finder>
<finder name="feedbackText" return-type="Collection">
<finder-column name="feedbackText" />
</finder>
<finder name="G_S" return-type="Collection">
<finder-column name="groupId" />
<finder-column name="status" />
</finder>
<reference package-path="com.liferay.portal" entity="User" />
<reference package-path="com.liferay.portlet.asset" entity="AssetEntry" />
<reference package-path="com.liferay.portlet.ratings" entity="RatingsStats" />
</entity>
</service-builder>
view raw service.xml hosted with ❤ by GitHub

3. Build the service

4. Edit the FeedbackLocalServiceImpl class and add the following methods:


public Feedback addFeedback(Feedback newFeedback, long userId,
ServiceContext serviceContext) throws SystemException,
PortalException {
Feedback feedback = feedbackPersistence.create(counterLocalService
.increment(Feedback.class.getName()));
feedback.setCompanyId(newFeedback.getCompanyId());
feedback.setGroupId(newFeedback.getGroupId());
feedback.setUserId(serviceContext.getUserId());
feedback.setFeedbackDate(newFeedback.getFeedbackDate());
feedback.setFeedbackText(newFeedback.getFeedbackText());
feedback.setStatus(WorkflowConstants.STATUS_DRAFT);
feedbackPersistence.update(feedback, false);
assetEntryLocalService.updateEntry(userId, feedback.getGroupId(),
Feedback.class.getName(), feedback.getFeedbackId(),
serviceContext.getAssetCategoryIds(),
serviceContext.getAssetTagNames());
WorkflowHandlerRegistryUtil.startWorkflowInstance(
feedback.getCompanyId(), feedback.getGroupId(), userId,
Feedback.class.getName(), feedback.getPrimaryKey(), feedback,
serviceContext);
return feedback;
}
public void deleteFeedbacks(Feedback feedback) throws SystemException,
PortalException {
assetEntryLocalService.deleteEntry(Feedback.class.getName(),
feedback.getFeedbackId());
feedbackPersistence.remove(feedback);
}
public Feedback updateStatus(long userId, long resourcePrimKey, int status,
ServiceContext serviceContext) throws PortalException,
SystemException {
User user = userLocalService.getUser(userId);
Feedback feedback = getFeedback(resourcePrimKey);
feedback.setStatus(status);
feedback.setStatusByUserId(userId);
feedback.setStatusByUserName(user.getFullName());
feedback.setStatusDate(serviceContext.getModifiedDate());
feedbackPersistence.update(feedback, false);
if (status == WorkflowConstants.STATUS_APPROVED) {
assetEntryLocalService.updateVisible(Feedback.class.getName(),
resourcePrimKey, true);
} else {
assetEntryLocalService.updateVisible(Feedback.class.getName(),
resourcePrimKey, false);
}
return feedback;
}

5. Make the following entries in liferay-portlet.xml file


<asset-renderer-factory>com.sample.harish.portlet.asset.FeedbackAssetRendererFactory</asset-renderer-factory>
<workflow-handler>com.sample.harish.portlet.workflow.FeedbackWorkflowHandler</workflow-handler>

6. create the FeedbackAssetRendererFactory class


public class FeedbackAssetRendererFactory extends BaseAssetRendererFactory {
@Override
public AssetRenderer getAssetRenderer(long classPK, int type)
throws PortalException, SystemException {
Feedback feedback = FeedbackLocalServiceUtil.getFeedback(classPK);
return new FeedbackAssetRenderer(feedback);
}
@Override
public String getClassName() {
return Feedback.class.getName();
}
@Override
public String getType() {
return "article";
}
}

7. create the FeedbackAssetRenderer class-


public class FeedbackAssetRenderer extends BaseAssetRenderer{
private Feedback _feedback;
public FeedbackAssetRenderer(Feedback feedback) {
_feedback = feedback;
}
public long getClassPK() {
return _feedback.getFeedbackId();
}
public long getGroupId() {
return _feedback.getGroupId();
}
public String getSummary(Locale arg0) {
return _feedback.getFeedbackText();
}
public String getTitle(Locale arg0) {
return "Feedback Contest Entry";
}
public long getUserId() {
return _feedback.getUserId();
}
public String getUuid() {
return _feedback.getUuid();
}
public String render(RenderRequest request, RenderResponse response, String template)
throws Exception
{
if (template.equals(TEMPLATE_FULL_CONTENT)) {
return "/html/feedback.jsp";
}
else
{
return null;
}
}
@Override
public String getUserName() {
// TODO Auto-generated method stub
return null;
}
}

8. create the /html/feedback.jsp file.


9. create the FeedbackWorkflowHandler class -


public class FeedbackWorkflowHandler extends BaseWorkflowHandler{
public String getClassName() {
return CLASS_NAME;
}
public String getType(Locale locale) {
return LanguageUtil.get(locale, "model.resource." + CLASS_NAME);
}
public Object updateStatus(int status,
Map<String, Serializable> workflowContext) throws PortalException,
SystemException {
long userId = GetterUtil.getLong(workflowContext.get(WorkflowConstants.CONTEXT_USER_ID));
long resourcePrimKey = GetterUtil.getLong(workflowContext.get(WorkflowConstants.CONTEXT_ENTRY_CLASS_PK));
ServiceContext serviceContext = (ServiceContext) workflowContext.get("serviceContext");
return FeedbackLocalServiceUtil.updateStatus(userId, resourcePrimKey,status, serviceContext);
}
public static final String CLASS_NAME = Feedback.class.getName();
}

10. We are done with all the changes now, to see our portlet in action go to control panel → Workflow Configuration and set the workflow for your custom portlet.

Tuesday, November 19, 2013

Hiding SessionErrors Default Error Message

Whenever we make use of SessionErrors to display error message in Liferay, below default error message is also displayed by Liferay.



To get rid of this default message use the below code snippet -

PortletConfig portletConfig = (PortletConfig)renderRequest.getAttribute(JavaConstants.JAVAX_PORTLET_CONFIG);
LiferayPortletConfig liferayPortletConfig = (LiferayPortletConfig) portletConfig;
SessionMessages.add(renderRequest, liferayPortletConfig.getPortletId() + SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE);
NOTE: This will work for specific portlet only.

Monday, November 18, 2013

Adding Success Message in Liferay Custom Portlet Configuration Page

To add success message and page refresh in configuration page, just add the following snippet in your ConfigurationImpl class's processAction method ..


LiferayPortletConfig liferayPortletConfig = (LiferayPortletConfig) portletConfig;
String portletResource = ParamUtil.getString(actionRequest, "portletResource");
SessionMessages.add(actionRequest, liferayPortletConfig.getPortletId() + SessionMessages.KEY_SUFFIX_REFRESH_PORTLET, portletResource);
SessionMessages.add(actionRequest, liferayPortletConfig.getPortletId() + SessionMessages.KEY_SUFFIX_UPDATED_CONFIGURATION);

Configure Solr With Liferay 6

Configuring solr on standalone tomcat-

1. download solr and unzip to any directory say d:
2. set environment variable SOLR_HOME as D:\apache-solr-1.4.1\example\solr
3. Copy D:\apache-solr-1.4.1\dist\apache-solr-1.4.1.war and paste it in \Tomcat 6.0\webapps folder. make sure rename the war file to solr.war.
4. start the tomcat to unzip the war.
5. stop tomcat
6. edit the file \Tomcat 6.0\webapps\solr\WEB-INF\web.xml. Uncomment the following entry and provide path of your SOLR_HOME

<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>D:\apache-solr-1.4.1\example\solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
view raw solr-web-xml hosted with ❤ by GitHub
7. Start tomcat and browse http://localhost:8080/solr/admin to verify your solr installation.

Configuring Solr plugin in Liferay-

1. download the required solr-web.war compatible with your liferay version
2. put this war in LIFERAY_HOME\deploy folder
3. After deployment shut down the Liferay server as well as solr instance.
4. Edit the file D:\liferay-portal-6.1.20-ee-ga2\tomcat-7.0.27\webapps\solr-web\WEB-INF\classes\META-INF\solr-spring.xml

<bean id="com.liferay.portal.search.solr.server.BasicAuthSolrServer" class="com.liferay.portal.search.solr.server.BasicAuthSolrServer">
<constructor-arg type="java.lang.String" value="http://localhost:8090/solr" />
</bean>
view raw solr-spring-xml hosted with ❤ by GitHub
provide your solr instance settings as above.
5. Copy D:\liferay-portal-6.1.20-ee-ga2\tomcat-7.0.27\webapps\solr-web\WEB-INF\conf\schema.xml file and paste it into D:\apache-solr-1.4.1\example\solr\conf folder.

Now start your tomcat and then Liferay server.

Friday, September 13, 2013

Liferay UI Tag liferay-ui:input-move-boxes

Following is the sample code to use liferay-ui:input-move-boxes tag-

1. JSP Code:

<form name=”fm” method=”post” action=”<<actionUrl>>”>
<liferay-ui:input-move-boxes
rightList="<%=rightFields %>"
rightTitle="Right Fields"
rightBoxName="rightFieldsList"
leftList="<%=leftFields%>"
leftTitle="Left Fields"
leftBoxName="leftFieldsList"
leftReorder="true" />
</liferay-ui:panel>
<br />
<liferay-aui:input name="hiddenLeftFields" type="hidden" />
<liferay-aui:input name="hiddenRightFields" type="hidden" />
<input type="button" value="Submit" onclick="<portlet:namespace />submitForm();">
</form>
<liferay-aui:script>
Liferay.provide(
window,
'<portlet:namespace />submitForm',
function() {
document.fm.<portlet:namespace />hiddenLeftFields.value = Liferay.Util.listSelect(document.fm.<portlet:namespace />leftFieldsList);
document.fm.<portlet:namespace />hiddenRightFields.value = Liferay.Util.listSelect(document.fm.<portlet:namespace />rightFieldsList);
document.fm.submit();
}, ['liferay-util-list-fields']
);
</liferay-aui:script>
2. Java Code:
String hiddenLeftFields = ParamUtil.getString(actionRequest, "hiddenLeftFields");
String hiddenRightFields = ParamUtil.getString(actionRequest, "hiddenRightFields");
view raw java-code hosted with ❤ by GitHub

Monday, September 9, 2013

jQuery Autocomplete in Liferay Custom Portlet

In the following post we are going to implement jQuery Autocomplete in our custom portlet.

1. create the service.xml file-

<service-builder package-path="com.sample.harish">
<author>harish.kumar</author>
<namespace>harish</namespace>
<entity name="Student" local-service="true" remote-service="true">
<column name="studentId" type="long" primary="true" />
<column name="studentName" type="String" />
<column name="course" type="String" />
<finder return-type="Collection" name="CourseLike">
<finder-column name="course" comparator="LIKE" />
</finder>
</entity>
</service-builder>
2. Add the finder method in StudentLocalServiceImpl class-

public java.util.List<Student> findByCourseLike(
java.lang.String course)
throws com.liferay.portal.kernel.exception.SystemException {
return StudentUtil.findByCourseLike(course);
}
3. Put the jquery js files in docroot/js folder and add the following entries in liferay-portlet.xml file -

<header-portlet-javascript>/js/jquery.min.js</header-portlet-javascript>
<footer-portlet-javascript>/js/jquery-ui.min.js</footer-portlet-javascript>
4. view.jsp file-

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css" />
<portlet:defineObjects />
This is the <b>JqueryAutocomplete</b> portlet.
<portlet:resourceURL var="getAutoCompleteData" id="getAutoCompleteData" >
<portlet:param name="action" value="autocompleteCall"/>
</portlet:resourceURL>
<portlet:actionURL name="submitCourse" var="courseUrl" />
<STYLE TYPE="text/css" media="all">
.ui-autocomplete {
position: absolute;
cursor: default;
height: 100px;
overflow-y: scroll;
overflow-x: hidden;
text-align:left;
}
</STYLE>
<script type="text/javascript">
function createAutoComplete(fieldName) {
$('#' + fieldName).autocomplete({
width: 300,
max: 10,
delay: 100,
minLength: 1,
minChars:2,
autoFocus: true,
cacheLength: 1,
scroll: true,
highlight: false,
source: function(request, response) {
$.ajax({
url: "<%= getAutoCompleteData %>" + "&fieldName=" + fieldName,
dataType: "json",
data: request,
success: function(data, textStatus, jqXHR) {
var items = data;
response(items);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log( textStatus);
}
});
}
});
}
$(document).ready(function() {
createAutoComplete("course");
});
</script>
<br/>
<form name="fm" method="post" action="<%=courseUrl%>">
<input type="text" name="course" id="course" value=""/> <br/><br/>
<input type="submit" />
</form>
5. Add the following methods in portlet class-
@Override
public void serveResource(ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws IOException,
PortletException {
String action = ParamUtil.getString(resourceRequest, "action");
if(action.equals("autocompleteCall"))
{
String fieldName = ParamUtil.getString(resourceRequest, "fieldName");
String term = ParamUtil.getString(resourceRequest, "term");
String res = getAutocompleteListData(fieldName,term);
resourceResponse.getWriter().write(res);
}
}
private String getAutocompleteListData(String fieldName, String term) {
List<String> courseList = new ArrayList<String>();
Gson gson = new Gson();
List<Student> students = null;
try {
students = StudentLocalServiceUtil.findByCourseLike(term + "%");
} catch (SystemException e) {
e.printStackTrace();
}
if (Validator.isNotNull(students)) {
for (Student stud : students) {
courseList.add(stud.getCourse());
}
}
return gson.toJson(courseList);
}
public void submitCourse(ActionRequest request, ActionResponse response)
{
String course = ParamUtil.getString(request, "course");
System.out.println("Process Course: " + course);
}

Sunday, September 1, 2013

Connecting Liferay with Another Database

In the following post we will connect liferay with some third party database (legacy database):

Method 1:

1. Create Service.xml

<entity name="Teacher" local-service="true" remote-service="true" data-source="myDatasource">
<!-- PK fields -->
<column name="teacherId" type="long" primary="true" />
<!-- Other fields -->
<column name="teacherName" type="String" />
</entity>
2. Create ext-spring.xml file as /WEB-INF/src/META-INF/ext-spring.xml

<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="myDatasource" lazy-init="true" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/harish?useUnicode=true"/>
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="liferayHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
<property name="dataSource" ref="myDatasource" />
</bean>
</beans>
view raw ext-spring-1 hosted with ❤ by GitHub
You wont believe but yes we are done!!


Method 2:

1. Make an entry in portal-ext.properties file for another database:

jdbc.default.url=jdbc:mysql://localhost/lportal?useUnicode=true&characterEncoding=UTF-&useFastDateParsing=false
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.username=
jdbc.default.password=
jdbc.test.driverClassName=com.mysql.jdbc.Driver
jdbc.test.url=jdbc:mysql://localhost/harish?useUnicode=true&characterEncoding=UTF-&useFastDateParsing=false
jdbc.test.username=
jdbc.test.password=
view raw portal-ext-db hosted with ❤ by GitHub
2. create service.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.1.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_1_0.dtd">
<service-builder package-path="com.harish">
<author>harish.kumar</author>
<namespace>sample</namespace>
<entity name="Employee" local-service="true" remote-service="true" data-source="testDataSource" session-factory="testSessionFactory" tx-manager="testTransactionManager">
<!-- PK fields -->
<column name="empId" type="long" primary="true" />
<!-- other fields -->
<column name="name" type="String" />
</entity>
</service-builder>
3. create ext-spring.xml file:

<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<aop:config>
<aop:pointcut id="transactionOperation" expression="bean(*Service.impl)" />
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionOperation" />
</aop:config>
<bean id="basePersistence" abstract="true">
<property name="dataSource" ref="testDataSource" />
<property name="sessionFactory" ref="testSessionFactory" />
</bean>
<bean id="transactionAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="testTransactionManager" />
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
<constructor-arg>
<bean class="com.liferay.portal.spring.annotation.PortalTransactionAnnotationParser" />
</constructor-arg>
</bean>
</property>
</bean>
<bean id="testHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration" lazy-init="true">
<property name="dataSource" ref="testDataSource" />
</bean>
<bean id="testSessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl" lazy-init="true">
<property name="sessionFactoryImplementor" ref="testHibernateSessionFactory" />
</bean>
<bean id="testTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
<property name="dataSource" ref="testDataSource" />
<property name="globalRollbackOnParticipationFailure" value="false" />
<property name="sessionFactory" ref="testHibernateSessionFactory" />
</bean>
<bean id="testDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<bean class="com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean">
<property name="propertyPrefix" value="jdbc.test." />
</bean>
</property>
</bean>
</beans>
view raw ext-spring-db-2 hosted with ❤ by GitHub

done!


NOTE: In both the above methods, we have to create the table manually in the database.

Liferay Permission on Custom Portlet

As mentioned on Liferay Dcoumentation we can add permissions to your custom portlets using four easy steps (also known as DRAC):

1. Define all resources and their permissions.
2. Register all defined resources in the permissions system. This is also known as adding resources.
3. Associate the necessary permissions with resources.
4. Check permission before returning resources.

Here we are implementing Liferay Permission for custom portlet named StudentMaster.

1. The first step is to define your resources and the actions that can be defined on them. Create a file named default.xml in /src/resource-actions folder -

<?xml version="1.0"?>
<!DOCTYPE resource-action-mapping PUBLIC "-//Liferay//DTD Resource Action Mapping 6.1.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_6_1_0.dtd">
<resource-action-mapping>
<portlet-resource>
<portlet-name>StudentMaster</portlet-name>
<permissions>
<supports>
<action-key>ADD_STUDENT</action-key>
<action-key>CONFIGURATION</action-key>
<action-key>VIEW</action-key>
</supports>
<site-member-defaults>
<action-key>VIEW</action-key>
</site-member-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>CONFIGURATION</action-key>
</guest-unsupported>
</permissions>
</portlet-resource>
<model-resource>
<model-name>com.harish.model.Student</model-name>
<portlet-ref>
<portlet-name>StudentMaster</portlet-name>
</portlet-ref>
<permissions>
<supports>
<action-key>EDIT_STUDENT</action-key>
</supports>
<site-member-defaults />
<guest-defaults />
<guest-unsupported>
<action-key>EDIT_STUDENT</action-key>
</guest-unsupported>
</permissions>
</model-resource>
</resource-action-mapping>

2. After defining resource permissions for our custom portlet, we need to refer Liferay to the resource-actions XML file that contains definitions. Create a properties file named portlet.properties that references the the file default.xml. In this portlet properties file, create a property named resource.actions.configs with the relative path to portlet’s resource-action mapping file (e.g.default.xml) as its value. Here’s what this property specification might look like:

resource.actions.configs=resource-actions/default.xml

3. Adding a Resource

After defining resources and actions, it’s time to add resources into the permissions system. Resources are added at the same time entities are added to the database. Each Entity that requires access permission must be added as a resource every time it is stored.

public Student addNewStudent(String studentName, String course, long companyId, long groupId, long userId) throws SystemException
{
long studentId = counterLocalService.increment(Student.class.getName());
Student student = studentPersistence.create(studentId);
student.setStudentName(studentName);
student.setCourse(course);
studentPersistence.update(student, false);
try {
resourceLocalService.addResources(companyId, groupId, userId, Student.class.getName(), studentId, false, true, true);
} catch (PortalException e) {
e.printStackTrace();
}
return student;
}
4. Adding Permission:

On the portlet level, no code needs to be written in order to have the permission system work for custom portlet. If we have defined any custom permissions (supported actions) in configuration file’s portlet-resource tag, they’re automatically added to a list of permissions in Liferay’s permissions UI. What good, however, are permissions that are available but can’t be set by users?
To let a user set permissions on model resources, we must expose the permission interface to the user. Just add these two Liferay UI tags to JSP:
1. : Returns a URL to the permission settings configuration page.
2. : Shows an icon to the user. These are defined in the theme, and one of them (see below) is used for permissions.

<liferay-security:permissionsURL
modelResource="<%= Student.class.getName() %>"
modelResourceDescription="<%= \"Student\" %>"
resourcePrimKey="1"
var="entryURL"
/>
<liferay-ui:icon image="permissions" url="<%= entryURL %>" />
view raw permission-icon hosted with ❤ by GitHub
5. Checking Permission:

<portlet:defineObjects />
<liferay-theme:defineObjects />
<%
long groupId = scopeGroupId;
String name = portletDisplay.getRootPortletId();
String primKey = portletDisplay.getResourcePK();
String actionId = "ADD_STUDENT";
%>
This is the <b>Student Master</b> portlet.
<portlet:actionURL var="addStudentUrl" name="addStudent" />
<br/><br/>
<strong>
<%-- portlet level permission check --%
<c:if test="<%= permissionChecker.hasPermission(groupId, name, primKey, actionId) %>">
<a href="<%=addStudentUrl.toString()%>">Add New Student</a>
</c:if>
</strong>
<br/><br/>
<liferay-ui:search-container delta="5" emptyResultsMessage="No Students were found!!">
<liferay-ui:search-container-results results="<%=ListUtil.subList((List<Student>)request.getAttribute(\"students\"), searchContainer.getStart(), searchContainer.getEnd())%>" total="${students.size()}" />
<liferay-ui:search-container-row className="com.harish.model.Student" keyProperty="studentId" modelVar="student">
<liferay-ui:search-container-column-text name="name" value="${student.studentName}" />
<liferay-ui:search-container-column-text name="subject" value="${student.course}" />
<%-- model level permission check --%
<c:if test="<%= permissionChecker.hasPermission(groupId, Student.class.getName(), student.getStudentId(), \"EDIT_STUDENT\") %>">
<liferay-ui:search-container-column-jsp path="/studentActions.jsp" align="right" />
</c:if>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator />
</liferay-ui:search-container>
view raw permission-jsp hosted with ❤ by GitHub

Thursday, May 23, 2013

Spring MVC Portlet Validations

In the previous post we have implemented spring mvc portlet using Liferay Portal. In the following post we are going to implement input validation for adding new student form. We will use Spring’s Validator framework for validating data entered during adding new student.

1. First of all we will create StudentValidator class which implements Spring’s Validator interface.


[code language="java"]
@Component("studentValidator")
public class StudentValidator implements Validator{

@Override
public boolean supports(Class clazz) {
return Student.class.isAssignableFrom(clazz);
}

@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "required.name", "Field name is required.");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "subject", "required.subject", "Field subject is required.");
}
}
[/code]

2. Now we will make changes in StudentController class

a. The @Autowired annotation is used to instruct the Spring container to inject the dependency. We will use this to inject StudentValidator in our StudentController class:

[code language="java"]
@Autowired
StudentValidator studentValidator;
[/code]

b. Modify the addStudent method to insert validation code -

[code language="java"]
@ActionMapping(params = "myaction=addStudent")
public void addStudent(@ModelAttribute("student") StudentImpl student, BindingResult result, ActionResponse actionResponse)
{
studentValidator.validate(student, result);
if(result.hasErrors())
{
actionResponse.setRenderParameter("myaction", "addStudentForm");
}
else
{
try {
long studentId = CounterLocalServiceUtil.increment(Student.class.getName());
student.setPrimaryKey(studentId);
StudentLocalServiceUtil.addStudent(student);
} catch (SystemException e) {
e.printStackTrace();
}
}
}
[/code]

c. modify the showAddStudentForm method -

[code language="java"]
@RenderMapping(params = "myaction=addStudentForm")
public String showAddStudentForm(Model model) throws SystemException
{
System.out.println("showAddStudentForm Called !!!!!!!!!!!");
return "addStudent";
}
[/code]

d. Add the following new method -

[code language="java"]
@ModelAttribute("student")
public Student getCommandObject() {
return new StudentImpl();
}
[/code]

3. make changes in addStudent.jsp file to display error messages-

[code language="html"]
<form:form action="<%=AddStudentURL.toString()%>" method="post" commandName="student">
<table>
<form:errors path="*" />
<tr><td>Name :</td> <td><form:input path="name" /></td></tr>
<tr><td colspan="2"><form:errors path="name"></form:errors></td></tr>
<tr><td>Subject:</td> <td><form:input path="subject" /></td></tr>
<tr><td colspan="2"><form:errors path="subject"></form:errors></td></tr>
<tr><td colspan="2"><input type="submit" value="Save" /></td></tr>
</table>
</form:form>
[/code]

4. Add the following snippet to myContext.xml file

[code language="xml"]
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>content.Language_en</value>
</list>
</property>
</bean>
[/code]

5. Add an entry to portlet.xml file -

[code language="xml"]
<resource-bundle>content.Language_en</resource-bundle>
[/code]

6. create new file named Language_en.properties with following content in src/content folder -

[code language="java"]
required.name = name is required!
required.subject = subject is required!
[/code]

We are done with all the changes required!