Service Builder
Service
  Builder is a model-driven code generation tool built by Liferay to  
automate the creation of interfaces and classes for database persistence
  and a service layer. Service Builder will generate most of the common 
 code needed to implement find, create, update, and delete operations on
  the database, allowing you to focus on the higher level aspects of  
service design.
The service layer generated by 
Service  Builder, has an implementation class that is responsible to 
handle  retrieving and storing data classes and adding the necessary 
business  logic around them. This layer can optionally be composed of 
two layers,  the local service and the remote service. The local service
 contains the  business logic and accesses the persistence layer. It can
 be invoked by  client code running in the same Java Virtual Machine. 
The remote  service usually ads a code to check security and is meant to
 be  accessible from anywhere over the Internet or your local network.  
Service Builder automatically generates the code necessary to allow  
access to the remote services using SOAP, JSON and Java RMI. 
Define the Model
The
  first step in using Service Builder is to define your model classes 
and  their attributes in a service.xml file. For convenience, we will 
define  the service within the my-greeting portlet, although it should 
be  placed inside a new portlet. Create a file named service.xml in  
portlets/my-greeting-portlet/docroot/WEB-INF inside the Plugins SDK and 
 add the following content:
<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd">
<service-builder package-path="com.sample.portlet.library">
<namespace>Library</namespace>
<entity name="Book" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="bookId" type="long" primary="true" />
<!-- Group instance -->
<column name="groupId" type="long" />
<!-- Audit fields -->
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />
<!-- Other fields -->
<column name="title" type="String" />
</entity>
</service-builder>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.0.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd">
<service-builder package-path="com.sample.portlet.library">
<namespace>Library</namespace>
<entity name="Book" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="bookId" type="long" primary="true" />
<!-- Group instance -->
<column name="groupId" type="long" />
<!-- Audit fields -->
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="userName" type="String" />
<column name="createDate" type="Date" />
<column name="modifiedDate" type="Date" />
<!-- Other fields -->
<column name="title" type="String" />
</entity>
</service-builder>
Overview of service.xml
<service-builder package-path="com.sample.portlet.library">
This
  specifies the package path that the class will generate to. In this  
example, classes will generate to  
WEB-INF/src/com/sample/portlet/library/
<namespace>Library</namespace>
The namespace element must be a unique namespace for this component. Table names will be prepended with this namepace.
<entity name="Book" local-service="true" remote-service="false">
The entity name is the database table you want to create.
<column name="title" type="String" />
Columns
  specified in service.xml will be created in the database with a data  
type appropriate to the Java type. Accessors will be automatically  
generated for these attributes in the model class.
Tip:
  Always consider adding two long fields called groupId and companyId to
  your data models. These two fields will allow your portlet to support 
 the multi-tenancy features of Liferay so that each community or  
organization (for each portal instance) can have its own independent  
data.
Generate the Service
Open a terminal window in your portlets/my-greeting-portlet directory and enter this command:
ant build-service
The
  service has been generated successfully when you see "BUILD  
SUCCESSFUL." In the terminal window, you should see that a large number 
 of files have been generated. An overview of these files is provided  
below:
- Persistence
- BookPersistence - book persistence interface @generated
 - BookPersistenceImpl - book persistence @generated
 - BookUtil - book persistence util, instances BookPersistenceImpl @generated
 
 - Local Service
- BookLocalServiceImpl - local service implementation. This is the only class within the local service that you will be able to modify manually. Your business logic will be here.
 - BookLocalService - local service interface @generated
 - BookLocalServiceBaseImpl - local service base @generated @abstract
 - BookLocalServiceUtil - local service util, instances BookLocalServiceImpl @generated
 - BookLocalServiceWrapper - local service wrapper, wraps BookLocalServiceImpl @generated
 
 - Remote Service
- BookServiceImpl - remove service implementation. Put here the code that adds additional security checks and invokes the local service.
 - BookService - remote service interface @generated
 - BookServiceBaseImpl - remote service base @generated @abstract
 - BookServiceUtil - remote service util, instances BookServiceImpl @generated
 - BookServiceWrapper - remote service wrapper, wraps BookServiceImpl @generated
 - BookServiceSoap - soap remote service, proxies BookServiceUtil @generated
 - BookSoap - soap book model, similar to BookModelImpl, does not implement Book @generated
 - BookServiceHttp - http remote service, proxies BookServiceUtil @generated
 - BookJSONSerializer - json serializer, converts Book to JSON array @generated
 
 - Model
