Saturday, August 25, 2012

Thursday, August 23, 2012

Liferay Custom JSON Web Service Development



Following is the step by step description of generating a custom liferay plugin service and exposing it as JSON Web Service.



STEP:1 Create a liferay plugin project and create new service


Here is the sample service.xml



Make sure remote-service=”true” in entity tag declaration.



STEP:2  Build the service.



STEP:3  Add your custom method in SampleLocalServiceImpl class



STEP:4  Build the service.



STEP:5  Add the method definition to SampleServiceImpl class



STEP:6  build the service.



STEP:7  Add the following <servlet> and <servlet-mapping> Entries to portlet's web.xml file -



STEP:8  deploy the portlet.


STEP:9  To access your json web services enter the following url -

http://localhost:8080/<<portlet-context>>/api/jsonws





and Its Done!!!





Friday, July 27, 2012

Spring MVC Portlet - Liferay

In this post we are going are develop a multi page portlet using Spring 3.0 Portlet MVC using annotations.

Following are screen shots of various pages -

  1. Home Page: Displays a lists of student with action button to perform edit and delete action on particular student. Add New Student link n the top opens up a new form where we can provide the details for new student and save.

    Home Page



  2. Add New Student: On clicking Add New Student following page will open.


add new student

3. Edit Student Form: Clicking edit from the action menu will display the edit student form.

edit form

  1. Delete Student: Clicking delete from the action menu will display a confirmation alert box and based on your choice will perform.delete studentFollowing are the code listings:


- StudentController.java

[sourcecode language="java"]

@Controller(value="studentController")
@RequestMapping(value = "VIEW")
public class StudentController {

@RenderMapping
public String showStudents(RenderResponse response,Model model) {
System.out.println("Render Called");
List students = null;
try {
students = StudentLocalServiceUtil.getStudents(-1, -1);
} catch (SystemException e) {
System.out.println("Error in getting student list");
e.printStackTrace();
}
model.addAttribute("students", students) ;
return "myView";
}

@RenderMapping(params = "myaction=addStudentForm")
public String showAddStudentForm(Model model) throws SystemException
{
System.out.println("showAddStudentForm Called !!!!!!!!!!!");
Student student = new StudentImpl();
model.addAttribute("student", student);
return "addStudent";
}

@ActionMapping(params = "myaction=addStudent")
public void addStudent(@ModelAttribute("student") StudentImpl student,BindingResult bindingResult, ActionRequest actionRequest, ActionResponse actionResponse)
throws Exception {

student.setPrimaryKey(CounterLocalServiceUtil.increment(Student.class.getName()));
Student newStudent = StudentLocalServiceUtil.addStudent(student);
System.out.println("Student added : " + newStudent.getName());
}

@RenderMapping(params = "myaction=editStudentForm")
public String editStudentForm(@RequestParam Long resourcePrimKey,Model model) throws PortalException, SystemException
{
System.out.println("Edit Student Form Called !!" + resourcePrimKey);
Student student = StudentLocalServiceUtil.getStudent(resourcePrimKey);
model.addAttribute("student", student);
return "editStudent";
}

@ActionMapping(params = "myaction=editStudent")
public void editStudent(@ModelAttribute StudentImpl student,@RequestParam Long resourcePrimKey,ActionResponse response) throws IOException
{
student.setId(resourcePrimKey);
System.out.println("Edit Student Called!!" + student.getId());
try {
StudentLocalServiceUtil.updateStudent(student);
} catch (SystemException e) {
System.out.println("Error Occured while updating!! ");
e.printStackTrace();
}
}

@ActionMapping(params = "myaction=deleteStudent")
public void deleteStudent(ActionRequest request,ActionResponse response){
long primKey = ParamUtil.getLong(request, "resourcePrimKey");
System.out.println("Delete Called for : " + primKey);
try {
StudentLocalServiceUtil.deleteStudent(primKey);
} catch (PortalException e) {
System.out.println("Error Occured while deleting");
e.printStackTrace();
} catch (SystemException e) {
System.out.println("Error Occured whlile deleting");
e.printStackTrace();
}
}
}

