« Back

Liferay's Architecture: The services layer

Company Blogs November 22, 2012 By Jorge Ferrer Staff

Here I am again for a second entry on the series of Liferay Architecture. This time I'm going to talk a bit more about the services layer of Liferay. As can be seen in the architecture diagram with which I started this series, the services layer is at the core of Liferay Portal:

The Services layer contains the great majority of the business logic for the portal platform and all of the portlets included out of the box. The services are organized in two sets:

  • Portal services (com.liferay.portal.service): contains the services for the portal level entities. A simple trick to identify them is to look at the "Portal" section of the Control Panel menu.
  • Portlet services (com.liferay.portlet.*.service): contains the services used by the different portlets in Liferay. There are also some packages that are not really associated to one portlet (or to more that one), so the word portlet here is being abused a little bit. What matters is that all the services that are no part of the core portal platform are properly organized and componentized.

One very specific aspect of the services layer is that it is divided in two sub-layers:

  1. Local Services (<Entity>LocalService.java): this are the ones that that contain the business logic and communicate with the persistance layer.
  2. Remote Services (<Entity>Service.java): the main goal is to perform security checks before invoking the equivalent method in the local service. In some cases the remote services are also responsible for converting the Java objects returned by the local services layer to other formats. For example, the RSS generation for portlets that support it is done in remote services.

I'm going to finish the entry with some further facts and patterns of Liferay's services layer. The first are more well known but some aren't:

  1. Each persisted entity has an associated service. For example, the User entity has UserService, DLFileEntry (the entity used to store documents of Documents & Media) has the DLFileEntryService.
  2. The services methods are executed in a transaction. That means that if your database supports it (and most do) if there is an error in the middle of the execution of a service method (or in any other method invoked by it), all the previous operations will be undone (rolled back) automatically for you. Liferay implements this under the hood using Spring's transations mechanisms.
  3. The persistance layer is always accessed from local services. You should never access it directly unless you really know what you are doing and you are able to handle transactions manually from the invoking code.
  4. The local services are very strict with the return types of its methods. The return type should be one of the following:
    1. void
    2. <Entity>
    3. List<Entity>
    4. primitive type (this is not used often)

That's it for this second entry. I'm looking forward for your feedback. I'd love to know what topics are more interesting to you so that I can keep them into account for next entries.

Update Nov 29th: Added primitive type as a 4th return type. Thanks David for the note about it.

Threaded Replies Author Date
"DLFileEntry (the entity used to store... Ákos Gábriel November 22, 2012 10:19 AM
Fixed. Thanks Ákos. I'm glad you liked it. Jorge Ferrer November 23, 2012 12:25 AM
Amazing post! Finally we have a great overview... Remis Lima Baima November 23, 2012 2:36 AM
Thanks Remis! That's exactly my plan. Once I... Jorge Ferrer November 23, 2012 4:36 AM
If you are looking for suggestions for next one... Dave Weitzel November 28, 2012 11:51 AM
Thank you for these posts. They definitely help... Alain Dresse November 28, 2012 2:23 PM
Well, there is a 4th type, a primitive (or the... David H Nebinger November 28, 2012 6:43 PM
@Dave Thanks for the suggestion, I do have some... Jorge Ferrer November 29, 2012 1:39 AM
Thanks David. Certainly helps a lot. I had... Alain Dresse November 29, 2012 1:45 AM
As I can read in development documentation,... Andrea Gentili November 30, 2012 7:40 AM
Hi Andrea, If you are accessing the web... Jorge Ferrer December 2, 2012 10:44 PM
@Alain, other entities are supported within the... David H Nebinger December 3, 2012 5:55 AM
Hi Jorge, which Oauth versione (1.0 or 2.0)... Andrea Gentili December 5, 2012 1:43 AM
Right now I think it's 1.0. Oauth 2.0 is more... Jorge Ferrer December 5, 2012 4:35 PM
Hi Jorge , Nice explanation of... Sushil Patidar January 21, 2014 4:34 AM
Hi Jorge , Nice explanation of... Sushil Patidar January 21, 2014 4:35 AM
Hi Sushil, <entity>LocalServiceClp can be used... Jorge Ferrer January 21, 2014 9:16 AM
Hi Jorge, Thanks for quick... Sushil Patidar January 21, 2014 9:49 PM
Liferay's Module Framework, which allows... Jorge Ferrer January 22, 2014 1:33 AM

"DLFileEntry (the entity used to store documents of Documents & Media) has the DLFileEntry"

Service is missing at the end I guess.

Thanks for the useful article again!
Posted on 11/22/12 10:19 AM.
Fixed. Thanks Ákos. I'm glad you liked it.
Posted on 11/23/12 12:25 AM in reply to Ákos Gábriel.
Amazing post!
Finally we have a great overview of the LR Architecture in one single place. I mean: your presentation of LR Architecture in the European Symposium with these blog posts :-).
It would be great it this topics were also integrated in the LR Development Guide: http://www.liferay.com/documentation/liferay-portal/6.1/development
This would help a lot new developers (I know that it would have helped me a lot 2 years ago when I started with LR :-).
Posted on 11/23/12 2:36 AM.
Thanks Remis!
That's exactly my plan. Once I finish the blog series I'll work with Jim Hinkey, the main author of the Dev Guide to incorporate the content in the next version.
Posted on 11/23/12 4:36 AM in reply to Remis Baima.
If you are looking for suggestions for next one I think an explanation of the URL Filtering system and how/ the order of filters is applied, which ones can safely be disabled for performance and which ones never should be would be useful if it isn't covered elsewhere of course.
Posted on 11/28/12 11:51 AM.
Thank you for these posts. They definitely help structure.