- BookModel - book base model interface @generated
 - BookModelImpl - book base model @generated
 - Book - book model interface @generated
 - BookImpl - book model implementation. You can use this class to add additional methods to your model other than the autogenerated field getters and setters.
 - BookWrapper - book wrapper, wraps Book @generated
 
 
Out of all of these classes only three can be manually modified: BookLocalServiceImpl, BookServiceImpl and BookImpl.
Write the Local Service Class
In
  the file overview above, you will see that BookLocalService is the  
interface for the local service. It contains the signatures of every  
method in BookLocalServiceBaseImpl and BookLocalServiceImpl.  
BookLocalServiceBaseImpl contains a few automatically generated methods 
 providing common functionality. Since this class is generated, you  
should never modify it, or your changes will be overwritten the next  
time you run Service Builder. Instead, all custom code should be placed 
 in BookLocalServiceImpl.
Open the following file:
/docroot/WEB-INF/src/com/sample/portlet/library/service/impl/BookLocalServiceImpl.java
We
  will be adding the database interaction methods to this service layer 
 class. Add the following method to the BookLocalServiceImpl class:
public Book addBook(long userId, String title)
throws PortalException, SystemException {
User user = UserUtil.findByPrimaryKey(userId);
Date now = new Date();
long bookId = CounterLocalServiceUtil.increment(Book.class.getName());
Book book = bookPersistence.create(bookId);
book.setTitle(title);
book.setCompanyId(user.getCompanyId());
book.setUserId(user.getUserId());
book.setUserName(user.getFullName());
book.setCreateDate(now);
book.setModifiedDate(now);
book.setTitle(title);
return bookPersistence.update(book);
}
throws PortalException, SystemException {
User user = UserUtil.findByPrimaryKey(userId);
Date now = new Date();
long bookId = CounterLocalServiceUtil.increment(Book.class.getName());
Book book = bookPersistence.create(bookId);
book.setTitle(title);
book.setCompanyId(user.getCompanyId());
book.setUserId(user.getUserId());
book.setUserName(user.getFullName());
book.setCreateDate(now);
book.setModifiedDate(now);
book.setTitle(title);
return bookPersistence.update(book);
}
Before  you can use this new method, 
you must add its signature to the  BookLocalService interface by running
 service builder again.
Navigate to the root folder of your portlet in the terminal and run:
ant build-service
Service
  Builder looks through BookLocalServiceImpl and automatically copies 
the  signatures of each method into the interface. You can now add a new
  book to the database by making the following call
BookLocalServiceUtil.addBook(userId, "A new title");
Built-In Liferay Services
In
  addition to the services you create using Service Builder, your  
portlets may also access a variety of services built into Liferay. These
  include UserService, OrganizationService, GroupService, 
CompanyService,  ImageService, LayoutService, OrganizationService, 
PermissionService,  UserGroupService, and RoleService. For more 
information on these  services, see Liferay in Action and Liferay's 
Javadocs. 
Security and Permissions Service
Liferay
  Portal implements a fine-grained permissions system, which developers 
 can use to implement access security into their custom portlets, giving
  administrators and users a lot more control over their portlets and  
content. This section of the document will provide a reference for  
implementing security into custom portlets. 
- Overview
 
Adding fine-grained permissions to custom portlets consists of four main steps (also known as DRAC):
- Define all resources and their permissions.
 - Register all the resources defined in step 1 into the permissions system. This is also known simply as "adding resources."
 - Associate the necessary permissions to these resources.
 - Check permission before returning resources.
 
- Implementing Permissions
 
In  this section, each of the four main steps in 
adding Liferay's security  feature into custom portlets (built on top of
 the Liferay portal) will  be explained. The following are two 
definitions that are important to  remember.
Resource
 - A generic term for any object  represented in the portal. Examples of
 resources include portlets (e.g.,  Message Boards, Calendar, etc.), 
Java classes (e.g., Message Board  Topics, Calendar Events, etc.), and 
files (e.g., documents, images,  etc.)
Permission -
 An action acting on a resource. For  example, the view in "viewing the 
calendar portlet" is defined as a  permission in Liferay.
Keep
 in mind that the  permission for a portlet resource is implemented a 
little differently  from the other resources such as Java classes and 
files. In each of the  subsections below, the permission implementation 
for the portlet  resource is explained first, then the model (and file) 
resource.
For  your custom portlet, 
Liferay portal needs to know whether there are  resources that require 
permission and whether there are custom  permissions. The default 
configuration is encapsulated in an XML file  found in the portal source
 under the  /portal-impl/classes/resource-actions directory; you might 
