Overriding and adding struts actions from hook plugins

This is a new cool feature I worked on with Brian and it’s coming on 6.1 as well as 6.0 EE SP2 and 5.2 EE SP6. With this feature you can add new struts actions to portal from a hook plugin and you can override any existing action with it.

There are two interfaces com.liferay.portal.kernel.struts.StrutsAction and com.liferay.portal.kernel.struts.StrutsPortletAction. The StrutsAction is used for regular struts actions like /c/portal/update_password and StrutsPortletAction is used for those that are used from portlets.

Let’s create a new simple hook to test it out. This hook will create a new struts path /c/portal/sample and wraps an existing struts action. Start by creating a new hook plugin in your plugins SDK. I’ll call it sample-struts-action.

./create.sh sample-struts-action

Next edit the liferay-hook.xml and add following fragment:

<?xml version="1.0"?>
<!DOCTYPE hook PUBLIC "-//Liferay//DTD Hook 6.1.0//EN" "http://www.liferay.com/dtd/liferay-hook_6_1_0.dtd">

<hook>
	<portal-properties>portal.properties</portal-properties>
	<custom-jsp-dir>/META-INF/custom_jsps</custom-jsp-dir>
	<struts-action>
		<struts-action-path>/portal/sample</struts-action-path>
		<struts-action-impl>com.liferay.samplestrutsaction.hook.action.SampleStrutsAction</struts-action-impl>
	</struts-action>
	<struts-action>
		<struts-action-path>/message_boards/view</struts-action-path>
		<struts-action-impl>com.liferay.samplestrutsaction.hook.action.SampleStrutsPortletAction</struts-action-impl>
	</struts-action>
</hook>

Next we need to create the struts action like below:

package com.liferay.samplestrutsaction.hook.action;

import com.liferay.portal.kernel.struts.BaseStrutsAction;
import com.liferay.portal.kernel.util.ParamUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Mika Koivisto
 */
public class SampleStrutsAction extends BaseStrutsAction {

	public String execute(
		HttpServletRequest request, HttpServletResponse response)
		throws Exception {

		String name = ParamUtil.get(request, "name", "World");

		request.setAttribute("name", name);

		return "/portal/sample.jsp";
	}

}

Next create the second Struts action. This one will actually wrap ViewAction of message boards portlet.

package com.liferay.samplestrutsaction.hook.action;

import com.liferay.portal.kernel.struts.BaseStrutsPortletAction;
import com.liferay.portal.kernel.struts.StrutsPortletAction;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

/**
 * @author Mika Koivisto
 */
public class SampleStrutsPortletAction extends BaseStrutsPortletAction {

	public void processAction(
			StrutsPortletAction originalStrutsPortletAction,
			PortletConfig portletConfig, ActionRequest actionRequest,
			ActionResponse actionResponse)
		throws Exception {

		originalStrutsPortletAction.processAction(
			originalStrutsPortletAction, portletConfig, actionRequest,
			actionResponse);
	}

	public String render(
			StrutsPortletAction originalStrutsPortletAction,
			PortletConfig portletConfig, RenderRequest renderRequest,
			RenderResponse renderResponse)
		throws Exception {

		System.out.println("Wrapped /message_boards/view action");

		return originalStrutsPortletAction.render(
			null, portletConfig, renderRequest, renderResponse);
	}

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

		originalStrutsPortletAction.serveResource(
			originalStrutsPortletAction, portletConfig, resourceRequest,
			resourceResponse);
	}

}

Then we need to create the JSP in docroot/META-INF/custom_jsps/html/portal/sample.jsp

Hello !

And lastly we need to create portal.properties in docroot/WEB-INF/src

auth.public.paths=/portal/sample

Now we are ready to deploy the plugin and see if it works. Just run ant deploy in your plugins sdk to deploy it.

You should see following in your tomcat console:

22:01:29,635 INFO  [AutoDeployDir:167] Processing sample-struts-action-hook-6.1.0.1.war
22:01:29,638 INFO  [HookAutoDeployListener:43] Copying web plugin for /Users/mika/Development/Liferay/git/bundles/deploy/sample-struts-action-hook-6.1.0.1.war
  Expanding: /Users/mika/Development/Liferay/git/bundles/deploy/sample-struts-action-hook-6.1.0.1.war into /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299
  Copying 1 file to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299/WEB-INF/classes
  Copying 1 file to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299/WEB-INF/classes
  Copying 1 file to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299/WEB-INF
  Copying 1 file to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299/META-INF
  Copying 12 files to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/webapps/sample-struts-action-hook
  Copying 1 file to /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/webapps/sample-struts-action-hook
  Deleting directory /Users/mika/Development/Liferay/git/bundles/tomcat-6.0.29/temp/20110117220130299
22:01:30,486 INFO  [HookAutoDeployListener:49] Hook for /Users/mika/Development/Liferay/git/bundles/deploy/sample-struts-action-hook-6.1.0.1.war copied successfully. Deployment will start in a few seconds.
Jan 17, 2011 10:01:39 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deploying web application directory sample-struts-action-hook
22:01:39,727 INFO  [PluginPackageUtil:1080] Reading plugin package for sample-struts-action-hook
22:01:39,759 INFO  [HookHotDeployListener:432] Registering hook for sample-struts-action-hook
22:01:39,770 INFO  [HookHotDeployListener:717] Hook for sample-struts-action-hook is available for use

Now try to access http://localhost:8080/c/portal/sample. It will ask you to sign in and once you sign in you should see the message Hello World! in your browser. You can add a paramer name to the url to change the message. If you access message boards it will print the message "Wrapped /message_boards/view action" in tomcat console and continue to render message boards as if nothing was changed.

Now our sample was really simple one. The return value from the execute method is the view where the request is dispatched next. This can be path to JSP, an existing struts forward or tiles definition. Returning null means that your action has handled the view already. Now you could try to return for instance portal.terms_of_use to display the terms of use.

You can download this sample plugin from svn://svn.liferay.com/repos/public/plugins/trunk/hooks/sample-struts-action-hook. The username is guest and password is empty.

UPDATE: We changed the API so that the original action is passed in so that you can also wrap it with your own logic instead of replacing. I also added a new hook property auth.public.paths so it allows you to set new public paths from hooks. I also added a StrutsPortletAction into to the sample and that demonstrates wrapping an existing action.

Blogs
Awesome - exactly what I went looking for.... when can I have it :-)
Awesome feature. Is it possible to create custom services in hook and then call the new services from these overrided struts action? And any hint on when liferay 6.0 EE SP2 will be released so that i can use these in my project?
About one year ago, I worked in a little development that allowed me to override/add, struts actions, tiles configurations, spring beans, and add classs to Liferay usng hooks...
You con find some clues in a 3-posts series at http://aigloss.blogspot.com/2011/04/liferay-portal-server-avoiding-use-of.html.
I've been using it in productin environments since there and has been tested in LF5.1.2 (it was originally developed for that LF version), ang earlier versions of Liferay 6 CE.
With Liferay 6.06 I am not finding com.liferay.portal.kernel.struts.BaseStrutsAction to import.
Nice!
Do you know if is possible to override an struts action in a hook without using ext--enviroment in liferay 5.2.3? Because in the DTD hook of liferay 5.2.3 there are the <struts-action> tags... but know I see that this will be a new functionality of liferay 6.1.
I'm little bit confusing.

Can anyone help me?