Could you please explain why the return types of the local services is so strict? What are the consequences of deviating from this in user defined services ?
Posted on 11/28/12 2:23 PM.
Well, there is a 4th type, a primitive (or the object equivalents).

The reason for the strictness is the CLP layer. ServiceBuilder creates a shim layer so calls are successful over the class loader boundary between different web applications (your plugins are separate wars and have their own class loader).

ServiceBuilder, however, only knows about the types defined in the service.xml file. It has no visibility over other types, no idea if they are appropriately serializable, etc.

There are two ways to use non-DB based entities as return types:

1) the return types must be defined at a global scope (put your classes in a jar and push the jar to the app container's global library, i.e. lib/ext in Tomcat).

2) There's a suggestion here http://www.liferay.com/community/forums/-/message_boards/message/12095602 that would seem to allow for a regular entity definition that might not actually get persisted (as long as you didn't invoke one of the standard CRUD methods).
Posted on 11/28/12 6:43 PM in reply to Alain Dresse.
@Dave Thanks for the suggestion, I do have some slides that cover URL handling but that will be several posts from now emoticon

@Alain, what I'm describing are the conventions we follow at Liferay. We follow them because we think having strict conventions makes it significantly easier to maintain the code for a product this large. Additionally, as David says, these conventions can also be leveraged by our own tools such as Service Builder to do some work for us. You don't need to follow the same conventions (I guess most people won't), but if you use Service Builder you will get benefits from following some of them.

@David, good catch on the 4th type, I'll add it to the post
Posted on 11/29/12 1:39 AM in reply to David H Nebinger.
Thanks David. Certainly helps a lot.

I had initially understood the restriction as being "the entity for which the service is defined". If I understand your answer correctly, I should read the restriction as "the entities defined by ServiceBuilder, i.e. DB based entities".

Not yet clear to me however if the restriction refers to entities in THE currently processed service.xml or if it extends to portal entities (Users, Organizations, ...) and entities defined in service.xml in other wars.
Posted on 11/29/12 1:45 AM in reply to David H Nebinger.
As I can read in development documentation, Liferay web services API support only basic authentication. Is it possible to enforce authentication policy? Thanks in advance
Posted on 11/30/12 7:40 AM.
Hi Andrea,
If you are accessing the web services API through an unsecure channel we recommend you to use HTTPS to protect your credentials.
For next version we are also adding Oauth as an alternative authentication option for web services.
Posted on 12/2/12 10:44 PM in reply to Andrea Gentili.
@Alain, other entities are supported within the same class loader using the @reference object.... But the limitation here is the 'same class loader' thing. Your entities are in one class loader, the portal's entities are in the portal's class loader, and other SB-based plugins will be in their own class loaders...

Here you're kind of stuck returning PKs for the entities that need to be pulled in and use those PKs to fetch them manually.
Posted on 12/3/12 5:55 AM in reply to Jorge Ferrer.
Hi Jorge,
which Oauth versione (1.0 or 2.0) will be supported as option for web service authentication?
Thanks in advance,
Andrea.
Posted on 12/5/12 1:43 AM in reply to David H Nebinger.
Right now I think it's 1.0.

Oauth 2.0 is more of a framework than a protocol.
Posted on 12/5/12 4:35 PM in reply to Andrea Gentili.
Hi Jorge ,
Nice explanation of the liferay service architecture. But service methods are also executed using <entity>LocalServiceClp. Would you please also elaborate the motive of <entity>LocalServiceClp generated by service builder.

Thanks
Posted on 1/21/14 4:34 AM.
Hi Jorge ,
Nice explanation of the liferay service architecture. But service methods are also executed using <entity>LocalServiceClp. Would you please also elaborate the motive of <entity>LocalServiceClp generated by service builder.

Thanks
Posted on 1/21/14 4:35 AM.
Hi Sushil,

<entity>LocalServiceClp can be used to invoke services defined and implemented in one plugin from another plugin. This class is autogenerated to handle the classloading manipulation necessary to do this, since the default classloading mechanisms of J2EE does not allow for it.

Another way of achieving the same and one in which we are investing for 6.2 and future versions is using OSGi.
Posted on 1/21/14 9:16 AM in reply to sushil patidar.
Hi Jorge,
Thanks for quick response. Whether it is possible to use OSGI in earlier versions(LR6 ,LR6.1) also ? .
Posted on 1/21/14 9:49 PM in reply to Jorge Ferrer.
Liferay's Module Framework, which allows developing OSGi modules to extend Liferay, is only available since 6.2. I guess nothing prevents you from using OSGi on your own, but I guess it would be much more work.
Posted on 1/22/14 1:33 AM in reply to sushil patidar.