use it as a  reference to create a similar file for your portlet. There 
is also a  Sample Permissions portlet available in the Plugins project 
on  SourceForge. If your portlet only needs the view and the 
configuration  permission, and that the portlet doesn't use any models 
with permission,  then you do not need to create this XML file. The 
reason is that all  portlets in Liferay automatically inherit these 
permissions. However, if  your portlet does have custom permission 
and/or uses models that have  custom permissions, then you will need to 
create an XML file defining  the resources and actions. Let's take a 
look at blogs.xml in  portal/portal-impl/classes/resource-actions and 
see how the blogs  portlet defined these resources and actions: 
<?xml version="1.0"?>
<resource-action-mapping>
<portlet-resource>
<portlet-name>33</portlet-name>
<supports>
<action-key>ADD_ENTRY</action-key>
<action-key>CONFIGURATION</action-key>
<action-key>VIEW</action-key>
</supports>
<community-defaults>
<action-key>VIEW</action-key>
</community-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>ADD_ENTRY</action-key>
</guest-unsupported>
</portlet-resource>
<model-resource>
<model-name>com.liferay.portlet.blogs.model.BlogsEntry</model-name>
<portlet-ref>
<portlet-name>33</portlet-name>
</portlet-ref>
<supports>
<action-key>ADD_DISCUSSION</action-key>
<action-key>DELETE</action-key>
<action-key>DELETE_DISCUSSION</action-key>
<action-key>PERMISSIONS</action-key>
<action-key>UPDATE</action-key>
<action-key>UPDATE_DISCUSSION</action-key>
<action-key>VIEW</action-key>
</supports>
<community-defaults>
<action-key>ADD_DISCUSSION</action-key>
<action-key>VIEW</action-key>
</community-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>ADD_DISCUSSION</action-key>
<action-key>DELETE</action-key>
<action-key>DELETE_DISCUSSION</action-key>
<action-key>PERMISSIONS</action-key>
<action-key>UPDATE</action-key>
<action-key>UPDATE_DISCUSSION</action-key>
</guest-unsupported>
</model-resource>
</resource-action-mapping>
<resource-action-mapping>
<portlet-resource>
<portlet-name>33</portlet-name>
<supports>
<action-key>ADD_ENTRY</action-key>
<action-key>CONFIGURATION</action-key>
<action-key>VIEW</action-key>
</supports>
<community-defaults>
<action-key>VIEW</action-key>
</community-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>ADD_ENTRY</action-key>
</guest-unsupported>
</portlet-resource>
<model-resource>
<model-name>com.liferay.portlet.blogs.model.BlogsEntry</model-name>
<portlet-ref>
<portlet-name>33</portlet-name>
</portlet-ref>
<supports>
<action-key>ADD_DISCUSSION</action-key>
<action-key>DELETE</action-key>
<action-key>DELETE_DISCUSSION</action-key>
<action-key>PERMISSIONS</action-key>
<action-key>UPDATE</action-key>
<action-key>UPDATE_DISCUSSION</action-key>
<action-key>VIEW</action-key>
</supports>
<community-defaults>
<action-key>ADD_DISCUSSION</action-key>
<action-key>VIEW</action-key>
</community-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>ADD_DISCUSSION</action-key>
<action-key>DELETE</action-key>
<action-key>DELETE_DISCUSSION</action-key>
<action-key>PERMISSIONS</action-key>
<action-key>UPDATE</action-key>
<action-key>UPDATE_DISCUSSION</action-key>
</guest-unsupported>
</model-resource>
</resource-action-mapping>
In  the 
XML, the first thing defined is the portlet itself. Right under the  
root element <resource-action-mapping>, we have a child element  
called <portlet-resource>. In this element, we define the portlet 
 name, which is 33 in our case. Next, we list all the actions this  
portlet supports under the <supports> tag. Keep in mind that this 
 is at the portlet level. To understand what should be listed here,  
developers should ask themselves what actions belong to the portlet  
itself or what actions are performed on the portlet that may require a  
security check. In our case, users need permission to add an entry  
(ADD_ENTRY), configure blogs portlet settings (CONFIGURATION), and view 
 the blogs itself (VIEW). Each of these supported permissions is within 
 its own <action-key> tag. After we've defined all the actions 
that  require a check, we move on to define some of the default 
permission  settings. The community-defaults tag defines what actions 
are permitted  by default for this portlet on the community (group) page
 upon which the  portlet resides. To put it another way, what should a 
