Liferay Service Builder

  • Sharebar

Why another blog on Service builder ?
Since you have landed on this post, we know that you are looking for a good reference for Liferay Service Builder, and by now you might be frustrated by the minimal documentation from Liferay, or are enervated by scrolling down the liferay forums, or you have been hopping from one blog to other since long. There is not even a single sufficient article/blog which explains service builder in detail. I and my colleague Pratik, faced the same problem some time ago, and we then decided to write a series of blogs which will help you in getting a good understanding of Service Builder.


We are using Liferay 5.2.3 for developing a web based collaboration portal with a very huge user base. Portal requires development of many custom portlets, which means handling CRUDs around old and new entities. We then started searching for some tools which could increase our pace of development of portlets and we came across Liferay Service Builder. This tool has great power but its effective usage requires good level of understanding. So here is the series of upcoming blogs which will introduce the liferay service builder concepts. We will start with "Service Builder Basics" and then dive deeper into advanced topics. Here is a snapshot of different spaces.

  1. Service Builder Basics
  2. Service Builder Finders
  3. Advantages , Disadvantages , Tips and Tricks
  4. Remote Services
  5. Caching
  6. Transactions
  7. Testing

What is service builder ?
Liferay provides a code generation utility called Service Builder, created with an intention to get rid of most boilerplate work during portlet development. Liferay internally uses Spring and Hibernate, which basically means if you are not using service builder, you will end up writing the service layers, pojo’s , dao’s , sql scripts and configuration files if not using annotations. Service Builder does all this with little instructions. To get a good hang of service builder lets walk through an example and run though the various stages starting with concept of an entity and ending with the deployment of that entity inside a portlet with suitable views.

Email Example
Lets say we need an entity of “Email” which has attributes such as from , to , cc, body, date and text.

Configuration
Create a service.xml file in your portlet as location - "portlet/docroot/WEB-INF/service.xml".  service.xml should stick to this schema definitions. Add entry for Email entity in service.xml.

<entity name="Email" local-service="true" remote-service="false" table="Email">
   	 <column name="id" type="long" primary="true">
   	 <column name="to" type="String">
   	 <column name="from" type="String">
   	 <column name="subject" type="String">
   	 <column name="content" type="String">
   	 <column name="date" type="Date">

   	 <!--  Finders -->
   	 <finder name="To" return-type="Collection">
   		 <finder-column name="to"></finder-column>
          </finder>
   	 <finder name="From" return-type="Collection">
   		 <finder-column name="from"></finder-column>
         </finder>
   	 <finder name="Subject" return-type="Collection">
   		 <finder-column name="subject"></finder-column>
         </finder>
   	<finder name="Date" return-type="Collection">
   		 <finder-column name="date"></finder-column>
         </finder>
</entity>
  • entity refers to a new model which we want to create
  • name attribute refers to the name of the entity
  • column tag represents the different fields in entity or columns in table
  • type refers to the data-type . Please note you cannot establish one-to-many or many-to-many relationships using this.
  • finder tag is used to create find utility methods

Code Generation
Run "ant build-service" from the command (will work only if liferay bin is included in your path). Below is the explanation of all the classes that will be generated. Liferay strictly follows program to interface design so every impl will have its corresponding interface.

Generated classes.
Service Builder generates three types of classes i.e. Model, Service and Persistence

Model Objects

These objects are nothing but the data/value objects.

Following is the list of model classes generated when you run service builder

  • BaseModel - This is the Base class provided by liferay which is extended by every model/entity object. This is analogous to object class in Java.
  • BaseModelImpl - Basic implementation provided by liferay for BaseModel.
  • EmailModel - Interface for the getters/setters of all the fields that are specified in the service.xml for this entity.
  • Email - This is interface for Email entity.
  • EmailModelImpl - Implementation for the EmailModel methods and couple of other utility methods like clone , toString etc.
  • EmailImpl - By Default this class is empty. The purpose of this class is to provide a placeholder to have custom methods on the entity (which are not generated by default) . For instance, if you want to make this entity rich by having  methods like validate “to” field , you can add method something like this
     …
    <pre>public boolean validateToAddress(){
    //Add code to validate this.to
    }
    …
    

    Now once you add this method in the Impl , you need to have this inside a corresponding interface also which is Email. To add this method signature just run the "build-service" target again and method will be added to EmailInterface. Please note that the method cannot be added inside the EmailModelImpl because in case if we change the entity in future or just run the ant build-service, those custom written methods will get deleted.

Service Objects

Once you have you model objects, you need services to operate on them, and service builders generates these as well


Following are the classes generated by service builder for service layer
  • EmailLocalService : Interface containing all the crud operations that can be performed on the Email entity. for e.g add/delete/get/update/find
  • EmailLocalServiceBaseImpl : Implementation for the EmailLocalService .This class is injected will the serviceImpl’s and persistenceImpl’s of all entities present in the service.xml. One service may need to call other service to do business operations. Injection of these service and persistence impls fully equipts base impl to do such type of operations.
  • EmailLocalServiceImpl : This class has the same role as EmailImpl in the model layer. If you want to add custom methods in the service layer for this model, then you can add the implementation in this class and run the ant build-service, and the new method signature will be pushed into EmailLocalService as well.
  • EmailLocalServiceUtil : Since we are using spring, ideally we should be able to inject the EmailLocalServiceImpl instance into a java class of view layer (e.g ActionClasses in struts or PageClass in Wicked), but in liferay if you are using JSP Portlet , it will not be possible to inject this dependency . So this util contains the same method signatures as the EmailLocalService but with static qualifier, so that you can use them directly. Internally it will look up that impl from the spring context and then execute the methods on it.
  • EmailLocalServiceClp : Clp or ClassLoaderProxy objects are used to serialize the objects. In this case it will be used to serialize EmailLocalServiceImpl. These clps are used for remote services which will be discussed in detail later.

