User Interface in Production

9 min read


Liferay User Interface Development

Liferay User Interface Development

Develop a powerful and rich user interface with Liferay Portal 6.0

  • Design usable and great-looking user interfaces for Liferay portals
  • Get familiar with major theme development tools to help you create a striking new look for your Liferay portal
  • Learn the techniques and tools to help you improve the look and feel of any Liferay portal
  • A practical guide with lots of sample code included from real Liferay Portal Projects free for use for developing your own projects
        Read more about this book      

(For more resources on this subject, see here.)

This section will introduce how to add workflow capabilities to any custom assets in plugins. Knowledge Base articles will be used as an example of custom assets. In brief, the Knowledge Base plugin enables companies to consolidate and manage the most accurate information in one place. For example, a user manual is always updated; users are able to rate, to add workflow and to provide feedback on these Knowledge Base articles.

Preparing a plugin—Knowledge Base

First of all, let’s prepare a plugin with workflow capabilities, called Knowledge Base. Note that the plugin Knowledge Base here is used as an example only. You can have your own plugin as well.

What’s Knowledge Base?

The plugin Knowledge Base allows authoring articles and organize them in a hierarchy of navigable categories. It leverages Web Content articles, structures, and templates; allows rating on articles; allows commenting on articles; allows adding hierarchy of categories; allows adding tags to articles; exports articles to PDF and other formats; supports workflow; allows adding custom attributes (called custom fields); supports indexing and advanced search; allows using the rule engine and so on.

Most importantly the plugin Knowledge Base supports import of a semantic markup language for technical documentation called DocBook. DocBook enables its users to create document content in a presentation-neutral form that captures the logical structure of the content; that content can then be published in a variety of formats, such as HTML, XHTML, EPUB, and PDF, without requiring users to make any changes to the source. Refer to

In general, the plugin Knowledge Base provides four portlets inside: Knowledge Base Admin (managing knowledge base articles and templates), Knowledge Base Aggregator (publishing knowledge base articles), Knowledge Base Display (displaying knowledge base articles) and Knowledge Base Search (the ability to search knowledge base articles).


The plugin Knowledge Base has following folder structure under the folder $PLUGIN_SDK_HOME/knowledge-base-portlet.

  • admin: View JSP files for portlet Admin
  • aggregator: View JSP files for portlet Aggregator
  • display: View JSP files for portlet Display
  • icons: Icon images files
  • js: JavaScript files
  • META-INF: Contains context.xml
  • search: View JSP files for portlet Search
  • WEB-INF: Web info specification; includes subfolders classes, client, lib, service, SQL, src, and tld

As you can see, JSP files such as init.jsp and css_init.jsp are located in the folder $PLUGIN_SDK_HOME/knowledge-base-portlet.

Services and models

As you may have noticed, the plugin Knowledge Base has specified services and models with the package named com.liferay.knowledgebase. You would be able to find details at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml. Service-Builder in Plugins SDK will automatically generate services and models against service.xml, plus XML files such as portlet-hbm.xml, portlet-model-hints.xml, portlet-orm.xml, portlet-spring.xml, base-spring.xml, cluster-spring.xml,dynamic-data-source-spring.xml, hibernate-spring.xml, infrastructure-spring.xml, messaging-spring.xml, and shard-data-source-spring.xml under the folder $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/META-INF.

The service.xml specified Knowledge Base articles as entries: Article, Comment, and Template. The entry Article included columns: article Id as primary key, resource Prim Key, group Id, company Id, user Id, user Name, create Date, modified Date, parent resource Prim Key, version, title, content, description, and priority; the entry Template included columns: template Id as primary key, group Id, company Id, user Id, user Name, create Date, modified Date, title, content, and description; while the entity Comment included columns: comment Id as primary key, group Id, company Id, user Id, user Name, create Date, modified Date, class Name Id, class PK, content and helpful. As you can see, the entity Comment could be applied on either any core assets or custom assets like Article and Template by using class Name Id and class PK.

By the way, the custom SQL scripts were provided at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/custom-sql/default.xml. In addition, resource actions, that is, permission actions specification—are provided at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/src/resource-actions/default.xml.

Of course, you can use Ant target build-wsdd to generate WSDD server configuration file $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/server-config.wsdd and to use Ant target build-client plus to generate web service client JAR file like $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/client/known-base-portlet-client.jar. In brief, based on your own custom models and services specified in service.xml, you can easily build service, WSDD, and web service client in plugins of Liferay 6 or above version.

Adding workflow instance link

First, you have to add a workflow instance link and its related columns and finder in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml as follows.

<column name="status" type="int" />
<column name="statusByUserId" type="long" />
<column name="statusByUserName" type="String" />
<column name="statusDate" type="Date" />
<!-- ignore details -->
<finder name="R_S" return-type="Collection">
<finder-column name="resourcePrimKey" />
<finder-column name="status" />
<!-- ignore details -->
<reference package-path="com.liferay.portal"
Link" />