user that has  access to the community in which this portlet resides be 
able to do  minimally? For the blogs portlet, a user with access to the 
community  containing the blogs portlet should be able to view it. 
Likewise, the  guest-defaults tag defines what actions are permitted by 
default to  guests visiting a layout containing this portlet. So if a 
guest has  access to the community page that contains a blogs portlet, 
the guest  should, at the very least, be able to view the portlet 
according to  blogs.xml (not necessarily the content of the portlet). 
Otherwise, the  guest will see an error message within the portlet. 
Depending on your  custom portlet, you may add more actions here that 
make sense. The  guest-unsupported tag contains actions that a visiting 
guest should  never be able to do. For example, the guest visiting the 
blogs portlet  should never be able to add a blog entry since the blog 
belongs to  either a user or a group of users. So even if a user wants 
to grant  guests the ability to add a blog entry to her blog, there is 
no way for  her to grant that permission because the blogs.xml doesn't 
permit such  an action for guests.
After 
defining the  portlet as a resource, we move on to define models within 
the portlet  that also require access check. The model resource is 
surrounded by the  <model-resource> tag. Within this tag, we first
 define the model  name. This must be the fully qualified Java class 
name of the model.  Next we define the portlet name that this model 
belongs to under the  portlet-ref tag. Though unlikely, a model can 
belong to multiple  portlets, which you may use multiple 
<portlet-name> tags to  define. Similar to the portlet resource 
element, the model resource  element also allows you to define a 
supported list of actions that  require permission to perform. You must 
list out all the performable  actions that require a permission check. 
As you can see for a blog  entry, a user must have permission in order 
to add comments to an entry,  delete an entry, change the permission 
setting of an entry, update an  entry, or simply to view an entry. The 
<community-defaults> tag,  the <guest-defaults> tag, and the
 <guest-unsupported> tag  are all similar in meaning to what's 
explained above for a portlet  resource.
After
 defining your permission  scheme for your custom portlet, you then need
 to tell Liferay the  location of this file. For Liferay core, the XML 
file would normally  reside in 
portal/portal-impl/classes/resource-actions and a reference to  the file
 would appear in the default.xml file. For a plugin, you should  put the
 file in a directory that is in the class path for the project.  Then 
create a properties file for your portlet (the one in the Sample  
Permissions Portlet is simply called,  
sample-permissions-portlet.properties) and create a property called  
resource.actions.configs with a value that points to the the XML file.  
Below is an example from the Sample Permissions Portlet: 
resource.actions.configs=resource-actions/sample-permissions-portlet.xml
- Adding Resource
 
After  defining resources and actions, 
the next task is to write code that  adds resources into the permissions
 system. A lot of the logic to add  resources is encapsulated in the 
ResourceLocalServiceImpl class. So  adding resources is as easy as 
calling the add resource method in  ResourceLocalServiceUtil class.
public void addResources(
String companyId, String groupId, String userId, String name,
String primKey, boolean portletActions,
boolean addCommunityPermissions, boolean addGuestPermissions);
String companyId, String groupId, String userId, String name,
String primKey, boolean portletActions,
boolean addCommunityPermissions, boolean addGuestPermissions);
For
  all the Java objects that require access permission, you need to make 
 sure that they are added as resources every time a new one is created. 
 For example, every time a user adds a new entry to her blog, the  
addResources(…) method is called to add the new entry to the resource  
system. Here's an example of the call from the  
BlogsEntryLocalServiceImpl class.
ResourceLocalServiceUtil.addResources(
entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
BlogsEntry.class.getName(), entry.getPrimaryKey().toString(),
false, addCommunityPermissions, addGuestPermissions);
entry.getCompanyId(), entry.getGroupId(), entry.getUserId(),
BlogsEntry.class.getName(), entry.getPrimaryKey().toString(),
false, addCommunityPermissions, addGuestPermissions);
The
  parameters companyId, groupId, and userId should be self explanatory. 
 The name parameter is the fully qualified Java class name for the  
resource object being added. The primKey parameter is the primary key of
  the resource object. As for the portletActions parameter, set this to 
 true if you're adding portlet action permissions. In our example, we 
set  it to false because we're adding a model resource, which should be 
 associated with permissions related to the model action defined in  
