Posting to a new Portlet Action Using Liferay Hooks 6.1-6.2   Leave a comment

Wow it has been way too long since I have written here. Currently I am dealing with Liferay version 6.1.2 RC2 which may be why I haven’t written much lately. I haven’t really been enjoying liferay as much as I had hopped as I find I spend way more time trying to figuring out the liferay way of doing thing rather than writing the code I want to create.

If you get a requirement to add a new functionality to an existing liferay portlet you will likely want to do this using a hook plugin. In this case I was adding a dismiss all button to the announcements portlet. This tutorial will not cover creating a hook for the portlet but will assume you are working with and existing hook for the portlet you want to modify. You can view more about creating hooks here: I sometimes find Liferay documentation to be lacking. No! I almost always find it lacking, this is just to remember / clarify some of the steps for my own future reference. In this case I am adding a button to the announcements portlet via a hook plugin. I want to fire an action, then refresh the page. This means we will be using actionURL instead of renderURL when triggering the button. Since this will be a new action and not an existing liferay function we are overriding we will first add a new struts action to our hook in the WEB-INF\liferay-hook.xml

        <!-- identifies the hooks file name -->
        <!-- specifies the root directory from which we can override jsp files in a liferay porlet -->
        <!-- specify the new action path that will fire the new action -->

In order for this new portlet action path to be made publicly available to liferay we would need to add a line to the myportal.properies we specified in the liferay-hook.xml. In this case however it is not necessary and we would NOT add this since we will only be calling this path from within the portlet! Just noting it here for future use. This would be more useful for a path you wanted to be available portal wide, not something specific to the portlet. In our case we are just using the action within the portlet we are hooking into… Notice that in this file I am using /portal prefix here which we did not use above. This will not not not map to the action patch we are creating. But since this is a reference you might need to add this depending on your use case!


Next we will create the new action class. This class will extend BaseStrutsPortletAction and will be placed in the package location we specified in the liferay-hook.xml (src\com\mycompany\action\MyNewStrutsPortletAction)

public class MyNewStrutsPortletAction extends BaseStrutsPortletAction {
    private static Log log = LogFactoryUtil.getLog(DismissAllActiveEntriesStrutsPortletAction.class);

    public void processAction(StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig,
                              ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
        // you can access the ThemeDisplay here from the action request
        ThemeDisplay themeDisplay = (ThemeDisplay)actionRequest.getAttribute(WebKeys.THEME_DISPLAY);

        // you can access parameters sent from the post here
        String portletName = ParamUtil.getString(actionRequest, "portletName");
        int flagValue = AnnouncementsFlagConstants.NOT_HIDDEN;
        long loggedInUserId = themeDisplay.getUserId();

        // this will return the proper scope we need to get all the entries on the page. Basically it just
        // executes the code already available within the liferay package, but were not able access from the hook.  
        // This was unfortunately executed from within the JSP via scriptlets in order to find all
        // announcements that were to be displayed on the page ...
         LinkedHashMap<Long, long[]> scopes = MyAnnouncementsUtil.getCurrentScopes(loggedInUserId, themeDisplay);

        // We can access liferay local service utility classes from within the hook.
        // This query was found in a JSP file inside of a scriptlet in entry_iterator.jspf 
        List<AnnouncementsEntry> activeEntries = AnnouncementsEntryLocalServiceUtil.getEntries(loggedInUserId, scopes,
                !portletName.equals(PortletKeys.ANNOUNCEMENTS), flagValue, QueryUtil.ALL_POS, QueryUtil.ALL_POS);

    public String render(StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig,
                         RenderRequest renderRequest, RenderResponse renderResponse) throws Exception {
        // normally you might want to just refresh the page.
        // return originalStrutsPortletAction.render(null, portletConfig, renderRequest, renderResponse);
        // Instead it is safer to take the user to the view.jsp directly in this case because the URL they fired
        // the action from may have contained information about an announcement that has since been
        // dismissed (causes an exception depending on the page where they clicked the button on)
        return "/portlet/announcements/view.jsp";

    public void serveResource(
            StrutsPortletAction originalStrutsPortletAction, PortletConfig portletConfig, ResourceRequest
            resourceRequest, ResourceResponse resourceResponse) throws Exception {
                originalStrutsPortletAction, portletConfig, resourceRequest, resourceResponse);

    private void dismissAllActiveEntries( List<AnnouncementsEntry> activeEntries) throws Exception {
    // This is what liferay source does when you click on the dismiss button for an announcement
    // so we will simply do this for each
    // announcement in the list. But you can do whatever you want here, I just like keeping the bulk
    // of the business logic in a different method. We should now have the same active entries that
    // were loaded into the page.
        for(AnnouncementsEntry entry : activeEntries) {
            // This was found in the liferay source when the user selects the dismiss button so we will do the same for
            // each entry in the list.
            AnnouncementsFlagServiceUtil.addFlag(entry.getEntryId(), AnnouncementsFlagConstants.HIDDEN);


Finally we create the button call the action. In this case the page I was adding the button to did not have a form action, so I took advantage of that. You might want to use ajax and javascript to post instead. We will add the button to view.jsp by copying in liferays’s view.jsp for the portlet then appending code to it. Since we want to override lfierays file this file will be located under the directory we specified in the liferay-hoook.xml followed by the same package structure as found in liferay (docroot\override_jsp\html\portlet\announcements\view.jsp).

<portlet:actionURL var="postURL">
    <portlet:param name="struts_action" value="/nameofportletweareextending/mynewactionpath" />
    <portlet:param name="portletName" value="<%= portletName %>" />
<aui:form action="<%= postURL %>" method="post">
<%-- if you don't want to post using the form action you could write an ajax call instead --%>
      <aui:button value="Dismiss All" type="submit" />

Now when you select this button, the action will fire, and then the specified page “html\portlet\announcements\view.jsp” will be rendered.


Posted February 12, 2015 by javasavy in Liferay

Tagged with

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: