User Interface in Production

Exclusive offer: get 50% off this eBook here
Liferay User Interface Development

Liferay User Interface Development — Save 50%

Develop a powerful and rich user interface with Liferay Portal 6.0

$29.99    $15.00
by Frank Yu Jonas X. Yuan Xinsheng Chen | November 2010 | Open Source

In this article, by Jonas X. Yuan, Xinsheng Chen & Frank Yu, authors of Liferay User Interface Development, we will cover:

  • How to add workflow capabilities on custom assets in plugins
  • Custom attributes in plugins

 

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 http://www.docbook.org/.

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).

Structure

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 namespace-mapping.properties 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" />
</finder>
<!-- ignore details -->
<reference package-path="com.liferay.portal"
entity="WorkflowInstance
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.

<workflow-handler>com.liferay.knowledgebase.admin.workflow.
ArticleWorkflowHandler</workflow-handler>

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 com.liferay.knowledgebase.service.impl.ArticleLocalServiceImpl.java. 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,
WorkflowConstants.STATUS_ANY);
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 com.liferay.knowledgebase.service.impl.ArticleLocalServiceImpl.java, 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:choose>
<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"
/>
</div></c:when>
</c:choose>

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)) %>" />
</c:if>

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.

Liferay User Interface Development Develop a powerful and rich user interface with Liferay Portal 6.0
Published: November 2010
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:
        Read more about this book      

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

Where would you find sample code—Knowledge Base plugin with workflow capabilities?

You can find a WAR file of the Knowledge Base plugin with workflow capabilities from the attached folder /code.

/code/knowledge-base-portlet-6.0.6.1.war

Next, deploy it. You will be able to see portlets available like Knowledge Base Admin, Knowledge Base Aggregator, Knowledge Base Display, and Knowledge Base Search.

You may be interested in the latest version of Knowledge Base plugin with workflow capabilities. Thus you can find the latest code at.

svn://svn.liferay.com/repos/public/plugins/trunk/portlets/knowledge-base-portlet

Custom attributes in plugins

The portal provides a framework to add custom attributes or call custom fields to any Service-Builder generated entities at runtime, where indexed values, text boxes, and selection lists for input and dynamic UI are available. For example, you could add custom fields on any entity like a wiki page, Message Boards category, Message Boards message, Calendar event, page, organization, user, Web Content, Document Library document, Document Library folder, Bookmarks entry, Bookmarks folder, Image Gallery image, Image Gallery folder, Blogs entry, and so on. Note that the custom fields UI displays assets in alphabetical order, instead of a random order.

Adding custom attributes capabilities

You can also add custom fields to custom entities like Knowledge Base Articles in plugins. As shown in the following screenshot, custom attributes are available on Knowledge Base articles. That is, you would be able to add a set of Custom Fields to Knowledge Base articles. Note that all Custom Fields could be indexed and search performance on custom fields will be very good.

As shown in the above screenshot, you can add a custom attribute, for example, Type, on the Knowledge Base Article first. Then you can input or update the value of Type; for instance, when you create a new Knowledge Base Article or update an existing Knowledge Base Article. Of course, you can add many custom attributes on Knowledge Base Articles according to your requirements. This is a nice way to extend your current data model, like Knowledge Base Articles. But how do you make it happen? Refer to the following section for more information.

How to make custom attributes?

In this section, we're going to introduce how to add custom attributes to custom entities in plugins. The entities Knowledge Base Articles will be used as an example. In brief, it should be simple to make it with following steps.

Adding custom attributes as references

First, you have to add custom attributes as references in $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/WEB-INF/service.xml as follows.

<reference package-path="com.liferay.portlet.expando"
entity="ExpandoValue" />

As shown in above code, the reference element allows you to inject services from another service.xml, that is, from portal core, within the same class loader. For example, if you inject the ExpandoValue entity, then you'll be able to reference the Custom Attributes services from your service implementation via the methods getExpandoValueLocalService and getExpandoValueService. You'll also be able to reference the Custom Attributes services via the variables ExpandoValueLocalService and ExpandoValueService.

Then, you need to run ANT target build-service to build service based on newly added custom attributes reference.

Adding custom attributes display

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

<custom-attributes-display>com.liferay.knowledgebase.admin.
ArticleCustomAttributesDisplay</custom-attributes-display>

As you can see, the tag custom-attributes-display value must be a class that implements com.liferay.portlet.expando.model.CustomAttributesDisplay and is called by Custom Fields administration UI.

Then you need to create the class com.liferay.knowledgebase.admin.ArticleCustomAttributesDisplay, which implements com.liferay.portlet.expando.model.CustomAttributesDisplay as follows:

public class ArticleCustomAttributesDisplay extends
BaseCustomAttributesDisplay {
public static final String CLASS_NAME = Article.class.getName();
public String getClassName() { return CLASS_NAME; }
public String getIconPath(ThemeDisplay themeDisplay) {
return themeDisplay.getPathThemeImages() + "/common/pages.png"; }
}

As you can see, ArticleCustomAttributesDisplay extends BaseCustomAttributesDisplay and overrode the methods getClassName and getIconPath. That's simple, isn't it?

Liferay User Interface Development Develop a powerful and rich user interface with Liferay Portal 6.0
Published: November 2010
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:
        Read more about this book      

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

Adding custom attributes capabilities when creating, updating, and indexing custom entities

When creating new entities or updating an existing entity, we do need to update custom attribute consequently. How can you do this? First of all, you could update implementation of the methods addArticle and updateArticle before the line // Asset in com.liferay.knowledgebase.service.impl.ArticleLocalServiceImpl.java. The following is sample code:

// Expando
ExpandoBridge expandoBridge = article.getExpandoBridge();
expandoBridge.setAttributes(serviceContext);

As shown in the above code, ArticleLocalServiceImpl gets custom attributes entity, that is, ExpandoBridge, first. Then it sets attributes based on current service content. Next, it tells the portal that custom attributes of current entity will get updated.

Afterwards when indexing custom entities, custom attributes should get indexed, too. How? You could update implementation of the method doGetDocument in com.liferay.knowledgebase.admin.util.AdminIndexer. The following is sample code:

ExpandoBridge expandoBridge = article.getExpandoBridge();
//ignore details
ExpandoBridgeIndexerUtil.addAttributes(document, expandoBridge);
return document;

Note that the line which gets custom attributes entity, that is, ExpandoBridge, should be added before generating document. In the same way, the line which adds custom attributes into the document before returning the document. By these lines, all custom attributes of current entity will get indexed.

Adding custom attributes UI tags

Last but not least, you need to add custom attributes UI tags in order to take custom attributes as input or to display custom attributes with values for current custom entity, for example, Knowledge Base Article.

To do so, you should add custom attributes UI tags to create or update custom attributes values after creating or updating content at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/edit_article.jsp as follows.

<liferay-ui:custom-attributes-available className="
<%= Article.class.getName() %>">
<liferay-ui:custom-attribute-list
className="<%= Article.class.getName() %>"
classPK="<%= (article != null) ? article.getArticleId() : 0 %>"
editable="<%= true %>"
label="<%= true %>"
/>
</liferay-ui:custom-attributes-available>

Logically you could re-arrange UI forms (title, content, description, and custom attributes) as you expected. For example, you can add above code before or after the line &gtaui:input name="title" /<.

For the same reason, you should add custom attributes UI tags to display custom attributes with their values after displaying content at $PLUGIN_SDK_HOME/knowledge-base-portlet/docroot/admin/view_article.jsp as follows

<liferay-ui:custom-attributes-available className="<%= Article.class.
getName() %>">
<liferay-ui:custom-attribute-list
className="<%= Article.class.getName() %>"
classPK="<%= (article != null) ? article.getArticleId() : 0 %>"
editable="<%= false %>"
label="<%= true %>"
/>
</liferay-ui:custom-attributes-available>

As you can see, the UI tag which is used to display custom attributes and their values is same as that of creating or updating custom attributes values.

Where would you find sample code—Knowledge Base plugin with custom attributes capabilities?