As shown in the above code, the column element represents a column in the database, four columns like status, statusByUserId, statusByUserName, and statusDate are required for Knowledge Base workflow, storing workflow related status, and user info; the finder element represents a generated finder method, the method finder R_S is defined as Collection (an option) for return type with two columns, for example, resourcePrimkey and status; where the reference element allows you to inject services from another service.xml within the same class loader. For example, if you inject the Resource (that is, WorkflowInstanceLink) entity, then you’ll be able to reference the Resource services from your service implementation via the methods getResourceLocalService and getResourceService. You’ll also be able to reference the Resource services via the variables resourceLocalService and resourceService.

Then, you need to run ANT target build-service to rebuild service based on newly added workflow instance link.

Adding workflow handler

Liferay 6 provides pluggable workflow implementations, where developers can register their own workflow handler implementation for any entity they build. It will appear automatically in the workflow admin portlet so users can associate workflow entities with available permissions. To make it happen, we need to add the Workflow Handler in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/liferay-portlet.xml of plugin as follows.


As shown in the above code, the workflow-handler value must be a class that implements com.liferay.portal.kernel.workflow.BaseWorkflowHandler and is called when the workflow is run.

Of course, you need to specify ArticleWorkflowHandler under the package com.liferay.knowledgebase.admin.workflow. The following is an example code snippet.

public class ArticleWorkflowHandler extends BaseWorkflowHandler {
public String getClassName(){/* get target class name */};
public String getType(Locale locale) {/* get target entity type,
that is, Knowledge base article*/};
public Article updateStatus( int status, Map<String, Serializable>
workflowContext) throws PortalException, SystemException
{/* update workflow status*/};
protected String getIconPath(ThemeDisplay themeDisplay)
{/* find icon
path */
return ArticleLocalServiceUtil.updateStatus(userId, resourcePrimKey,
status, serviceContext); };

As you can see, ArticleWorkflowHandler extends BaseWorkflowHandler and overrode the methods getClassName, getType, updateStatus, and getIconPath. That’s it.

Updating workflow status

As mentioned in the previous section, you added the method updateStatus in ArticleWorkflowHandler. Now you should provide implementation of the method updateStatus in The following is some example sample code:

public Article updateStatus(long userId, long resourcePrimKey,
int status, ServiceContext serviceContext) throws PortalException,
SystemException {
/* ignore details */
// Article
Article article = getLatestArticle(resourcePrimKey,
articlePersistence.update(article, false);
if (status != WorkflowConstants.STATUS_APPROVED)
{ return article; }
// Articles
// Asset
// Social
// Indexer
// Attachments
// Subscriptions

As shown in above code, it first gets latest article by resourcePrimKey and WorkflowConstants.STATUS_ANY. Then, it updates the article based on the workflow status. And moreover, it updates articles display order, asset tags and categories, social activities, indexer, attachments, subscriptions, and so on.

After adding new method at, you need to run ANT target build-service to build services.

Adding workflow-related UI tags

Now it is time to add workflow related UI tags (AUI tags are used as an example) at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp. First of all, add the AUI input workflow action with value WorkflowConstants.ACTION_SAVE_DRAFT as follows.

<aui:input name="workflowAction" type="hidden" value="
<%= WorkflowConstants.ACTION_SAVE_DRAFT %>" />

As shown in above code, the default value of AUI input workflowAction was set as SAVE DRAFT with type hidden. That is, this AUI input is invisible to end users.

Afterwards, it would be better to add workflow messages by UI tag liferay-ui:message, like a-new-version-will-be-created-automatically-if-this-content-is-modified for WorkflowConstants.STATUS_APPROVED, and there-is-a-publication-workflow-in-process for WorkflowConstants.STATUS_PENDING.

<% int status = BeanParamUtil.getInteger(article, request, "status",
WorkflowConstants.STATUS_DRAFT); %>
<c:when test="<%= status == WorkflowConstants.STATUS_APPROVED %>">
<div class="portlet-msg-info">
<liferay-ui:message key="a-new-version-will-be-created-
automatically-if-this-content-is-modified" />
</div> </c:when>
<c:when test="<%= status == WorkflowConstants.STATUS_PENDING %>">
<div class="portlet-msg-info">
<liferay-ui:message key="there-is-a-publication-workflow-in-process"

And then add AUI workflow status tag aui:workflow-status at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp.

<c:if test="<%= article != null %>">
<aui:workflow-status id="<%= String.valueOf(resourcePrimKey) %>"
status="<%= status %>" version="<%= GetterUtil.getDouble(String.
valueOf(version)) %>" />

As you can see, aui:workflow-status is used to represent workflow status. Similarly you can find other AUI tags like a button, button_row, column, field_wrapper, fieldset, form, input, layout, legend, option, panel, script, and select.

Finally you should add the JavaScript to implement the function publishArticle() as follows.

function <portlet:namespace />publishArticle() {
document.<portlet:namespace />fm.<portlet:namespace
/>workflowAction.value = "<%= WorkflowConstants.ACTION_PUBLISH %>";
<portlet:namespace />updateArticle();

As you can see, the workflow action value is set as WorkflowConstants.ACTION_PUBLISH. You have added workflow capabilities on Knowledge Base articles in plugins. From now on, you will be able to apply workflow on Knowledge Base articles through Control Panel.


Please enter your comment!
Please enter your name here