blogs.xml. The addCommunityPermissions and the addGuestPermissions  
parameters are inputs from the user. If set to true,  
ResourceLocalService will then add the default permissions to the  
current community group and the guest group for this resource  
respectively.
If you would like to 
provide  your user the ability to choose whether to add the default 
community  permission and the guest permission for the resources within 
your custom  portlet, Liferay has a custom JSP tag you may use to 
quickly add that  functionality. Simply insert the 
<liferay-ui:input-permissions />  tag into the appropriate JSP and
 the checkboxes will show up on your  JSP. Of course, make sure the tag 
is within the appropriate <form>  tags.
To
 prevent having a lot of dead  resources taking up space in the 
Resource_ database table, you must  remember to remove them from the 
Resource_ table when the resource is no  longer applicable. Simply call 
the deleteResource(…) method in  ResourceLocalServiceUtil. Here's an 
example of a blogs entry being  removed:
ResourceLocalServiceUtil.deleteResource(
entry.getCompanyId(), BlogsEntry.class.getName(),
Resource.TYPE_CLASS, Resource.SCOPE_INDIVIDUAL,
entry.getPrimaryKey().toString());
entry.getCompanyId(), BlogsEntry.class.getName(),
Resource.TYPE_CLASS, Resource.SCOPE_INDIVIDUAL,
entry.getPrimaryKey().toString());
- Adding Permission
 
On  the portlet level, no code needs to 
be written in order to have the  permission system work for your custom 
portlet. Your custom portlet will  automatically have all the permission
 features. If you've defined any  custom permissions (supported actions)
 in your portlet-resource tag in  section 3.1, those are automatically 
added to a list of permissions and  users can readily choose them. Of 
course, for your custom permissions to  have any value, you'll need to 
show or hide certain functionality in  your portlet. You can do that by 
checking the permission first before  performing the intended 
functionality. 
In  order to allow a user
 to set permissions on the model resources, you  will need to expose the
 permission interface to the user. This can be  done by adding two 
Liferay UI tags to your JSP. The first one is the  
<liferay-security:permissionsURL> tag which returns a URL that  
takes the user to the page to configure the permission settings. The  
second tag is the <liferay-ui:icon> tag that shows a permission  
icon to the user. Below is an example found in the file  
view_entry_content.jspf.
<liferay-security:permissionsURL
modelResource="<%= BlogsEntry.class.getName() %>"
modelResourceDescription="<%= entry.getTitle() %>"
resourcePrimKey="<%= entry.getPrimaryKey().toString() %>"
var="entryURL"
/>
<liferay-ui:icon image="permissions" url="<%= entryURL %>" />
modelResource="<%= BlogsEntry.class.getName() %>"
modelResourceDescription="<%= entry.getTitle() %>"
resourcePrimKey="<%= entry.getPrimaryKey().toString() %>"
var="entryURL"
/>
<liferay-ui:icon image="permissions" url="<%= entryURL %>" />
The
  attributes you need to provide to the first tag are modelResource,  
modelResourceDescription, resourcePrimKey, and var. The modelResource  
attribute is the fully qualified Java object class name. It then gets  
translated in Language.properties to a more readable name.
As
  for the modelResourceDescription attribute, you can pass in anything  
that best describes this model instance. In the example, the blogs title
  was passed in. The resourcePrimKey attribute is simply the primary key
  of your model instance. The var attribute is the variable name this 
URL  String will get assigned to. This variable is then passed to the  
<liferay-ui:icon> tag so the permission icon will have the proper 
 URL link. There's also an optional attribute redirect that's available 
 if you want to override the default behavior of the upper right arrow  
link. That is all you need to do to enable users to configure the  
permission settings for model resources.
- Checking Permissions
 
The  last major step to implementing permission to
 your custom portlet is to  check permission. This may be done in a 
couple of places. For example,  your business layer should check for 
permission before deleting a  resource, or your user interface should 
hide a button that adds a model  (e.g., a calendar event) if the user 
does not have permission to do so.
Similar  to the
 other steps, the default permissions for the portlet resources  are 
automatically checked for you. You do not need to implement anything  
for your portlet to discriminate whether a user is allowed to view or  
to configure the portlet itself. However, you do need to implement any  
custom permission you have defined in your resource-actions XML file. In
  the blogs portlet example, one custom supported action is ADD_ENTRY.  
There are two places in the source code that check for this permission. 
 The first one is in the file view_entries.jsp. The presence of the add 
 entry button is contingent on whether the user has permission to add  
