Suppose that you, a portlet developer, need to develop a FAQ portlet that displays questions and answers and that allows certain users to create/update/delete FAQ entries, i.e., a simple CRUD application. Usually, the first thing that comes in mind is to implement a new Java-based portlet, actually, 2 portlets, one for displaying and a second for managing FAQ entries. Fortunately, Ray Augé showed me a different approach, there are some simple cases that can be solved only by using our Web Content framework, this way, each FAQ entry becomes a Web Content entry and for displaying them you can just create a Web Content Template containing a Velocity script.
The ability to create Velocity scripts has been in the portal for a long time but we made some enhancements for 5.3 that will make it easier to build such scripts. Note that some APIs used in this blog post are still in development and will be available only in 5.3. You can download all templates and structures used in this example here.
Portlet example built with Liferay WCM
Here's a screenshot of this portlet in action:
Each pair of question and answers are Web Content entries, and the template responsible for listing them is located at /templates/FAQ-PORTLET.vm in the zip file.
There are many advantages of building CRUD applications with Liferay WCM, as a developer you don't need to care implementing many features provided by Liferay WCM for free, such as:
1. Creation, update and deletion of FAQ entries: since each FAQ entry is actually a Web Content entry, you can manage them from the Web Content portlet:
To edit an entry, you just need to fill the form, notice the category select box, FAQ-PORTLET.vm will filter entries accordingly:
FAQ entries could have other complex field types, such as images, files or any type available in Structures.
2. Versioning: you can have several versions of the same FAQ entry, you can see the history of changes and rollback to older versions if needed, just like any Web Content.
3. Approval workflow: content of each entry can be revised and approved by editors, FAQ entries will be displayed only when they are approved.
4. Tagging: you can aggregate FAQ entries with Asset Publisher portlet.
5. Export/import: you can backup or share FAQ entries with others by exporting and importing them to .lar files.
6. Staging and remote publishing: you can create FAQ entries in the staging community and publish them to the live community when they are ready, they can be also published to a remote Liferay instance.
7. Permissioning: you can define which FAQ entries an user will have permission to view.
7. Setup: Since the portlet that displays all FAQ entries is a Web Content itself with an associated Structure, you can take advantage of this to configure your portlet, in this example, there is a "show_index" option that will display or hide the questions index:
What's new in 5.3?
You might be thinking "OK, there is nothing new here, I know how to create Velocity templates and call Liferay services from them, what's new in 5.3?"
One of the problems we've found while creating these applications is that we can't query for Web Content fields separately. In the example, I needed to filter FAQ entries by their category field, however Web Contents are stored in the database like that:
<?xml version="1.0" encoding="UTF-8"?>
<dynamic-element instance-id="uwYU33xF" name="question" type="text" index-type="text">
<dynamic-content><![CDATA[What is Liferay Portal EE?]]></dynamic-content>
<dynamic-element instance-id="rsTKdp5r" name="answer" type="text_area" index-type="text">
<dynamic-content><![CDATA[<p>Liferay Portal Enterprise...</p>]]></dynamic-content>
<dynamic-element instance-id="q7HOfdUk" name="category" type="list" index-type="keyword">
As you can see, it would be hard to make a database query and fetch all FAQ entries associated to the "EE Edition" category, the table is not normalized. We fixed that by indexing Web Content fields separately in Lucene, now you have new options while creating a new Structure, you can define that a field will be indexed as a Keyword or Text by Lucene or won't be indexed at all:
In FAQ-PORTLET.vm we filter FAQ entries by the selected category:
#set ($clauses = )
#set ($clause = $booleanClauseFactoryUtil.create("category", $selectedCategory, "MUST"))
#set ($void = $clauses.add($clause))
#set ($articleHits = $journalArticleService.search($companyId, ... $clauses, ...))
Advantages of creating CRUD applications with Liferay WCM
- Faster coding, no need to deploy .wars, you can dynamically edit and save your velocity script, you'll see your changes right away.
- Small footprint, it's not a regular portlet with tons of jars consuming memory, it will take longer processing the script but this can be avoided by caching entries.
- You get all Liferay WCM features for free as I mentioned above, you just need to code a velocity script for displaying entries.
- Velocity scripts are harder to debug.
- You can't instantiate Java objects, creation of objects can only be made by calling factories and static methods.
- If your application has many views or many actions can be performed, your script will become very big, making it harder to maintain. You can't add business logic, there is no data validation.
There are many other useful applications that can be built with Liferay WCM, one that I can think of is Jobs Listing app, we'd like to hear from you which other apps could be useful.
Templates can be easily shared, we are planning to create a new type of plugin, something like a "Webscript" plugin type, a bundle would be basically a .lar file containing templates and structures that we could publish through our plugin installer portlet.