Tuesday, June 3, 2014

Liferay Service Builder Custom Service Methods

Introduction:

Liferay Service Builder is a tool to generate service layer to liferay portlets. It will create all necessary CRUD operation related classes and respective methods.

We will use Util classes’ methods to perform CRUD operations in portlet development.
The following is the tutorial about Service Builder.


Liferay Service Builder have provided some Util classes so that we can use those classes and its methods

The following are the important Service Util classes we will use


XXXLocalServiceUtil
XXXServiceUtil
XXXUtil

XXX is your entity name in service.xml file example say Student is your entity name.

StudentLocalServiceUtil
StudentServiceUtil
StidentUtil


XXXLocalServiceUtil (StudentLocalServiceUtil)

All important CRUD operation related methods will be available. We can use this class anywhere in our code implementation i.e. when we want to interacts with database. The operations are like add, update, delete, and read.

When we call methods from this classes there is no security check applied or there no permission checking applicable.

XXXServiceUtil(StudentServiceUtil)

This class is similar to Local Service Util and available all CRUD operation methods but here it will use some security checks and permission checking are applied when we call the methods. If the user does not have required permissions then it will throw Principle Exception

Scenario:

Use some XXXServiceUtil method in JSP page and access the page as Guest User then you can get Principle Exception

Same page you can access after login as Admin then no exception will be thrown.

Generally this class will use to perform admin related task if we call this method in Guest user mode then it will throw the exception


Principle Exception


XXXUtil (StudenUtil)

This class especially for finder methods and all finder methods will be available.

Generally in liferay we can create finder methods with help of service.xml file

We will use following tag in service.xml file so that respective finder method will be create in XXXUtil class.


<entity name="Student" local-service="true" remote-service="true">
              <!-- PK fields -->
              <column name="studentId" type="long" primary="true" />
              <column name="firstName" type="String" />
              <column name="lastName" type="String" />
              <column name="studentAge" type="int" />
              <column name="studentGender" type="int" />
              <column name="studentAddress" type="String" />
              <!-- Finder methods -->
              <finder name="Gender" return-type="Collection">
                     <finder-column name="studentGender"/>
              </finder>
</entity>


Note:

When we declared Collection return type is a java.uti.List<ObjectType>

Method Syntax in Java Class


public returnType  findByXXX (finderColumns){

}

XXX is the name we specified in finder tag as name attribute.


 Example:


public List findByGender(int stdentGender){

}


When we use finder tag we need to specify the finder columns inside the finder tag.
We need specify the finder method return type i.e. Collection or Object type

If the methods want return more than one value or records then need to specify as Collection
If the method returns only one object or one record then we can specify as Object i.e. respective object we specified as entity.

Example:

By Gender we can get more records or values so its return type should be Collection


<finder name="byGender" return-type="Collection">
<finder-column name="studentGender"/>
</finder>


For above Configuration respective SQL query as follows


Select * from LS_Student Where studentgender=?


For Above Finder Configuration respective Java Method in XXXUtil(StudentUtil) as follows


public class StudentUtil {

public static java.util.List<com.meera.dbservice.model.Student> 
findByGender(
int studentGender)
throws com.liferay.portal.kernel.exception.SystemException {
return getPersistence().findBybyGender(studentGender);
}
}

If the finder returns only one value or single object, Assume by first name we have only one record is expected.


<finder name="fistName" return-type="Student">
<finder-column name="firstName"/>
</finder>


For above Configuration respective SQL query as follows


Select * from LS_Student Where firstName=?


Note:

In the above configuration we can expect only one value that is respective entity model object that is why return type we specified as Object i.e. Student

Finder on Multiple Columns

If we want find the records based on multiple columns


<finder name="Gender_Age" return-type="Collection">
<finder-column name="studentGender"/>
<finder-column name="studentAge"/>
</finder>


For above Configuration respective SQL query as follows


Select * from LS_Student Where studentGender=? AND StudentAge=?


For Above Finder Configuration respective Java Method in XXXUtil(StudentUtil) as follows


public class StudentUtil{

public static java.util.List<com.meera.dbservice.model.Student>
findByGender_Age(int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return getPersistence().findByGender_Age(studentGender,
studentAge);
}
}