entry (and also whether the user is in tab one).
<%
boolean showAddEntryButton = tabs1.equals("entries") && PortletPermission.contains(permissionChecker, plid, PortletKeys.BLOGS, ActionKeys.ADD_ENTRY);
%>
boolean showAddEntryButton = tabs1.equals("entries") && PortletPermission.contains(permissionChecker, plid, PortletKeys.BLOGS, ActionKeys.ADD_ENTRY);
%>
The second place that  checks for the add 
entry permission is in the file  BlogsEntryServiceImpl. (Notice the 
difference between this file and the  BlogsEntryLocalServiceImpl.) In 
the addEntry(…) method, a call is made  to check whether the incoming 
request has permission to add entry.
PortletPermission.check(
getPermissionChecker(), plid, PortletKeys.BLOGS,
ActionKeys.ADD_ENTRY);
getPermissionChecker(), plid, PortletKeys.BLOGS,
ActionKeys.ADD_ENTRY);
If  the check fails, it 
throws a PrincipalException and the add entry  request aborts. You're 
probably wondering what the PortletPermission and  the PermissionChecker
 classes do. Let's take a look at these two  classes.
The
 PermissionChecker class has a method  called hasPermission(…) that 
checks whether a user making a resource  request has the necessary 
access permission. If the user is not signed  in (guest user), it checks
 for guest permissions. Otherwise, it checks  for user permissions. This
 class is available to you in two places.  First in your business logic 
layer, you can obtain an instance of the  PermissionChecker by calling 
the getPermissionChecker() method inside  your ServiceImpl class. This 
method is available because all ServiceImpl  (not LocalServiceImpl) 
classes extend the PrincipalBean class, which  implements the 
getPermissionChecker() method. The other place where you  can obtain an 
instance of the PermissionChecker class is in your JSP  files. If your 
JSP file contains the portlet tag  <portlet:defineObjects /> or 
includes another JSP file that does,  you'll have an instance of the 
PermissionChecker class available to you  via the permissionChecker 
variable. Now that you know what the  PermissionChecker does and how to 
obtain an instance of it, let's take a  look at Liferay's convention in 
using it.
PortletPermission  is a helper class 
that makes it easy for you to check permission on  portlet resources (as
 opposed to model resources, covered later). It has  two static methods 
called check(…) and another two called contains(…).  They are all 
essentially the same. The two differences between them are:
- One check(…) method and one contains(…) method take in the portlet layout ID variable (plid).
 - The check(…) methods throw a new PrincipalException if user does not have permission, and the contains(…) methods return a boolean indicating whether user has permission.
 
The contains(…)  methods are meant to be used in 
your JSP files since they return a  boolean instead of throwing an 
exception. The check(…) methods are meant  to be called in your business
 layer (ServiceImpl). Let's revisit the  blogs portlet example below. 
(The addEntry(…) method is found in  BlogsEntryServiceImpl.)
public BlogsEntry addEntry(
long plid, String title, String content, int displayDateMonth,
int displayDateDay, int displayDateYear, int displayDateHour,
int displayDateMinute, String[] tagsEntries,
boolean addCommunityPermissions, boolean addGuestPermissions,
ThemeDisplay themeDisplay)
throws PortalException, SystemException {
PortletPermissionUtil.check(
getPermissionChecker(), plid, PortletKeys.BLOGS,
ActionKeys.ADD_ENTRY);
return blogsEntryLocalService.addEntry(
getUserId(), plid, title, content, displayDateMonth, displayDateDay,
displayDateYear, displayDateHour, displayDateMinute, tagsEntries,
addCommunityPermissions, addGuestPermissions, themeDisplay);
}
long plid, String title, String content, int displayDateMonth,
int displayDateDay, int displayDateYear, int displayDateHour,
int displayDateMinute, String[] tagsEntries,
boolean addCommunityPermissions, boolean addGuestPermissions,
ThemeDisplay themeDisplay)
throws PortalException, SystemException {
PortletPermissionUtil.check(
getPermissionChecker(), plid, PortletKeys.BLOGS,
ActionKeys.ADD_ENTRY);
return blogsEntryLocalService.addEntry(
getUserId(), plid, title, content, displayDateMonth, displayDateDay,
displayDateYear, displayDateHour, displayDateMinute, tagsEntries,
addCommunityPermissions, addGuestPermissions, themeDisplay);
}
Before  the addEntry(…) method calls 
BlogsEntryLocalServiceUtil.addEntry(…) to  add a blogs entry, it calls 
PortletPermission.check(…) to validate user  permission. If the check 
fails, a PrincipalException is thrown and an  entry will not be added. 
Note the parameters passed into the method.  Again, the 
getPermissionChecker() method is readily available in all  ServiceImpl 
classes. The plid variable is passed into the method by its  caller 
(most likely from a PortletAction class). PortletKeys.BLOGS is  just a 
static String indicating that the permission check is against the  blogs
 portlet. ActionKeys.ADD_ENTRY is also a static String to indicate  the 