[/sourcecode]

- myView.jsp

[sourcecode language="java"]

<portlet:renderURL var="addStudentJSP">
<portlet:param name="myaction" value="addStudentForm"></portlet:param>
</portlet:renderURL>
<% PortletURL iteratorURL = renderResponse.createRenderURL(); %>

<a href="<%=addStudentJSP%>">Add New Student</a>

<br/><br/>

<liferay-ui:search-container delta="5" emptyResultsMessage="No Students were found!!" iteratorURL="<%=iteratorURL%>">
<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.test.model.Student" keyProperty="id" modelVar="student">
<liferay-ui:search-container-column-text name="name" value="${student.name}" />
<liferay-ui:search-container-column-text name="subject" value="${student.subject}" />
<liferay-ui:search-container-column-jsp path="/WEB-INF/jsp/studentActions.jsp" align="right" />
</liferay-ui:search-container-row>
<liferay-ui:search-iterator />
</liferay-ui:search-container>

[/sourcecode]

- addStudent.jsp

[sourcecode language="java"]

<portlet:actionURL var="AddStudentURL">
<portlet:param name="myaction" value="addStudent"></portlet:param>
</portlet:actionURL>

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

[/sourcecode]


- editStudent.jsp
[sourcecode language="java"]

<h2>Edit Student</h2>

<portlet:actionURL var="EditStudentURL">
<portlet:param name="myaction" value="editStudent" />
<portlet:param name="resourcePrimKey" value="${student.primaryKey}" />
</portlet:actionURL>

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

- studentActions.jsp

[sourcecode language="java"]

<%
ResultRow row = (ResultRow) request.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);
Student myStudent = (Student) row.getObject();
String primKey = String.valueOf(myStudent.getPrimaryKey());
%>

<liferay-ui:icon-menu>
<liferay-portlet:renderURL var="editURL">
<portlet:param name="myaction" value="editStudentForm" />
<portlet:param name="resourcePrimKey" value="<%= primKey %>" />
</liferay-portlet:renderURL>
<liferay-ui:icon image="edit" message="Edit" url="<%= editURL.toString() %>" />

<portlet:actionURL var="deleteURL">
<portlet:param name="myaction" value="deleteStudent" />
<portlet:param name="resourcePrimKey" value="<%= primKey %>" />
</portlet:actionURL>
<liferay-ui:icon-delete url="<%= deleteURL.toString() %>" />
</liferay-ui:icon-menu>
[/sourcecode]

- Portlet Deployment Descriptor (portlet.xml)

[sourcecode language="java"]

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0">

<portlet>
<portlet-name>springdemo</portlet-name>
<display-name>SpringDemo</display-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/context/portlet/myContext.xml</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Spring Demo</title>
<short-title>Spring Demo</short-title>
<keywords></keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
</portlet-app>
[/sourcecode]

- Portlet Web Application Context (myContext.xml)

[sourcecode language="java"]

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
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-3.0.xsd">

<context:component-scan base-package="com.test" />

<!-- <bean id="studentController"
class="com.test.controller.StudentController"/>

<bean id="portletModeHandlerMapping"
class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="portletModeMap">
<map>
<entry key="view">
<ref bean="studentController" />
</entry>
</map>
</property>
</bean>
-->

</beans>

[/sourcecode]

- Root Web Application Context (applicationContext.xml)

[sourcecode language="java"]

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
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-3.0.xsd">

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>

</beans>

[/sourcecode]

- Project Structure

project-structure

 

Build and Deploy it like any other liferay portlet.

Please comment if you have any questions or suggestions !!!

 

 

Tuesday, July 24, 2012

Liferay Custom Portlet Mode

 

The PortletMode class defines three constants—VIEW, EDIT, and HELP—corresponding
to the VIEW, EDIT, and HELP portlet modes. A portal may define support for additional portlet modes supported by the portal server or by the portlet.

 