You can simply download WAR of Knowledge Base plugin with custom attribute capabilities from attached code folder:

/code/knowledge-base-portlet-6.0.6.1.war

And then deploy it. That's it.

Summary

In this article we learned:

  • How to add workflow capabilities on custom assets in plugins
  • Custom attributes in plugins

Further resources on this subject:


About the Author :


Frank Yu

Frank has 10 years of extensive experience in Vignette-based and Liferay-based portal design, development, architecture, and project management, particularly in healthcare portal application development. As a project lead and senior Liferay architect, he provides portal design and architecture consulting services and manages multiple onshore and offshore teams to build portal and CMS applications for his clients.

His team leadership and hand-on experience in areas such as portlets, portal themes and skins, the customization of portal frameworks, CMS, architecture, and performance tuning have been proven to be very valuable for his clients. He also has deep knowledge in system integration with multiple legacy systems, all major RDBMS and J2EE application servers. Previously, he worked on different portal products or applications at InterComponentWare, Pay By Touch, and McKesson, a Fortune-14 healthcare company. He holds an M.S. degree in Computer & Information Sciences and was a Ph.D. candidate in cancer research. He received his B.S. degree from Nanjing University, China.

Jonas X. Yuan

Jonas X. Yuan is a Chief Architect of ForgeLife LLC and an expert on Liferay Portal, e-commerce, and Content Management Systems (CMS). As an open source community contributor, he has published five Liferay books from 2008 to 2012. He is also an expert on Liferay integration with Ad Server OpenX, different search engines, enterprise content including videos, audio, images, documents, and web contents, and other technologies, such as BPM Intalio and Business Intelligence Pentaho, LDAP, and SSO. He holds a Ph.D. in Computer Science from the University of Zurich, where he focused on Integrity Control in federated database systems.

He earned his M.S. and B.S. degrees from China, where he conducted research on expert systems for predicting landslides. Previously, he worked as a Project Manager and a Technical Architect in Web GIS (Geographic Information System).
He is experienced in Systems Development Lifecycle (SDLC) and has deep, hands-on skills in J2EE technologies. He developed a BPEL (Business Process Execution Language) engine called BPELPower from scratch at the NASA data center. As the chief architect, Dr. Yuan successfully led and launched several large-scale Liferay/Alfresco e-commerce projects for millions of users each month.

He has worked on the following books: Liferay Portal Enterprise Intranets, 2008; Liferay Portal 5.2 Systems Development, 2009; Liferay Portal 6 Enterprise Intranets, 2010; Liferay User Interface Development, 2010; Liferay Portal Systems Development, 2012.

Xinsheng Chen

Xinsheng Chen is a web application architect. He holds an MS degree in Computer Science from California State University, San Bernardino. His focus was on online banking applications. He also has a Bachelor's degree from Wuhan University, China. Mr. Chen was previously a QA engineer working at VMware, Inc. He later led a team in developing four educational computer games for a Florida school district. Mr. Chen has rich experience in J2EE technologies. He also has extensive experience in Content Management Systems (CMS), including Alfresco. He has worked on 23 Liferay Portal projects. He is also the co-author of Liferay Beginner's Guide and Liferay User Interface Development.

Books From Packt


Liferay Portal 6 Enterprise Intranets
Liferay Portal 6 Enterprise Intranets

Liferay Portal 5.2 Systems Development
Liferay Portal 5.2 Systems Development

Silverlight 4 User Interface Cookbook
Silverlight 4 User Interface Cookbook

jQuery UI 1.7: The User Interface Library for jQuery
jQuery UI 1.7: The User Interface Library for jQuery

Learning the Yahoo! User Interface library
Learning the Yahoo! User Interface library

Asterisk Gateway Interface 1.4 and 1.6 Programming
Asterisk Gateway Interface 1.4 and 1.6 Programming

jQuery UI 1.6: The User Interface Library for jQuery
jQuery UI 1.6: The User Interface Library for jQuery

Yahoo User Interface 2.X Cookbook: RAW
Yahoo User Interface 2.X Cookbook: RAW


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
8
x
t
A
n
V
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software