Note:

When we use finder on multiple columns it will apply the AND operator in SQL query.

When we call XXXUtil methods in JSP or Portlet action class then we will get Exception

Example:


java.util.List<com.meera.dbservice.model.Student>  studentsList=
StudentUtil. findByGender_Age(1,20)


When we use above code in anywhere then we will get Hibernate Exception


org.hibernate.HibernateException: No Hibernate Session bound to thread


Solution:

We need to use these methods in XXXLocalServiceImpl then we will call these methods using XXXLocalServiceUtil

Note:

We can call any method which is in XXXLocalServiceUtil class in JSP, Portlet Action class or other places.

Custom Method Implementation:

When we thing about above scenarios we are not able to call finder methods and some the methods in XXXServiceUtil methods. This is where we need to implement custom methods.

Steps:
  1. Implement Custom method in XXXLocalServiceImpl class
  2. Run service Builder
  3. Call Implemented method using XXXLocalServiceUtil

Implement Custom method in XXXLocalServiceImpl class

Whenever we get the requirement to write our custom methods then we need to implement in respective entity local service implementation class


XXXLocalServiceImpl

StudentLocalServiceImpl


Assume scenario we are not able to call finder methods form StudentUtil so we will implement custom method in StudentLocalServiceImpl.java


public  java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge(int studentGender, int studentAge)

throws com.liferay.portal.kernel.exception.SystemException {

return StudentUtil.findByGender_Age(studentGender, studentAge);

}


Here we have implemented our custom method in XXXLocalServiceImpl 
(StudentLocalServiceImpl.java) and inside the custom method we have used XXXUtil methods.
Like this we can use XXXServiceUtil and XXXUtil methods in XXXLolcalServiceImpl custom method implementation.

Note:

XXXLocalServiceImpl class available in basepackage.service.impl path

Run service Builder

Once we implement the custom method in XXXServiceImpl then we need to run service builder using ant build-service target from ant view in eclipse.

After run service builder respective method signature will be created in XXXLocalServiceUtil class.

Note:

For every change in XXXLocalServiceImpl class we need to re run the service builder.

Call Implemented method using XXXLocalServiceUtil

Now the method is available in XXXLocalSeriviceUtil class so that we can call method anywhere.

Example:

Method in StudentUtil.java


public class StudentUtil{

public static java.util.List<com.meera.dbservice.model.Student>
 findByGender_Age(
int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return getPersistence().findByGender_Age(studentGender,
 studentAge);
}
}


Note:

We can’t call above method directly

Implement the Custom method in StudentLocalServiceImpl.java


public class StudentLocalServiceImpl extends
StudentLocalServiceBaseImpl {
public  java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge(
int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return StudentUtil.findByGender_Age(studentGender, studentAge);
}
}


Respective method Signature in StudentLocalServieUtil.java


public static java.util.List<com.meera.dbservice.model.Student>
findByGenderAndAge(
int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return getService().findByGenderAndAge(studentGender, studentAge);
}


Note:

Method signature available after run the service builder

Using custom method in JSP page or Portlet Action Class


java.util.List<Student>  studentsList=
StudentLocalServiceUtil. findByGenderAndAge(1,20)



Important Points
  • Whenever we need to implement custom method then we will use XXXLocalServiceimpl class
  • We can’t call XXXUtil and XXXServiceUtil methods directly so we need to use XXXLocalServiceImpl class to implement custom methods.
  • All finder methods will be created in XXXUtil
  • When we call XXXServiceUtil methods as Guest then we will get Principle Exception.
  • When we call XXXUtil methods directly then we will get Hibernate Exception says No Hibernate Session bound to thread
  • For every custom method implementation in XXXLocalServiceImpl then the respective method signature will be created in XXXLocalServiceUtil and this is happened after run the service builder.
  • We always use XXXLocalServiceUtil to interact with database and some time we will use XXXServiceUtil too.

Note:

We can use Dynamic Query API to meet all finder requirements. We can do same as finder methods in Liferay Dynamic Query API.

Complete code for Example

Cutome Method Implemetation(StudentLocalServiceImpl.java)


