The right tool for the job? Chapter 2: Customizing a Core Portlet

Liferay comes with so many features that it's hard to judge when a feature is a good solution for a given problem. I'd like to shine some light onto some of these features and common misconceptions about them because it's easy to abuse them for purposes for which they're not well suited - despite making the impression they might.
CC BY-ND 2.0 by S. Benno

This chapter is about modifications that are commonly done to Liferay's out-of-the-box portlets.

It's easy to modify the OOTB-portlets: For the UI side you can introduce JSP hooks. On the action-handling side, you can override Struts-Actions (for example). You can go even further and fiddle with request parameters (e.g. in servlet filters), but let's keep it at the first two options for now.

Why does Liferay's Portlet not do what I want?

Liferay (the portal) is a platform that must be everything to everybody. As a platform vendor, Liferay (the company) must implement Liferay (the portal) with as broad applicability as possible. You (the implementor of a specific portal) on the other hand typically need to focus on one very specific problem: Your portal. You don't need all this flexibility and configurability beyond your own usecases. You're just interested in implementing your own requirements.

Consequently, some of Liferay's implementations might be overly generic for you. You can be happy that they are, because that means that there's a very good chance that there's an overlap with your requirements. And if it isn't big enough an overlap, you can still customize Liferay's portlets and UI to match your requirements. Knowing that you can change the UI with "just a simple JSP hook" is tempting. If all you need is a simple change to a simple UI, go for it. The more complex either your change or the changed Liferay component is, the more you should refrain from such a quick fix.

What to do when OOTB is not enough?

So what - you need a change to a complex UI. There are JSP-Hooks and Struts Action overloads. They might do what you want, and are readily available, quickly done. Are they always the tools that you should use? Well...

There are two aspects that you should keep in mind when thinking about JSP hooks and changing Liferay's OOTB-portlets in general: Maintainability of your changes and the fact that customizations are global to the whole portal. Any customization that you're doing to a portlet will be available everywhere (I'm ignoring Application Adapters here, but you'll get the point).

The elephant in the room is Maintainability. If you're looking at Liferay's JSPs, most of them - especially the more flexible, configurable ones - are not the files that you want to touch. Imagine yourself changing them, and then receiving an update from Liferay. Be it the next CE GA version or the next EE Servicepack. When this update changes the file that you've customized as well, you're up for a three-way merge. Enjoy. Potentially on every update. Rinse, repeat. Probably not what you're looking forward for.

What other options do you have?

All other things being equal (which they never are), I personally value maintainability higher than any other aspect of a customization. Particularly higher than quick implementation. For that reason, sometimes I rather suggest custom portlets that do exactly what you want them to do - no configuration, no nothing. Consider the options: For something that's close, but not 100% of Asset Publisher, you can hard code exactly the functionality that you'd like to see in your own tiny custom hard-coded portlet, or modify Asset Publisher to pay attention to just one more option.

If you know Liferay, you'll know that Asset Publisher is a very powerful portlet, possibly the one with the most configuration options. Maintaining your changes in Asset Publisher's JSPs will be really hard - particularly because there are so many conditions that need to be taken care of. Typically a more complex component attracts more bugfixes than a very simple component, so the odds of three-way-merges are quite high. Writing your own hard coded plugin on the other hand is guaranteed not to interfere with any future updates of Liferay.

Have you just heard a suggestion to hard-code portlets?

Yes indeed. Hardcode as much as makes sense in your portal: In your portal, you need to take care of your requirements. Your requirements are typically not as broad as Liferay's. You don't (always) need to implement a generically configurable system. At least you don't need the configurability to the same level as Liferay does. Where Liferay needs an "Asset Publisher" (just the name is quite abstract), you might need an "Interesting Facts" portlet. The criteria for interesting facts can totally be hardcoded - you might want to configure the number of items shown, maybe some more, but not 20+ options like Asset Publisher does.

If all you have is a hammer...

...the world looks like a nail. This article is meant to add more tools to your toolbox. Just because Liferay makes its UI available for customizations this doesn't mean you must always use this technique to implement your customizations. Create your own simple navigation portlet, if Liferay's is insufficient for you. Create your Web Content filter by accessing the CMS-API instead of modifying Asset Publisher. Think simple, think maintainable. The more of the core you change, the harder you'll resist to updating your portal, even on a minor update - let alone on a security update. And that will bite you sooner or later.

If the message sounds vaguely familiar, here it is again, with a more specific example. And yes, the complexity that I'm suggesting here is: A few hours of creativity for creating the new plugin, rather than the same hours of trying to understand and patch any of Liferay's existing portlets.

You can still do that, but choose wisely when you'll actually change vs when you create your own portlet. Whatever you do: Remember that most effort will go into the maintenance of your code. Optimize the maintenance time.

Blogs
I will try to summarize what your advice is:
- for simple customization use JSP hooks or struct action overriding
- for complex customization write a new portlet and a new JSP and use interfaces like the CMS-API.
So my questions is: for the purposes of the maintenance is Liferay going to change the API, let's say from one major milestone to another milestone? Because if liferay do so, also writing a custom portlet will require maintence work isn't?
Regards
"It depends" (TM) - this is also what I'd like to state as my advice emoticon

When you modify a JSP, you're actually modifying Liferay's implementation. A JSP-hook is very close to an ext-plugin in that it actually refers to the implementation of Liferay itself - it just is easier to override through copying a few JSPs. Thus, when you change the implementation of Liferay (the portal), keep in mind that it is the business of Liferay (the company) to change its implementation too. And nobody minds if someone else did the same in a plugin.

The API however is designed to be as stable as possible. It changes far less often (and if it happens it's easier to identify and potentially better documented) than any change to the implementation, including a JSP.

So yes, you still have to maintain your portlets, but at least they're shielded from the implementation by the API. That should be a lot easier than a three-way-merge every time you get a minor fix for something in Liferay. From that point of view my advice is: Don't immediately choose the obvious (a JSP hook) but note that there are more options. Choose one of them because you've evaluated the different expected maintenance effort. And don't underestimate the problems of maintaining a JSP hook to a complex JSP page.

All other things being equal (which they never are), I'd always opt for easier maintainability. Which side will be easier to maintain depends a lot on the complexity of the changed UI. It's just that I have the feeling that nobody ever thinks of writing their own plugin, everybody just tries to modify Liferay's UI and I'd like to turn this default around or at least provide another option.