Portal Managed Mode - If the portal server is responsible for managing the portlet mode, the portlet mode is referred to as portal-managed. Liferay provides config, about, print, preview and edit_defaults custom portlet modes.

Portlet Managed Mode - If the portlet is responsible for managing the portlet mode, it’s referred to as portlet-managed..

 

Implementing the Portal-managed Custom Portlet mode:

 

Here are the steps to implement print custom portlet mode provided by liferay

 

1. Define support in the portlet.xml -

We must specify the custom portlet mode in the portlet deployment descriptor using the <portlet-mode> subelement of the <supports> element

<portlet-mode>print</portlet-mode>

 

2. A custom portlet mode must also be defined at the portlet application level. The <custom-portlet-mode> subelement of <portlet-app> specifies the custom portlet modes that are available to portlets in the portlet application

<custom-portlet-mode>

<portlet-mode>print</portlet-mode>


</custom-portlet-mode>

 

3. Setting portlet mode in the URL

PortletURL printModeUrl = renderResponse.createRenderURL();
if(renderRequest.isPortletModeAllowed(new PortletMode("print"))) {
printModeUrl.setPortletMode(new PortletMode("print"));
}
request.setAttribute("printModeUrl", printModeUrl);

 

NOTE: if(renderRequest.isPortletModeAllowed(new PortletMode("print")))

above condition checks whether liferay provides support for print custom portlet mode. The PortalContext’s getSupportedPortletModes() method returns the list of portal-managed portlet modes.

 

4. Add link to switch to print mode

<href="<%=printModeUrl.toString() %>">Print Mode</a>


 

5. Implementing the custom portlet mode behavior -

In the portlet class override the doPrint method:

@Override
public void doPrint(RenderRequest renderRequest,
RenderResponse renderResponse) throws IOException, PortletException {
System.out.println("Print Mode Called");
super.doPrint(renderRequest, renderResponse);
}

 

**Liferay doesnt provide support for portlet-managed custom portlet modes.

 

 

Friday, June 15, 2012

Liferay Ehcache Configuration : Distributed Caching in Liferay

Liferay Portal uses Ehcache to support distributed caching.


1. Enable distributed caching

To enable the distributed caching in liferay portal just set the following property in the portal-ext.properties file.

cluster.link.enabled=true

2. Default Hibernate cache settings

In Liferay Portal, hibernate is configured to use the Ehcache and default caching configurations are specified in the hibernate-clustered.xml file.

Following configuration is used by default for all the Liferay entities.



3. Customizing Hibernate Cache Settings

Let say we want to customize the hibernate cache settings for MBMessage Entity. Following are the steps to achieve our goal -

create a new folder say myEhcache in the [Tomcat Home]/webapps/ROOT /WEB-INF/classes/ folder and copy the default hibernate-clustered.xml file in the myEhcache folder.

Edit the hibernate-clustered.xml file and an entry for MBMessage Entity



4. Add an entry to portal-ext.properties file to provide the path of your custom hibernate-clustered.xml file

    net.sf.ehcache.configurationResourceName=/myEhcache/hibernate-clustered.xml

Restart the server.

5. Viewing Cache Configuration in jconsole -

jconsole can be used to view the current cache settings applied. Following is screenshot displaying the cache configuration for MBMessageImpl class:


As we customized the Hibernate cache settings, Cache settings for the clustered environment can also be configured via following files -

1.  liferay-single-vm.xml

2. liferay-multi-vm-clustered.xml


Thursday, June 14, 2012

Liferay Search Container : Orderable Columns

In this post we are going to implement the orderable columns for search container.

Following are the steps -

1. Put the following code in your jsp which is used to render the search container.


This If condition is provided to handle the default case. Here defaultColumn and defaultOrder can be replaced with the desired column and order respectively. Here we are sorting the results on the title column.

2.  Here is the TitleComparator.java code -



3.  add the following code to your controller's render method :



4.  Here is the search container part -




Now Title column in the search container will be rendered as clickable and upon clicking will sort the title column data.