action requiring the permission check. You're encouraged to do  likewise
 with your custom portlet names and custom action keys.
Whether
  you need to pass in a portlet layout ID (plid) depends on whether your
  custom portlet supports multiple instances. Let's take a look at the  
message board portlet for example. A community may need three separate  
page layouts, each having a separate instance of the message board  
portlet. Only by using the portlet layout ID will the permission system 
 be able to distinguish the three separate instances of the message 
board  portlet. This way, permission can be assigned separately in all 
three  instances. Though in general, most portlets won't need to use the
  portlet layout ID in relation to the permission system.
Since
  the ServiceImpl class extends the PrincipalBean class, it has access 
to  information of the current user making the service request. 
Therefore,  the ServiceImpl class is the ideal place in your business 
layer to check  user permission. Liferay's convention is to implement 
the actual  business logic inside the LocalServiceImpl methods, and then
 the  ServiceImpl calls these methods via the LocalServiceUtil class 
after the  permission check completes successfully. Your PortletAction 
classes  should make calls to ServiceUtil (wrapper to ServiceImpl) 
guaranteeing  that permission is first checked before the request is 
fulfilled.
Checking  model resource permission is 
very similar to checking portlet resource  permission. The only major 
difference is that instead of calling methods  found in the 
PortletPermission class mentioned previously, you need to  create your 
own helper class to assist you in checking permission. The  next section
 will detail how this is done.
It is  advisable to
 have a helper class to help check permission on your custom  models. 
This custom permission class is similar to the  PortletPermission class 
but is tailored to work with your custom models.  While you can 
implement this class however you like, we encourage you  to model your 
implementation after the PortletPermission class, which  contains four 
static methods. Let's take a look at the  BlogsEntryPermission class.
public class BlogsEntryPermission {
public static void check(
PermissionChecker permissionChecker, long entryId, String actionId)
throws PortalException, SystemException {
if (!contains(permissionChecker, entryId, actionId)) {
throw new PrincipalException();
}
}
public static void check(
PermissionChecker permissionChecker, BlogsEntry entry,
String actionId)
throws PortalException, SystemException {
if (!contains(permissionChecker, entry, actionId)) {
throw new PrincipalException();
}
}
public static boolean contains(
PermissionChecker permissionChecker, long entryId, String actionId)
throws PortalException, SystemException {
BlogsEntry entry = BlogsEntryLocalServiceUtil.getEntry(entryId);
return contains(permissionChecker, entry, actionId);
}
public static boolean contains(
PermissionChecker permissionChecker, BlogsEntry entry,
String actionId)
throws PortalException, SystemException {
return permissionChecker.hasPermission(
entry.getGroupId(), BlogsEntry.class.getName(), entry.getEntryId(),
actionId);
}
}
public static void check(
PermissionChecker permissionChecker, long entryId, String actionId)
throws PortalException, SystemException {
if (!contains(permissionChecker, entryId, actionId)) {
throw new PrincipalException();
}
}
public static void check(
PermissionChecker permissionChecker, BlogsEntry entry,
String actionId)
throws PortalException, SystemException {
if (!contains(permissionChecker, entry, actionId)) {
throw new PrincipalException();
}
}
public static boolean contains(
PermissionChecker permissionChecker, long entryId, String actionId)
throws PortalException, SystemException {
BlogsEntry entry = BlogsEntryLocalServiceUtil.getEntry(entryId);
return contains(permissionChecker, entry, actionId);
}
public static boolean contains(
PermissionChecker permissionChecker, BlogsEntry entry,
String actionId)
throws PortalException, SystemException {
return permissionChecker.hasPermission(
entry.getGroupId(), BlogsEntry.class.getName(), entry.getEntryId(),
actionId);
}
}
Again,  the two check(…) methods are meant to be
 called in your business layer,  while the two contains(…) methods can 
be used in your JSP files. As you  can see, it's very similar to the 
PortletPermission class. The two  notable differences are:
- Instead of having the portletId as one of the parameters, the methods in this custom class take in either an entryId or a BlogsEntry object.
 - None of the methods need to receive the portlet layout ID (plid) as a parameter. (Your custom portlet may choose to use the portlet layout ID if need be.)
 
Let's see how this class is used in the blogs portlet code.
public BlogsEntry getEntry(String entryId) throws PortalException, SystemException {
BlogsEntryPermission.check(
getPermissionChecker(), entryId, ActionKeys.VIEW);
return BlogsEntryLocalServiceUtil.getEntry(entryId);
}
BlogsEntryPermission.check(
getPermissionChecker(), entryId, ActionKeys.VIEW);
return BlogsEntryLocalServiceUtil.getEntry(entryId);
}
In  the BlogsEntryServiceImpl class is a method 
called getEntry(…). Before  this method returns the blogs entry object, 
it calls the custom  permission helper class to check permission. If 
this call doesn't throw  an exception, the entry is retrieved and 
returned to its caller.
<c:if test="<%= BlogsEntryPermission.contains(permissionChecker, entry, ActionKeys.UPDATE) %>">
<portlet:renderURL windowState="<%= WindowState.MAXIMIZED.toString() %>" var="entryURL">
<portlet:param name="struts_action" value="/blogs/edit_entry" />
<portlet:param name="redirect" value="<%= currentURL %>" />
<portlet:param name="entryId" value="<%= entry.getEntryId() %>" />
</portlet:renderURL>
<liferay-ui:icon image="edit" url="<%= entryURL %>" />
</c:if>
<portlet:renderURL windowState="<%= WindowState.MAXIMIZED.toString() %>" var="entryURL">
<portlet:param name="struts_action" value="/blogs/edit_entry" />
<portlet:param name="redirect" value="<%= currentURL %>" />
<portlet:param name="entryId" value="<%= entry.getEntryId() %>" />
</portlet:renderURL>
<liferay-ui:icon image="edit" url="<%= entryURL %>" />
</c:if>
In  the view_entry_content.jsp file,
 the BlogsEntryPermission.contains(…)  method is called to check whether
 or not to show the edit button. That's  all there is to it!
Let's
 review what we've just  covered. Implementing permission into your 
custom portlet consists of  four main steps. First step is to define any
 custom resources and  actions. Next step is to implement code to 
register (or add) any newly  created resources such as a BlogsEntry 
object. The third step is to  provide an interface for the user to 
configure permission. Lastly,  implement code to check permission before
 returning resources or showing  custom features. Two major resources 
are portlets and Java objects.  There is not a lot that needs to be done
 for the portlet resource to  implement the permission system since 
Liferay Portal has a lot of that  work done for you. You mainly focus 
your efforts on any custom Java  objects you've built. You're now well 
on your way to implement security  to your custom Liferay portlets! 
Excellent informative post.. Real Estate In Bhopal
ReplyDeleteFirst of all web developers should be understand the exact requirements and concept of website creation from the consumers.It would help to neglect some technical issues during project time.
ReplyDeleteWeb Designing Companies | Web Design Companies
search the Best Commercial Property For Buy
ReplyDeleteFor other topics on liferay i found this very helpful Liferay Tutorials
ReplyDelete• Nice and good article. It is very useful for me to learn and understand easily. Thanks for sharing your valuable information and time. Please keep updatingAzure Online course Hyderabad
ReplyDeleteThanks for the post, I am techno savvy. I believe you hit the nail right on the head. I am highly impressed with your blog.
ReplyDeleteIt is very nicely explained. Your article adds best knowledge to our Java Online Training from India.
or learn thru Java Online Training from India Students.
A lot of thanks for all of the hard work on this web page. Betty delights in setting aside time for research and it's really easy to see why. My spouse and i learn all of the dynamic way you produce very helpful techniques through your website and attract contribution from other ones about this situation while our daughter is without a doubt starting to learn a great deal. Take advantage of the remaining portion of the new year. You are conducting a stunning job. remote service Virginia
ReplyDeleteThanks for the nice blog. It was very useful for me. I'm happy I found this blog. Thank you for sharing with us,I too always learn something new from your post. spicewood custom pool builder
ReplyDeleteI have read your article, it is very informative and helpful for me.I admire the valuable information you offer in your articles. Thanks for posting it.. spicewood custom pool builder
ReplyDeleteThanks for sharing your informative blog of post.Keep on sharing your ideas.
ReplyDeleteMicrosoft Windows Azure Training | Online Course | Certification in chennai | Microsoft Windows Azure Training | Online Course | Certification in bangalore | Microsoft Windows Azure Training | Online Course | Certification in hyderabad | Microsoft Windows Azure Training | Online Course | Certification in pune