Blog Post

...

Invoke an action of core Liferay portlet

Liferay is shipped with a bunch of certain preinstalled portlets, such as Documents and Media, Message Boards, Asset Publisher, etc. Each of these portlets has a set of predefined struts actions (definitions can be found under ROOT/WEB-INF/struts-config.xml) which are invoked upon some user action in current portlet. During a custom portlet development there is a need may occur to call any of these actions, for example folder create/update/delete of Documents and Media (Document Library), without copying a core functionality to custom portlet. This article will demonstrate how to make it work, taking as an example Move Folder action of Documents and Media portlet.

Each Struts action has two phases render and actually action. Unfortunately, it is not possible to invoke render phase of core portlet, because at the time of the call there is redirect to this portlet jsp should occur and if the portlet is not placed within current page then an error displayed. An action phase in contrast is always welcome to invoke.

So let’s imagine a situation when we need to manipulate folders within Document Library from inside of our custom portlet, more specifically on custom portlet button click – do move folder action. First step is to get this action’s struts id from ROOT/WEB-INF/struts-config.xml: prefix “document_library”, postfix “folder” and “move”:

<action path="/document_library/move_folder" type="com.liferay.portlet.documentlibrary.action.EditFolderAction">
	<forward name="portlet.document_library.edit_folder" path="portlet.document_library.move_folder" />
	<forward name="portlet.document_library.error" path="portlet.document_library.error" />
</action>

 

The id of the action /document_library/move_folder, one more thing we need to check is the parameters that may be required for the action class. To do this please have a look at action class source code, luckily Liferay is an opensource product, so it is pretty easy (EditFolderAction.java is our case):

public void processAction(ActionMapping actionMapping, ActionForm actionForm, PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse)
    throws Exception  {
    String cmd = ParamUtil.getString(actionRequest, "cmd");
    try {
      if ((cmd.equals("add")) || (cmd.equals("update"))) {
        updateFolder(actionRequest);
      } else if (cmd.equals("delete")) {
        deleteFolders(actionRequest, false);
      } else if (cmd.equals("move")) {
        moveFolders(actionRequest, false);
      } ...
    }
  }
  
  protected void moveFolders(ActionRequest actionRequest, boolean moveFromTrash)
    throws Exception  {
    long[] folderIds = null;
    long folderId = ParamUtil.getLong(actionRequest, "folderId");
    if (folderId > 0L) {
      folderIds = new long[] { folderId };
    } else {
      folderIds = StringUtil.split(
        ParamUtil.getString(actionRequest, "folderIds"), 0L);
    }
    long parentFolderId = ParamUtil.getLong(
      actionRequest, "parentFolderId");
    ServiceContext serviceContext = ServiceContextFactory.getInstance(
      DLFileEntry.class.getName(), actionRequest);
    for (long moveFolderId : folderIds) {
        DLAppServiceUtil.moveFolder(
          moveFolderId, parentFolderId, serviceContext);
    }
  }

 

From the code above the following required parameters retrieved:

  • cmd – command to perform (may be add/delete/move …)
  • folderId or folderIds – ids of the folders to move
  • parentFolderId – id of the folder to move to.

To invoke the action phase of current action we need to generate a URL of this action. Because desired action is outside of custom portlet we should use liferay-portlet:actionURL jsp tag, which wraps all required ids and parameters with outer portlet id prefixes. In our case final URL tag will look so:

<liferay-portlet:actionURL portletName="<%=PortletKeys.DOCUMENT_LIBRARY%>" var="moveFolderURL" plid="<%=themeDisplay.getPlid()%>"  varImpl="moveFolderURL" 
	<portlet:param name="struts_action" value="/document_library/move_folder" />
	<portlet:param name="cmd"  value="<%= Constants.MOVE %>"  />
	<portlet:param name="folderId" value="<%= String.valueOf(folderId) %>" />		
	<portlet:param name="parentFolderId" value="<%= String.valueOf(parentFolderId) %>" />	
</liferay-portlet:actionURL>

 

In the jsp code below we can find the id of struts action plus parameters found in action class. One more important thing here is a portletName attribute, which is the outer portlet id (document library portlet in our case). The final step is to link implemented action with button control:

<aui:button value="move folder" onClick="<%= moveFolderURL.toString() %>" />

 

As a result we get a button that invokes move_folder struts action of Documents and Media portlet. In this way all predefined struts actions can be called with little exceptions, when parameters can not be wrapped with target portlet id.

Comments (3)

Tags: liferay


Comments:

...

HassanBakri Nov 30, 2015 at 16:55 #

hi Stanislav thanks for great Post i'm trying to call reply_membership_request struts actions the action class is i'm workin in (lifera CE 6.2 GA4) https://github.com/liferay/liferay-portal/blob/6.2.x/portal-impl/src/com/liferay/portlet/sites/action/ReplyMembershipRequestAction.java the required fields (as i think) are :- 1-membershipRequestId 2-replyComments 3-statusId so the final url wold be look like this : <portlet:actionURL portletName="<%=PortletKeys.SITE_MEMBERSHIPS_ADMIN %>" var="replyMembershipRequestURL"> <portlet:param name="struts_action" value="/sites_admin/reply_membership_request" /> <portlet:param name="membershipRequestId" value="<%=String.valueOf(aaUser.getMembershipRequestId()) %>"/> <portlet:param name="replyComments" value="Thanx Joining Us Happy juerny"/> <portlet:param name="statusId" value="<%= String.valueOf(MembershipRequestConstants.STATUS_APPROVED) %>"/> </portlet:actionURL> the problem is i get this exception Attribute portletName invalid for tag actionURL according to TLD liferay so what is going on ????

...

HassanBakri Nov 30, 2015 at 16:58 #

hi Stanislav i'm trying to call reply_membership_request struts actions the action class is i'm workin in (lifera CE 6.2 GA4) https://github.com/liferay/liferay-portal/blob/6.2.x/portal-impl/src/com/liferay/portlet/sites/action/ReplyMembershipRequestAction.java the required fields i guess are : 1-membershipRequestId 2-replyComments 3-statusId so the final url wold be look like this : <portlet:actionURL portletName="<%=PortletKeys.SITE_MEMBERSHIPS_ADMIN %>" var="replyMembershipRequestURL"> <portlet:param name="struts_action" value="/sites_admin/reply_membership_request" /> <portlet:param name="membershipRequestId" value="<%=String.valueOf(aaUser.getMembershipRequestId()) %>"/> <portlet:param name="replyComments" value="Thanx Joining Us Happy juerny"/> <portlet:param name="statusId" value="<%= String.valueOf(1) %>"/> </portlet:actionURL> the problem is i get this exception Attribute portletName invalid for tag actionURL according to TLD liferay

...

Stanislav Dec 24, 2015 at 13:41 #

Hi Hassan, when you use cross portlet communication, you need to use <liferay-portlet:actionURL> jsp tag, not <portlet:actionURL>.

Leave a Comment