This article accompanies the dev.life session "Ridiculously simple plugins" hosted today (26. Aug, 16:00 CEST, 14:00 UTC) by me. The session is broadcasted on youtube and recording will be available (and linked here) after the session.
The purpose of this session is to demonstrate that - given the proper architecture - you can extend Portal Applications within minutes. Well - the story is: Your developer estimates an hour (to do it properly), which means that you might want to round up to the next unit, e.g. 1 day - and this includes documentation, deployment, administration etc.
It's most likely harder to get your system administrator to update the production system yet again than to implement new functionality - given a proper architecture.
Quick start if you want to follow along:
Everything you need is available on www.olafkock.de/liferay/rsp/ and if you don't want to read through everything when we start, pick the instructions with the yellow markers below:
During the session we're going to create 3 simple plugins. Two of them are extending a business layer that is generated with XMLPortletFactory. If you'd like, you can download & execute xmlportletfactory yourself with the customer&invoice definition file, but you can also use the shortcut and download this portlet project, unzip it in the portlets directory of your plugins sdk (yes, I'm using Ant, sorry Maveners) and open it in your development environment. For the session I'll use Liferay Developer Studio, but you're free to use whatever you'd like.
What does this project do? It's just what xmlportletfactory generates from the customer.xml script. Actually, I've cheated. It also contains a custom portlet as well that will provide some random data for you. However, it doesn't compile: Consider it to be just the xmlportletfactory output. To make it usable, you'll need to run Liferay's ServiceBuilder.
We'll explore the resulting code during this dev.life session. In short: Add all portlets from the new "Customer" section to a page, create a few customers and invoices and click the icon left of a customer to see the invoices updated.
If you examine the default xmlportletfactory-generated UI, it's not too obvious, which customer is currently selected. You can see it when the icon in a customer's row changes from a square to an arrow. Let's make the current customer more visible by hooking into the already established mechanism of Inter Portlet Communication. The first portlet we create is a CustomerDetailPortlet, showing the name and location of a customer. If we had more business data, we'd probably show more data in the details. (Solution to be linked after the session)
For the next portlet, assume you're using this system, with thousands of customers in the database. Whenever somebody calls, you'll have to search for them again. But when they're calling, they typically call multiple times, delivering more details for their issues. That's why we want to keep track of the latest 5 callers and we'll create a MostRecentlyUsedCustomerPortlet (MRU): This will make it easy to just click on their name, rather than searching for the record again. (Solution to be linked after the session)
What does this teach us? In a portlet environment you can easily compose your application from many different building blocks. If you introduce yet another portlet that interacts with the existing ones, it doesn't need to be big to add value. And it doesn't need to be high-risk to update the site: If your new portlet has a bug - just remove it again. The others will still continue to work, unaffected.
Here's the screenshot of what can be achieved within minutes: (Customer and Invoices Portlets are what xmlportletfactory generated)
Customizing Core Portlets vs. Adding ridiculously Simple Portlets
Time permitting, we'll have one more plugin that demonstrates how to simplify Liferay's UI through a ridiculously simple portlet. If you add WebContent, you'll find that the UI for adding a single article has quite a complex UI. You can translate, tag, expire, categorize your content, provide abstracts etc.
What if your authors are untrained, infrequent users of Liferay? Do you want to train them on the generic UI? They'll probably be annoyed because it's so complex and they don't need all of the features. So why not simplify the UI?
In the forums, this typically comes along as "How do I change the WebContent Editor (or other plugins) to use my defaults?". I'd like to suggest a different approach: Create your own, ridiculously simple plugin. It doesn't mess with Liferay's portlets, is easy to maintain and quick to write. And if the API that you use changes in the next version, you can easily identify the spot to upgrade. In fact, that's exactly what I did - I stole some code from James' 7cogs article and made it work on Liferay 6.2 because the API changed slightly.
So, we're creating a SimplifiedArticlePortlet, which takes an article's title, as well as english and german text through a really simple UI. Point your inexperienced authors to this portlet to add their new articles and you'll be able to take them from there (and you can edit them with the full-featured WebContent editor). Here's a screenshot of the result:
If you follow along (e.g. develop the portlets) during the session, this one is a bit harder to follow - after all it involves an API call with 39 parameters. That's why I've prepared the portlet for you to copy/paste portions as you like: http://www.olafkock.de/liferay/rsp/SimplifiedArticlePortlet.java and http://www.olafkock.de/liferay/rsp/SimplifiedArticlePortlet-view.jsp
Given your own applications: Consider to make the best out of the portal environment and compose your big application from many small building blocks. The reward is an easy maintenance of each single component and easy extension of the whole system.
Liferay's API is easy to use (even given occasional 39-parameter methods) and sometimes it's a great option to just hardcode your own logic to a ridiculously simple plugin than to extend and tweak one of Liferay's very generic out-of-the-box portlets. There's a place for generic features, just as there's a place for specialized, narror, behaviour. Choose what makes sense to you and don't fear to write throwaway code: If it's well compartmented (e.g. in a single plugin) there's nothing bad in it.
During the broadcast I didn't finish the MRUCustomerPortlet - here's what needs to be done. The code changes are marked in the solution download that will come up soon - portlet.xml is just updated as required, not marked:
- Decorate the <li> content on view.jsp with a hyperlink that executes an action
- Create an action handler in the portlet class, triggering the customerId event
- Declare that our MRUCustomer portlet does also publish this event in portlet.xml
- Declare that xmlportletfactory's CustomerPortlet now also processes this event in portlet.xml
- Implement the eventhandler in CustomerPortlet to highlight the selected row.
And you're done. The full "solution" is now uploaded to customer-portlet-solution.zip.
Note that I do not consider the solution code (or the code presented in the presentation) "good style": When I refer to a "ridiculously simple" plugin, I am stating 1 hour of effort. With the plugins presented here, I took slightly more than 1 hour for 3 plugins. Naturally this means I'll need a few shortcuts that shouldn't actually go into production code. But you get the point.