Thank you.
Mike and Roberto this is only available in upcoming 6.1 and 6.0 EE SP2 and 5.2 EE SP6. Neither 6.0 CE or 5.2 CE has this feature as it was developed after their release.
Hi Roberto,
I've posted the jar, and a sample hook for Liferay 5.2.3 with the module I was talking in the other post. As told, using that you'll be able to override/add struts configs and actions, tiles configs, spring beans, plus any other thing Liferay allow you to do using hook.
You can check that sample out at http://aigloss.blogspot.com/2011/07/liferay-portal-server-avoiding-use-of.html
Hope you like it!
Hi Aig, is there something like zeep-o-tron for Liferay 6.0.6?
I have'nt tested it yet for that Liferay version, but, unless there is some package modification or something like that, it will surely work.
I'll try to test it and upload a working sample for LF 6.0.6 during this week. Just uploaded it for 5.2.3 first because of Roberto needs.
I am trying to create a hook plugin by extending the class EditPagesAction .I have provided my version of action class with name NPPEditPagesAction.I am able to deploy my plugin into liferay .But I am not able to excute my implemention class code given in NPPEditPagesAction.I tried to set breakpoint in my code but I am not able to get the Debug perspecetive in eclipse.
hook.xml:
--------------
<hook>
<custom-jsp-dir>/WEB-INF</custom-jsp-dir>
<struts-action>
<struts-action-path>/layout_management/edit_pages</struts-action-path>
<struts-action-impl>com.liferay.portlet.communities.action.NPPEditPagesAction</struts-action-impl>
</struts-action>
</hook>


Implementiaon :

public class NPPEditPagesAction extends EditPagesAction {

public void processAction(ActionMapping mapping, ActionForm form,
PortletConfig portletConfig, ActionRequest actionRequest,
ActionResponse actionResponse) throws Exception {

System.out.println("Inside processAction...createTheme()");
String cmd = ParamUtil.getString(actionRequest, Constants.CMD);

try {
if (cmd.equals("createtheme")) {
createTheme(actionRequest);
}

super.processAction(mapping, form, portletConfig, actionRequest,actionResponse);

} catch (Exception e) {

}
}

public ActionForward render(ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
RenderRequest renderRequest, RenderResponse renderResponse)
throws Exception {

return super.render(mapping, form, portletConfig, renderRequest, renderResponse);
//return mapping.findForward(getForward(renderRequest, "portlet.communities.edit_pages"));

}

@SuppressWarnings("static-access")
public static void createTheme(ActionRequest actionRequest) {

System.out.println("Inside createTheme...");
ThemeUtil themeUtil = new ThemeUtil();
final String themeZipFilePath = ThemeUtil.SAMPLE_THEMES_PATH;
final String themeConfigFilePath = ThemeUtil.THEMES_CONFIG_PATH;
try{
//To Modify liferay-look-and-feel.xml
themeUtil.getXMLDetails(themeConfigFilePath);

//To Extract the sample themes zip folder to tomcat location
themeUtil.extractFolder(themeZipFilePath);

} catch (Exception ex) {
ex.printStackTrace();
}

}

///edit_pages_look_and_feel.jsp
<liferay-ui:section>
<div style="width: 40%;">theme name:</div>
<input type="text" id="name">
<div style="width: 40%;">theme id:</div>
<input type="text" id="id"><br>
<div style="width: 40%;">body background:</div>
<input type="text" id="background" class="color"><br>
<div style="width: 40%;">bgcolor:</div>
<input type="text" id="bgcolor" class="color"><br>
<input type="button" value="<liferay-ui:message key="save" />" onclick="<portlet:namespace />createTheme();" />
</liferay-ui:section>


edit_pages.jsp
---------------

function <portlet:namespace />createTheme() {
alert("Hi:Inside createtheme....");
document.<portlet:namespace />fm.<portlet:namespace /><%= Constants.CMD %>.value = "createtheme";
submitForm(document.<portlet:namespace />fm);
}
Was a very nice feature and i tried and implemented it successfully. I have small requirement not sure that is doable or not, i need to redirect to an existing Struts Action in one of the conditions during the render of the BaseStrutsPortletAction case. e..g redirecting to path "login/login"
Rajesh Chaurasia, are you sure you have the right struts-path? Some of the paths are changed automatically by com.liferay.portal.struts.StrutsActionPortletURL so that the path matches the struts-path of the portlet. This can be quite confusing because the struts path in the jsp is different that what is actually rendered.
Kamesh Sampath, can you provide me a example of how would you do that with plain Struts? It might be possible if it's not then it might be something to consider adding.
Isn't this supported by simply delegating those cases back to:

"originalAction" which is the value of the execute's method ActionMapping parameter?
I ve a similar problem of Rajesh Chaurasia

i want override ...action.GetCategoriesAction
so i write the liferay-hook.xml

<struts-action>
<struts-action-path>/asset/get_categories</struts-action-path>
<struts-action-impl>it.reply.open.wt.asset.action.GetCategoriesAction</struts-action-impl>
</struts-action>

but when in my code it invokes this action it uses :
url: themeDisplay.getPathMain() + '/asset/get_categories'

adding the pathMain ( that in my case is /c/ ) so it cant find the action class...
but if i dont add the pathMain it cant find url.



there is a solution for this?
Great, informative article! Really useful feature!

But I was stuck in one silly mistake in my liferay-hook.xml. The ORDER of elements really MATTERS!
It should be as described in "liferay-hook_6_0_0.dtd" (don't pay attention to version).

My liferay-hook.xml was:
<hook>
<custom-jsp-dir>/WEB-INF/custom_jsps</custom-jsp-dir>
<portal-properties>portal.properties</portal-properties>
</hook>

This needed to be:
<hook>
<portal-properties>portal.properties</portal-properties>
<custom-jsp-dir>/WEB-INF/custom_jsps</custom-jsp-dir>
</hook>

I had problems to deploy it, and have gotten such ERROR:
ERROR [HotDeployUtil:114] com.liferay.portal.kernel.deploy.hot.HotDeployException: Error registering hook for Search1-hook
com.liferay.portal.kernel.deploy.hot.HotDeployException: Error registering hook for Search1-hook
at com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener.throwHotDeployException(BaseHotDeployListener.java:46)
at com.liferay.portal.deploy.hot.HookHotDeployListener.invokeDeploy(HookHotDeployListener.java:271)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._doFireDeployEvent(HotDeployUtil.java:111)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._fireDeployEvent(HotDeployUtil.java:188)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:40)
at com.liferay.portal.kernel.servlet.HookContextListener.contextInitialized(HookContextListener.java:36)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4205)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4704)
at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1282)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1380)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:306)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:142)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1385)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1649)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1658)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1638)
at java.lang.Thread.run(Thread.java:619)

I am glad it's resolved now, hope this will help others!
Great feature so far! ... but...

I am trying to create a jsp-Hook for the portlet-configuration tabs. I already figured out, my struts action has to extend BaseStrutsPortletAction. But if I add my own Action there, I get the error

2011-12-12 16:04:00 ERROR [PortletRequestProcessor:377] Forward does not exist

Any help or hint would be great!

(see also: this forum post )
I'm able to wrap the message_boards/view action as you describe here. But when I attempt to wrap /login/facebook_connect_oauth I get a runtime exception: com.liferay.portal.struts.PortletActionAdapter cannot be cast to com.liferay.portal.struts.ActionAdapter.

If I instead extend the class BaseStrutsAction as below, the facebook login functionality ceases to work properly. Is there something fundamentally different about the FacebookConnectAction class or am I doing something wrong?

public class FacebookMyConnectAction extends BaseStrutsAction {

@Override
public String execute(StrutsAction originalStrutsAction,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// TODO Auto-generated method stub
return super.execute(originalStrutsAction, request, response);
}
This is a nice feature indeeed, but there seems to be a bug when wrapping actions that are sending redirects. In my case I'm trying to wrap com.liferay.portal.action.LoginAction (/c/portal/login) with a custom action.

In liferay-hook.xml I have the following:

<hook>
<portal-properties>portal.properties</portal-properties>
<struts-action>
<struts-action-path>/portal/login</struts-action-path>
<struts-action-impl>PortalLoginAction</struts-action-impl>
</struts-action>
</hook>

Then, my PortalLoginAction -class has the following appearance:

public class PortalLoginAction extends BaseStrutsAction {

@Override
public String execute(StrutsAction originalStrutsAction, HttpServletRequest request, HttpServletResponse response)
throws Exception {
//custom code
return originalStrutsAction.execute(request, response);
}
}

Everything works well here until reaching the execution of the original action. The problem seems to be that LoginAction.execute() uses response.sendRedirect() and returns null. The execute() method in com.liferay.portal.struts.StrutsActionAdapter in turn expects the original action to return an ActionForward, thus resulting in a NullPointerException (line 48).

Does anyone know a workaround for this problem? I'm using Liferay 6 EE SP2 and I wouldn't like to make any custom fixes to the code.
I have also hit the same exact problem as Rex Petersen has above. In my case I am trying to override the action for the UpdateReminderQueryAction. The blog post does not make it obvious why the wrapper example above is extending BaseStrutsPortletAction. It is doing so because the action class for message boards view extends PortletAction.

Rex, in the body of your execute method listed above replace the call to super.execute() with this instead:

return originalStrutsAction.execute(request, response);

Mika, if you could enhance your blog to mention this part of the process it would be greatly appreciated.
Hey can you open a ticket for this and post the ticket number here. It should work with returning null as the forward.
I'm assuming you are responding to Jon Haikarainen. right?
R V this is implemented in 6.1.0 CE and backported to 6.0 EE SP2 so not available in 6.0.6 CE.
When I override an existing JSP e.g. lets say blogs/search.jsp, I faced couple of problems

1. I am not able to use the existing struts path "/blogs/search" eventhough I override the same in my hook.xml, its picking my class only when I give a alternate search path like "/blogs/search1"

2. When i return the existing JSP page via the Struts Portlet Action render method I see the basic Portlet CSS styles are gone.

Any thoughts on what I am missing and ways to fix them ?
Is it posible to extend Action that are defined in liferay/.../liferay-portlet.xml, for examle:

<portlet>
<portlet-name>56</portlet-name>
<icon>/html/icons/journal_content.png</icon>
<struts-path>journal_content</struts-path>
<configuration-action-class>com.liferay.portlet.journalcontent.action.ConfigurationActionImpl</configuration-action-class>
...
Mark, unfortunately no. You can only extend actions that are defined in struts-config.xml
Hi all
this is cool feature and i am trying to implement this but i have one question
the default liferay action classes extends PortletAction class which is in portal-impl has method like getForward(),setForward(),sendRedirect(),

now when i am override class i am replacing extends PortletAction with BaseStrutsPortletAction in that i am unable to get those methods for that what i need to change any one can give update
Hi,
I got class cast exception when I access URL : [localhost:8080/c/message_boards/view]

02:50:33,129 ERROR [StripFilter:59] java.lang.ClassCastException: com.liferay.portal.struts.PortletActionAdapter cannot be cast to com.liferay.porta
struts.ActionAdapter
java.lang.ClassCastException: com.liferay.portal.struts.PortletActionAdapter cannot be cast to com.liferay.portal.struts.ActionAdapter
at com.liferay.portal.struts.PortalRequestProcessor.processActionCreate(PortalRequestProcessor.java:485)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:230)
at com.liferay.portal.struts.PortalRequestProcessor.process(PortalRequestProcessor.java:174)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:414)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at com.liferay.portal.servlet.MainServlet.callParentService(MainServlet.java:533)
at com.liferay.portal.servlet.MainServlet.service(MainServlet.java:510)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:72)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.servlet.filters.strip.StripFilter.processFilter(StripFilter.java:304)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.servlet.filters.gzip.GZipFilter.processFilter(GZipFilter.java:123)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.servlet.filters.secure.SecureFilter.processFilter(SecureFilter.java:201)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.servlet.filters.sso.ntlm.NtlmPostFilter.processFilter(NtlmPostFilter.java:83)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.sharepoint.SharepointFilter.processFilter(SharepointFilter.java:80)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.BaseFilter.processFilter(BaseFilter.java:121)
at com.liferay.portal.servlet.filters.virtualhost.VirtualHostFilter.processFilter(VirtualHostFilter.java:208)
at com.liferay.portal.kernel.servlet.BaseFilter.doFilter(BaseFilter.java:48)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java:184)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:92)
at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:738)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDoFilter(InvokerFilterChain.java:203)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:105)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java:164)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:92)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java:164)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:92)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.processDirectCallFilter(InvokerFilterChain.java:184)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilterChain.doFilter(InvokerFilterChain.java:92)
at com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter.doFilter(InvokerFilter.java:70)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:928)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:539)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)