Hello Programmers,
If you are looking to override a Portlet MVC Action Command then you are at correct place. I'm going to override LoginMVCActionCommand in this example. I'm writing the steps here. Before starting code, you should read the following blogs.
Hope you gone through the blogs. In first blog, If you see the complete output for the command g! b 217 then you will find the following in the result.
{com.liferay.portal.kernel.portlet.bridges.mvc.MVCActionCommand}={mvc.command.name=/login/login, javax.portlet.name=[com_liferay_login_web_portlet_FastLoginPortlet,com_liferay_login_web_portlet_LoginPortlet], component.name=com.liferay.login.web.internal.portlet.action.LoginMVCActionCommand, component.id=144, service.id=160, service.bundleid=217, service.scope=bundle}
Notice the followings properties and values. These are very important to override a portlet MVC action command.
mvc.command.name=/login/login
javax.portlet.name=[com_liferay_login_web_portlet_FastLoginPortlet,com_liferay_login_web_portlet_LoginPortlet]
service.id=160
Let's understand the above values.
- mvc.command.name : a key to identify the particular command. It is the value of name property in your JSP's matching actionUrl.
- javax.portlet.name : the portlet that is affected by this command.
- service.id : component weight.
Let's override the login action command.
- Create Liferay Module Project in a Liferay Workspace Project. I have created a module login-action-hook under workspace project evon-module.
- Right click on module project -> New -> Others.
- Search Liferay Component Class and select it. Check Image 1 below.
- Select your Project name from drop down. Provide Package name, Component Class Name and select Portlet Action Command from drop down for Component Class Template. Check Image 2 below.
- Click Finish.
Image 1
Image 2
IDE creates the classes with some default annotation and code in your action command class. Open file and change the code. You can delete the unnecessary classes other than your ActionCommand class.
Please notice - We need to resolve the dependencies manually in case of different components. In case of Portlet Action Command, here are the build.gradle dependencies.
dependencies {
compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib", version: "2.0.0"
compileOnly group: "com.liferay", name: "com.liferay.petra.content", version: "1.0.0"
compileOnly group: "com.liferay", name: "com.liferay.portal.upgrade", version: "2.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.impl", version: "2.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.7.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.util.java", version: "2.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0"
compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
}
Once changed the dependencies, right click on module -> Gradle -> Refresh the project. It will take time to resolve and download the dependencies.
We already found out the mvc.command.name and javax.portlet.name properties for the LoginMCVActionCommand. Let's keep the values in our component annotation.
package com.evontech.action;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.portlet.bridges.mvc.BaseMVCActionCommand;
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCActionCommand;
@Component(
immediate = true,
property = {
"javax.portlet.name=com_liferay_login_web_portlet_FastLoginPortlet",
"javax.portlet.name=com_liferay_login_web_portlet_LoginPortlet",
"mvc.command.name=/login/login",
"service.ranking:Integer=161"},
service = MVCActionCommand.class
)
public class EvonLoginMVCActionCommand extends BaseMVCActionCommand {
private static final Log _log = LogFactoryUtil.getLog(EvonLoginMVCActionCommand.class);
@Reference(target = "(&(mvc.command.name=/login/login)(javax.portlet.name=com_liferay_login_web_portlet_FastLoginPortlet)(javax.portlet.name=com_liferay_login_web_portlet_LoginPortlet)(component.name=com.liferay.login.web.internal.portlet.action.LoginMVCActionCommand))")
protected MVCActionCommand mvcActionCommand;
public EvonLoginMVCActionCommand() {
super();
_log.info("**** EvonLoginMVCActionCommand Constructor ****");
}
@Override
protected void doProcessAction(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
_log.info("*************** My Login ************* ");
mvcActionCommand.processAction(actionRequest, actionResponse);
}
}
I changed the default annotation and the default code. Let's understand it.
- Check the component annotation. I've kept the values that we found from gogo shell. The properties let know the OSGI runtime that which action command is overriden. I've used the service.ranking:Integer=161 here. This property overrides the service.id and used to tell the OSGi runtime which service to use, in cases where there are multiple components registering the same service, with the same properties. The higher the integer you specify here, the more weight your component carries. Therefore I used 161 to override my default value 160.
- I've used @Reference annotation to target the original LoginMVCActionCommand object so that I can use the default functionality along with my code. Please notice, I've used the (component.name=com.liferay.login.web.internal.portlet.action.LoginMVCActionCommand) inside the annotation to avoide the circular reference detection issue.
- You can write your custom code in doProcessAction method.
Deploy the code and you will see your logs in log window.
That's all.
Hope that would help you.
7 Comment(s)