public class StudentLocalServiceImpl extends
StudentLocalServiceBaseImpl {
public  java.util.List<com.meera.dbservice.model.Student>
findByGenderAndAge(
int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return StudentUtil.findByGender_Age(studentGender, studentAge);
}
}


Cstome method Signature in


public class StudentLocalServiceUtil {
public static java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge(
int studentGender, int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return getService().findByGenderAndAge(studentGender,
 studentAge);
}
}


Calling method in JSP page(/html/jsps/get_students_by_gender_age.jsp)


<%@page import="com.liferay.portal.kernel.util.ListUtil"%>
<%@page import="com.meera.dbservice.model.Student"%>
<%@page import="java.util.List"%>
<%@page import="com.meera.dbservice.service.StudentLocalServiceUtil"%>

<%@ include file="init.jsp"%>
<a href="<portlet:renderURL />">&laquo;Home</a>
<div class="separator"></div>
<liferay-portlet:renderURL varImpl="getStudentsByAgeAndGender">
<portlet:param name="mvcPath"
value="/html/jsps/get_students_by_gender_age.jsp" />
</liferay-portlet:renderURL>
<liferay-portlet:renderURL varImpl="iteratorURL">
<portlet:param name="studentAge"
value="<%= String.valueOf(studentAge) %>" />
<portlet:param name="studentGender"
value="<%= String.valueOf(studentGender) %>" />
<portlet:param name="mvcPath"
value="/html/jsps/get_students_by_gender_age.jsp" />
</liferay-portlet:renderURL>
<h2>Search Students</h2><br/>
<form action="<%=getStudentsByAgeAndGender%>"
name="studentForm"  method="POST">
<b>Age</b><br/>
<input type="text" name="<portlet:namespace/>studentAge" id="<portlet:namespace/>studentAge"
value="<%=String.valueOf(studentAge)%>"/><br/>
<b>Gender</b><br/>
<input type="radio" name="<portlet:namespace/>studentGender" value="1" <%=studentGender==1?"checked":""%>>Male<br>
<input type="radio" name="<portlet:namespace/>studentGender" value="0" <%=studentGender==0?"checked":""%>>Female<br/>
<input type="submit" name="addStudent" id="addStudent" value="Search"/>
</form>
<liferay-ui:search-container
displayTerms="<%= new DisplayTerms(renderRequest) %>"
emptyResultsMessage="there-are-no-students"
headerNames="firstName,studentAge,studentGender"
iteratorURL="<%= iteratorURL %>"
delta="5"
> 
<liferay-ui:search-container-results>
<%

List<Student> studentList=
StudentLocalServiceUtil.findByGenderAndAge(studentGender, studentAge);

searchContainer.setTotal(studentList.size());
studentList = ListUtil.subList(studentList,searchContainer.getStart(),
searchContainer.getEnd());
searchContainer.setResults(studentList);
%>
</liferay-ui:search-container-results>
<liferay-ui:search-container-row
className="Student"
keyProperty="studentId"
modelVar="currentStudent">
<liferay-portlet:renderURL varImpl="rowURL">
<portlet:param name="backURL" value="<%= currentURL %>" />
<portlet:param name="mvcPath" value="/html/jsps/display_student.jsp" />
<portlet:param name="studentId" value="<%= String.valueOf(currentStudent.getStudentId()) %>" />
</liferay-portlet:renderURL>
<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="firstName"
property="firstName"
/>
<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="studentAge"
property="studentAge"
/>
<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="studentGender"
value='<%=currentStudent.getStudentGender()==1?"Male":"Female"%>'
/>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator searchContainer="<%=searchContainer %>" />
</liferay-ui:search-container>


Download Liferay Custom Service Methods Portlet




Environment:

Liferay IDE 2.x+Eclipse (Kepler) +Liferay Plugins SDK 6.2+Tomcat 7.x Liferay Portal Bundle

Deployment and its Working.

Download portlet you can source or war file to deploy into liferay portal as your convenient.

Once portlet successfully deployed drag the portlet in any desired page. Portlet is available in sample category.

In the portlet page you can click on Get Student By Gender And Age link then you can see the search container with search inputs.

Portlet Screens:

Default Page


Search the students by Age and Gender



Reference Links




Author

Popular Posts

Recent Posts

Recent Posts Widget