Persistence objects

Persistence classes contain all the code for dealing with hibernate sessions and fetching the actual model objects

  • BasePersistence - BasePersistence class is provided by liferay which every persistence impl extends. Some of the methods are registerListener , unregisterListener which are used to associate listeners with events occurring on the Entity Table. for e.g addition of new entity.
  • SessionFactory - As the name suggests, this classes is used for the database sessions.We rarely have to deal directly with this class. This class is extended by the BasePersitenceImpl.
  • BasePersistenceImpl - Default implementation for the BasePersistence and SessionFactory.
  • EmailPersistence - Interface for the basic CRUD operation that can be done on the Email Model.
  • EmailPersistenceImpl - Implementation for the EmailPersistence. Again this class is also injected with the persistence impl of all the entities specified in the service.xml. This persistence impl is not same as the ModelImpl or LocalServiceImpl, because you cannot write your custom methods in this class. If you have to create a custom persistence method then you need to create a finder. This will be discussed in our next blog.

Generated sql’s

tables.sql - This sql contains the basic template for table creation. This has to be tweaked as per the database used.

create table Email (
    id_ LONG not null primary key,
    to_ VARCHAR(75) null,
    from_ VARCHAR(75) null,
    subject VARCHAR(75) null,
    content VARCHAR(75) null,
    date_ DATE null
);

indexes.sql : This sql lists the indexes on those fields which are specified as finders in the service.xml.

create index IX_936DE65F on Email (date_);
create index IX_19F9ECE3 on Email (from_);
create index IX_8DEFA35A on Email (subject);
create index IX_92C5C772 on Email (to_);


Code Utilization

Lets take the use case of displaying all the emails that were created yesterday. So, to fetch emails by date, our portlet will call service class, which will call persistence class, and this will return the list of emails created yesterday. Lets start in t the reverse order and see how to write custom methods in each layer.

Persistence layer

This finder entry shown below, which we added while creating our Email entity,  is responsible for creation of a finder method in EmailPersestenceImpl.java and  and also in EmailPersistence.java.

	<finder name="Date" return-type="Collection">
   		 <finder-column name="date">
   	 </finder-column></finder>

The method which gets added has the following signature:

	public java.util.List<com.xebia.general.model.email> findByDate(
   	 java.util.Date date) throws com.liferay.portal.SystemException;

Service Layer

Our service layer should have a custom method which will take a date and then call the persistence layer to get all the emails corresponding to that date.  Our custom method will go into EmailLocalServiceImpl.java and will look like

public  List<email> getAllEmailsByDate(Date createdDate) throws SystemException{
   		 List<email> emailsByDate = emailPersistence.findByDate(createdDate);
   		 return emailsByDate;
    }

After adding this method run service builder. Service Builder then pushes this method in the corresponding service and util classes. The new method that is added in EmailLocalService.java will look like

	@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public java.util.List<com.xebia.general.model.email> getAllEmailsByDate(
   	 java.util.Date createdDate) throws com.liferay.portal.SystemException;

and in EmaiLocalServiceUtil.java

	public static java.util.List<com.xebia.general.model.email> getAllEmailsByDate(
   	 java.util.Date createdDate) throws com.liferay.portal.SystemException {
   	 return getService().getAllEmailsByDate(createdDate);
    }

Portlet code

We now have the method for fetching emails by date in both persistence and service layer. Lets call the LocalServiceUtil class to get yesterday's emails

List<email> emailsByDate = EmailLocalServiceUtil.getAllEmailsByDate(yesterday);

We would now like to conclude the "Service Builder Basics". After reading this post you should know: the classes generated by liferay, using of the generated classes, and placeholders for adding your custom code. In the next post we will add some entities in Email, and will then see how to use one-to-many, many-to-many, or write custom sqls by using finders.

Share the bee buzz:
  • Digg
  • del.icio.us
  • Facebook
  • DZone
  • LinkedIn
  • StumbleUpon
  • Technorati
  • Twitter

6 Responses to “Liferay Service Builder”

  1. Awesome post.. Well done Robin and Pratik !!
    waiting for rest of the post in the series

  2. Great work. Can’t wait for the next post!

  3. Excellent article on Service Builders

  4. Its a nice and detail

  5. [...] 1. Liferay Service-builder: Perhaps the most important tool and most widely used feature of liferay, We used this for rapidly generating services, persistence and sql create scripts . However, we did face several issues with Service builder, which would open a whole new chapter of discussion if we start dissecting service builder here, but for now I would say it was a good bargain. How to use service builder can be found here. [...]

  6. i am waiting for next article please include explanation of one to one mapping between entities specified in same service.xml.

Leave a Reply