13 min read

Each site is represented as a community and each community is made up of a lot of pages, for example, public pages and private pages. In order to build web sites, we need to manage communities and, further, manage pages for each community. The Communities portlet provides the ability to create and manage communities and their users, as well as of the Manage Pages portlet.

Extending Communities portlet

The Communities portlet provides the ability to create and manage communities and their users. A community is a special group holding a number of users who share common interests. By default, a community is represented by the Group_ table with fields such as groupId, companyId, creatorUserId, name, description, type, typeSettings, friendlyURL, active, and so on. Now let’s take an in-depth look at the customization of the community.

As shown in the following screenshot, we may want to add one searchable field for each community, which is Keywords. For example, suppose we are creating a new community with the name Book Street, and the description a community for website www.bookpubstreet.com. Now we have a chance to add the new Keywords field with the value, for example, Book; Street; Palm Tree; Publication. Similarly, when editing the properties of a community—for example Name, Description, Type, and Active—we again have a chance to edit Keywords.

Liferay Portal 5.2 Systems Development

In addition, we expect to have more fields in the customized communities: Created (when the community was created), ModifierUserId (who modified the community), and Modified (when the community was modified).

Liferay Portal 5.2 Systems Development

As shown in the preceding screenshot, when listing communities, not only should the default fields (for example, Name, Type, Members, Online Now, Active, Pending Requests) and Actions icons (for example, Edit, Permissions, Manage Pages, Assign User Roles, Assign Members, Leave, and Delete) be displayed, but also the customized columns (for example, the username and Keywords) should be displayed.

How do we implement these features? In this article, we’re going to show how to customize the Communities portlet using the above requirements as examples. Obviously, it is open for you to customize this portlet in a number of ways according to your own requirements. In general, the processes for customization of this portlet should be the same.

Building Ext Communities portlet

The Communities portlet can be used to create and manage new portal communities and their users. As you can see, a community can be regarded as a separate portal instance; each community gets its own set of pages, content management system, shared calendar, and default permissions. Moreover, a user belonging to multiple communities can navigate among them within the same portal session.

Generally speaking, we do not want to update the Communities portlet, but keep it as it is. Our goal is to customize and extend it. In general, this can be done by using the following two steps:

  1. Build a customized Ext Communities portlet, which has exactly the same functions, look, and feel as that of the original Communities portlet.
  2. Extend this customized portlet and let it have an additional model and service, and moreover, its own look and feel.

In this part, let’s build the Ext Communities portlet, having exactly same functions, look, and feel as that of the Communities portlet.

Constructing the portlet

Now let’s define a Struts portlet with the name “Ext Communities”. We first need to configure it in both portlet-ext.xml and liferay-portlet-ext.xml, and then set the title in Language-ext.properties, and then add the Ext Communities portlet to the Book category in liferay-display.xml.

    1. Locate the portlet-ext.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it.
    2. Add the following lines between </portlet> and </portlet-app> and save the file:
<portlet>
 <portlet-name>extCommunities</portlet-name>
 <display-name>Ext Communities</display-name>
 <portlet-class>com.liferay.portlet.StrutsPortlet</portlet-class>
 <init-param><name>view-action</name>
 <value>/ext/communities/view</value></init-param>
 <expiration-cache>0</expiration-cache>
 <supports><mime-type>text/html</mime-type></supports>
 <resource-bundle>
 com.liferay.portlet.StrutsResourceBundle
 </resource-bundle>
 <security-role-ref>
 <role-name>power-user</role-name>
 </security-role-ref>
 <security-role-ref>
 <role-name>user</role-name>
 </security-role-ref>
</portlet>

As shown in the code above, the portlet-name element contains the canonical name of the portlet (for example, extCommunities). The display-name element contains a short name that is intended to be displayed in the portal (for example, Ext Communities). The portlet-class element contains the fully qualified class name of the portlet (for example, com.liferay.portlet.StrutsPortlet). The init-param element contains a name-value pair, for example view-action-ext/communities/view, as an initialization parameter of the portlet. Further, the expiration-cache defines expiration-based caching for this portlet. The supports element contains the supported MIME-type. The resource-bundle element contains a resource bundle class, for example com.liferay.portlet. StrutsResourceBundle. Finally, the security-role-ref element contains the declaration of a security role reference in the code of the web application.

