Portlet Action method invocation in Liferay

Portlet action method executes action phase of portlet. It’s not required to override any method to define action method in portlet. Portlet action method is called by its super class (LiferayPortlet) through reflection.

actionURL(in JSP) is used to call the portlet action method. You can define multiple action methods in the portlet. One actionURL can point only one portlet action method. To call different action methods, a separate actionURL needs to be created.  In short, there will be a one-to-one mapping between actionURL(in JSP) and the action method.

In my previous blog, we saw how portlet action method can be defined and how it’s called. In this article, you will learn how the action method is invoked internally.

First, you need to create liferay MVC Portlet. I gave portlet name as TestActionMethodPortlet under com.opensource.techblog.portlet package. I have defined one action method as per the below code snippet.

@ProcessAction(name="actionMethod1")
public void sampleActionMethod(ActionRequest request, ActionResponse response)
                throws IOException, PortletException, PortalException, SystemException{
            _log.info("This is sampleActionMethod ...");
        }

Explanation

  • This is our action method. It takes actionRequest and actionResponse as parameters.
  • ProcessAction annotation is used to map this action method to the action URL (Created in JSP).
  • It’s not necessary to define this annotation. But then in that case you need to give the action method name the same as the name attribute of actionURL in JSP.

Add the following code in the view.jsp

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<portlet:defineObjects />
<portlet:actionURL name="actionMethod1" var="sampleActionMethodURL">
</portlet:actionURL>

<form action="${sampleActionMethodURL}" method="post">
	UserName :-<input type="text" name="userName"><br>
	<input type="submit" value="Submit"> 
</form>

Explanation

  • I have create actionURL by portlet:actionURL tag. name attribute of this tag is the same as the name attribute of @ProcessAction annotation of the action method. So this actionURL is used to calls the action method (sampleActionMethod).
  • I have set actionURL to form’s action attribute so on submitting this HTML form, it will call portlet action method – sampleActionMethod.

To define the action method, I haven’t overridden any method from the parent class. Then how and when it’s called? Before answering the question, let’s see the portlet class hierarchy

Portlet Action method in Liferay - Portlet Class Hierarchy

 

Explanation

  • Our custom portlet (TestActionMethodPortlet) extends MVCPortlet.
  • MVCPortlet extends LiferayPortlet which extends GenericPortlet.
  • GenericPortlet implements the Portlet interface. GenericPortlet and Portlet interface is included in default implementation(portlet.jar file). Rest all classes are provided by Liferay.

Portlet action method invocation

When actionURL is called, the invocation of the portlet action method will be as per the below diagram.

calling of action method - Portlet action method invocation

 

Explanation

  • MVCPorltet is the parent class of our custom portlet class (TestActionMethodPortlet) and LiferayPortlet is the parent class of MVCPortlet. Both these classes (MVCPorltet and LiferayPortlet) are provided by Liferay.
  • You need to configure Liferay source into Eclipse to get a source of the above classes.

Step: 1

  • When actionURL is clicked, Liferay will call processAction() method of MVCPortlet which internally call processAction method of its superclass(LiferayPortlet)

Step: 2

  • processAction internally calls callActionMethod of same(LiferayPortlet) class.
  • Following are few lines of the code of callActionMethod.
     String actionName = ParamUtil.getString(
			actionRequest, ActionRequest.ACTION_NAME);

		if (Validator.isNull(actionName) ||
			actionName.equals("callActionMethod") ||
			actionName.equals("processAction")) {

			return false;
		}

		try {
			Method method = MethodCache.get(
				_classesMap, _methodsMap, getClass().getName(), actionName,
				new Class[] {ActionRequest.class, ActionResponse.class});

			method.invoke(this, actionRequest, actionResponse);
      //More code...

Explanation 

  • First, it reads the value of request parameter (ActionRequest.ACTION_NAME = ‘javax.portlet.action’) in actionName local variable.
  • The value of this request parameter is equal to the name attribute of the action URL tag that you have defined in the view.jsp.
  • In the try block, it uses this value (as string) to calls the action method (that you have defined in your custom portlet) by java reflection.
  • Now you understand that why it’s required to
    • either keep the action method name the same as the name attribute of action URL in JSP or
    • keep name attribute of @processAction annotation same as the name attribute of action URL in JSP (In case if you have defined action method with annotation).
  • If you observe the actionURL generated by portlet:actionURL tag in JSP, it looks like the below snippet.
http://localhost:8080/web/nilang/home?p_auth=e6cvA8tX&p_p_id=testactionmethod_WAR_testactionmethodportlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&p_p_col_id=column-1&_testactionmethod_WAR_testactionmethodportlet_javax.portlet.action=actionMethod1

 Observation

  • You can observe that the value of javax.portlet.action is equals to “actionMethod1” (the name attribute of actionURL.( _testactionmethod_WAR_testactionmethodportlet_  (which is portletId) is appended before javax.portlet.action)
  • value of this parameter will be considered as action method and it’s called through reflection in callActionMethod of LiferayPortlet.
  • That is the reason, you need to either
    • keep the action method name the same as the name attribute of the action URL (by portlet:actionURL tag)
    • or give the name attribute of @ProcessAction annotation the same as the name attribute of action URL (by portlet:actionURL tag).

 Note:- in case if no matching action method is found, then it will throw the following exception.

javax.portlet.PortletException: java.lang.NoSuchMethodException: com.liferay.util.bridges.mvc.MVCPortlet.actionMethod1

Summing UP

  • Portlet action method executes action phase of the portlet.
  • You no need to override any method to define the action method.
  • When actionURL is clicked, MVCPortlet’s processAction method will be called. This method will call processAction method of LiferayPortelt.
  • processAction method internally calls callActionMethod of the same class (LiferayPortlet).
  • Our custom portlet action method is called through java reflection in callActionMethod of LiferayPortelt.
  • You may refer to this link to know about the portlet action phase

I would recommend looking at the index page ‘A Complete Liferay Guide‘ to browse all topics about Liferay.

Recommended For You

About the Author: Nilang

Nilang Patel is a technology evangelist who loves to spread knowledge and helping people in all possible ways. He is an author of two technical books - Java 9 Dependency and Spring 5.0 Projects.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.