Secondly, let’s register the extCommunities portlet in liferay-portlet-ext.xml as follows:

    1. Locate the liferay-portlet-ext.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it.
    2. Add the following lines immediately after <!– Custom Portlets –> and save it:
<portlet>
 <portlet-name>extCommunities</portlet-name>
 <struts-path>ext/communities</struts-path>
 <use-default-template>false</use-default-template>
 <restore-current-view>false</restore-current-view>
</portlet>

As shown in the code above, the Ext Communities portlet is registered in the portal. The portal will check struts-path to see whether a user has the required permissions to access the portlet or not. As you can see, struts-path has the value ext/communities. It means that all requests to the ext/communities/* path are considered a part of this portlet scope. Only those users whose request paths match ext/communities/* will be granted access.

Moreover, the use-default-template element has the value false, so the portlet will not use any user’s default template. The restore-current-view element has the value false so the portlet will reset the current view when toggling between maximized and normal states.

Thirdly, add a title (for example, Ext Communities), for the Ext Communities portlet at Language-ext.properties as follows:

    1. Locate the Language-ext.properties file in the /ext/ext-impl/src/content folder and open it.
    2. Add the following line after javax.portlet.title.book_reports=Reports for Books and save it:
javax.portlet.title.extCommunities=Ext Communities

The code above provides mapping for the title of the portlet. If the mapping is not provided, the portal will show the default title javax.portlet.title.extCommunities.

Finally, add the Ext Communities portlet to the Book category in liferay-display.xml as follows:

    1. Locate the liferay-display.xml file in the /ext/ext-web/docroot/WEBINF folder and open it.
    2. Add the following line immediately after the line <portlet id=”book_reports” /> and save it:
<portlet id="extCommunities" />

As shown in the code above, it adds the Ext Communities portlet to the category Book. From now on, you are able to select this portlet from the Book category directly when adding portlets to pages.

Setting up actions

Now, let’s set up all actions required for the Ext Communities portlet. We need to prepare an action class, for example, ExtEditGroupAction. So how do we build this action? You can build the actions from scratch, but our purpose is to customize and extend the Communities portlet. In one word, we expect to reuse the out of the box portlet source code as much as possible and to write minimum code.

As mentioned earlier, we have the portal project for the portal source code in the Eclipse IDE, which is referred to as the /portal prefix. We also have the ext project for customized code, which is referred to as the /ext prefix. The following is a process flow to build the ExtEditGroupAction action class of the Ext Communities portlet.

    1. Create a com.ext.portlet.communities.action package in the /ext/ext-impl/src folder.
    2. Create an ExtEditGroupAction class in this package and open it.
    3. Add the following lines and save it:
public class ExtEditGroupAction extends EditGroupAction {
 public void processAction( ActionMapping mapping, ActionForm 
 form, PortletConfig portletConfig,
 ActionRequest actionRequest, ActionResponse actionResponse) 
 throws Exception {
 String cmd = ParamUtil.getString(actionRequest,
 Constants.CMD);
 try { 
 if (cmd.equals(Constants.ADD) || 
 cmd.equals(Constants.UPDATE)) {
 updateGroup(actionRequest); 
 }
 else if (cmd.equals(Constants.DELETE)) {
 deleteGroup(actionRequest); 
 }
 sendRedirect(actionRequest, actionResponse); 
 }
 catch (Exception e) {
 if (e instanceof NoSuchGroupException ||
 e instanceof PrincipalException) {
 SessionErrors.add(actionRequest, e.getClass().getName());
 setForward(actionRequest, "portlet.ext.communities.error");
 }
 else if (e instanceof DuplicateGroupException ||
 e instanceof GroupFriendlyURLException ||
 e instanceof GroupNameException ||
 e instanceof RequiredGroupException) {
 SessionErrors.add(actionRequest, e.getClass().getName(), e);
 if (cmd.equals(Constants.DELETE)) {
 actionResponse.sendRedirect(
 ParamUtil.getString(actionRequest, "redirect")); 
 }
 } else { throw e;} 
 } 
 }
 public ActionForward render(ActionMapping mapping, ActionForm 
 form, PortletConfig portlonfig,
 RenderRequest renderRequest, RenderResponse renderResponse) 
 throws Exception {
 try { ActionUtil.getGroup(renderRequest); }
 catch (Exception e) {
 if (e instanceof NoSuchGroupException ||
 e instanceof PrincipalException) {
 SessionErrors.add(renderRequest, 
 e.getClass().getName());
 return mapping.findForward
 ("portlet.ext.communities.error");
 } 
 else {throw e;} 
 }
 return mapping.findForward(getForward(renderRequest, 
 "portlet.ext.communities.edit_community")); 
 }
}

As shown in the code above, ExtEditGroupAction extends EditGroupAction from the com.liferay.portlet.communities.action package in the /portal/portal-impl/src folder. It overrides two methods (render and processAction) of EditGroupAction.

Setting up page flow and page layout

We have set up the action. We have also updated the forward path as the portlet.ext.communities.* value. In order to get the page flow working, we need to set up an action path and a page flow.

First, let’s set up the action path and page flow in struts-config.xml as follows:

    1. Locate the struts-config.xml file in the /ext/ext-web/docroot/WEB-INF folder and open it.
    2. Add the following lines after <struts-config> <action-mappings> and save it:
<!-- Ext Communities -->
<action path="/ext/communities/edit_community" 
 type="com.ext.portlet.communities.action.
 ExtEditGroupAction">
 <forward name="portlet.ext.communities.edit_community" 
 path="portlet.ext.communities.edit_community" />
 <forward name="portlet.ext.communities.error" 
 path="portlet.ext.communities.error" />
</action>
<action path="/ext/communities/view" 
 forward="portlet.ext.communities.view" />

The code above defines a set of action paths associated with the action and forward paths, as well as those mentioned earlier. For example, the action path /ext/communities/edit_community is associated with the com.ext.portlet.communities.action.ExtEditGroupAction action and the forward path names portlet.ext.communities.edit_community and portlet.ext.communities.error.

Then based on the page flow and JSP files, let’s define the page layout in tiles-defs.xml:

  1. Locate the tiles-defs.xml file in the ext/ext-web/docroot/WEB-INF folder and open it.
  2. Add the following lines after <struts-config> <action-mappings> and save it:
    <!-- Ext Communities -->
    <action path="/ext/communities/edit_community"
     type="com.ext.portlet.communities.action.
     ExtEditGroupAction">
    <forward name="portlet.ext.communities.edit_community"
     path="portlet.ext.communities.edit_community" />
    <forward name="portlet.ext.communities.error"
     path="portlet.ext.communities.error" />
    </action>
    <action path="/ext/communities/view"
     forward="portlet.ext.communities.view" />

The code above defines a set of action paths associated with the action and forward paths, as well as those mentioned earlier. For example, the action path /ext/communities/edit_community is associated with the com.ext.portlet.communities.action.ExtEditGroupAction action and the forward path names portlet.ext.communities.edit_community and portlet.ext.communities.error.

Then based on the page flow and JSP files, let’s define the page layout in tiles-defs.xml:

  1. Locate the tiles-defs.xml file in the ext/ext-web/docroot/WEB-INF folder and open it.
  2. Add the following lines after <tiles-definitions> and save it:
    <!-- Ext Communities -->
    <definition name="portlet.ext.communities" extends="portlet" />
    <definition name="portlet.ext.communities.edit_community" 
     extends="portlet.ext.communities">
     <put name="portlet_content" 
     value="/portlet/ext/communities/edit_community.jsp" />
    </definition>
    <definition name="portlet.ext.communities.view" extends="portlet">
     <put name="portlet_content" 
     value="/portlet/ext/communities/view.jsp" />
    </definition>
    <definition name="portlet.ext.communities.error" 
     extends="portlet">
     <put name="portlet_content" 
     value="/portlet/communities/error.jsp" />
    </definition>

The code above defines the page layout for the Ext Communities portlet. For example, portlet.ext.communities.edit_community is associated with the JSP file /portlet/ext/communities/edit_community.jsp. In addition, it specifies that the community view page layout (for example, portlet.ext.communities.view) is associated with the JSP page file /portlet/ext/communities/view.jsp.

Preparing JSP files

We have now set up the actions. We have also set up page flow and page layout. Now let’s set up the JSP files that are required for the Ext Communities portlet. We need to prepare JSP files such as view.jsp, edit_community.jsp, group_search.jsp, and so on. So how do we build this? You can build them from scratch. However, here we will copy and modify JSP files of the Communities portlet. In this section we expect to reuse the source code, including JSP files, as much as possible.

First, let’s create the view.jsp JSP file as follows:

  1. Create a communities folder within the /ext/ext-web/docroot/html/portlet/ext/ folder.
  2. Locate the view.jsp JSP file in the /portal/portal-web/docroot/html/portlet/communities folder, and copy it to the /ext/ext-web/docroot/html/portlet/ext/communities folder.
  3. Open view.jsp in the /ext/ext-web/docroot/html/portlet/ext/communities folder, update /communities/edit_community with /ext/communities/edit_community as shown in the following two lines, and save it:
    portletURL.setParameter("struts_action", "/ext/communities/view");
    <liferay-ui:search-form 
     page="/html/portlet/ext/communities/group_search.jsp" 
     searchContainer="<%= searchContainer %>" 
     showAddButton="<%= showTabs1 %>" />

Next, we need to create the JSP file edit_community.jsp as follows:

  1. Locate the JSP file edit_community.jsp in the /portal/portal-web/docroot/html/portlet/communities folder, and copy it to the /ext/extweb/docroot/html/portlet/ext/communities folder.
  2. Open edit_community.jsp in the /ext/ext-web/docroot/html/portlet/ext/communities folder, update /communities/edit_community with /ext/communities/edit_community as shown in following line, and save it:
    <form action="<portlet:actionURL 
     windowState="<%= WindowState.MAXIMIZED.
     toString() %>">
     <portlet:param name="struts_action" 
     value="/ext/communities/edit_community" />
     </portlet:actionURL>" 
     method="post" name="<portlet:namespace />fm" 
     onSubmit="<portlet:namespace />saveGroup(); return false;">

In addition, we need to make the button Add Community available, in the following manner:

  1. Locate JSP file group_search.jsp in the /portal/portal-web/docroot/html/portlet/enterprise_admin folder.
  2. Copy the JSP file group_search.jsp from /portal/portal-web/docroot/html/portlet/enterprise_admin to /ext/ext-web/docroot/html/portlet/ext/communities, and open it.
  3. Update /communities/edit_community with /ext/communities/edit_community as shown in the following lines, and save it:
    submitForm(document.<portlet:namespace />fm, '<portlet:renderURL 
     windowState="<%= WindowState.MAXIMIZED.toString() %>">
    <portlet:param name="struts_action" 
     value="/ext/communities/edit_community" />
    <portlet:param name="redirect" 
     value="<%= currentURL %>" />
    </portlet:renderURL>');

Congratulations! You have cloned the Communities portlet. Finally, we can deploy updates into Tomcat as follows:

  1. Stop Tomcat if it is running.
  2. Click on the Ant target: deploy at the Ant view ext.
  3. Start Tomcat.
  4. Open up a new browser with the URL http://localhost:8080.
  5. Click on Sign in and enter [email protected] / test.
  6. Click on Add Application | Book

LEAVE A REPLY

Please enter your comment!
Please enter your name here