Forums

Home » Liferay Portal » English » 3. Development

Combination View Flat View Tree View
Threads [ Previous | Next ]
toggle
Alex Belt
Using Struts in 6.x
June 17, 2013 12:40 PM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

I just upgraded Liferay from 5.2.3 to 6.0.6 in a development environment. I've been trying to deploy our portlet plugin to the new environment with no success so far. It's a Struts based plugin that worked without issue in 5.2.3. I've recompiled it using the 6.0 sdk and updated the various config files for the new version. The plugin Action classes use Liferay's Struts classes, com.liferay.portlet.StrutsPortlet and com.liferay.portlet.struts.PortletAction, contained in the portal-impl.jar, so I am naturally using the PortalClassLoader to access it form the plugin. That being said, I've found some conflicting information elsewhere on the forums here and through Google. So here are my questions:

1. I've seen documentation (including the sample Struts based portlet plugin) here that says to use the com.liferay.portlet.StrutsPortlet class for Struts based apps, then other forum entries saying don't do this because plugins can no longer access this class. Based on my log files, it would appear that you can't. But which one is correct? And if you aren't supposed to use it, why does the sample plugin still use it?

2. If I have to switch to Apache's Struts2 instead of using the Liferay classes, how do I access the Liferay specific data that was provided by default from Liferay's StrutsPortlet class? Isn't there a simpler upgrade path, or do I need to seriously retool the plugin?
Victor Zorin
RE: Using Struts in 6.x
June 17, 2013 8:50 PM
Answer

Victor Zorin

Rank: Liferay Legend

Posts: 1176

Join Date: April 14, 2008

Recent Posts

Some of our portlets are still using Liferay Struts 1 framework, and work well across Liferay 4, 5.2.3, 6.1.0+GE and 6.1.20EE.
Have not experienced any significant portability/migration issues. Portal-impl.jar is not required to run any of these.

Base class for struts portlet we use is org.apache.portals.bridges.struts.StrutsPortlet.
Alex Belt
RE: Using Struts in 6.x
June 18, 2013 7:29 AM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

Thanks Victor. I'm a little out of my depth now, so I'm still somewhat confused. Our portlets are implemented using Struts' Action classes, but they are routed to through the com.liferay.portlet.StrutsPortlet class. If I switch the mapping in web.xml to org.apache.portals.bridges.struts.StrutsPortlet, do I need to change all our Action classes? Or just extend the new StrutsPortlet class and put it in the web.xml mapping so I don't have to change the Action classes?

Liferay is my first exposure to portlet technology, about 7 - 8 months, and the code base I'm working on was already here when I came on - I haven't had to create or upgrade a plugin, so I'm still getting a feel for the process.

Thanks,
Alex
Victor Zorin
RE: Using Struts in 6.x
June 18, 2013 2:55 PM
Answer

Victor Zorin

Rank: Liferay Legend

Posts: 1176

Join Date: April 14, 2008

Recent Posts

How do your Action classes look like? What do they implement/extend?

In our case they extend org.apache.struts.action.Action, but we have own layer of functions to hide dependence from Liferay specifics so we can switch over to another portal platform if such need arrives.

I can have a look further into internals, because we have made this code during Liferay V4.? migration headaches and we have never had to revisit it again so I would not remember now.

What I am sure is that our portlets do not require portal-impl.jar; we also use struts-config.xml exactly the same way as Liferay OOTB portlets do, etc.
Alex Belt
RE: Using Struts in 6.x
June 19, 2013 7:20 AM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

Our Action classes extend a custom class, BaseAction. That class is injected with various Services objects by Spring that are used to access the various portal databases. The BaseAction class extends the com.liferay.portal.struts.PortletAction class, also located in the portal-impl.jar file. The method signatures in our code look like this:

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

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


There are some other convenience methods in the BaseAction class that are liberally used throughout the Action classes as well. Supposedly the code follows what was the best practices for Liferay and portals at the time it was written, but I'm not convinced. I'm wondering if it would make more sense to migrate away from Struts entirely, though that would be a huge undertaking.
Victor Zorin
RE: Using Struts in 6.x
June 20, 2013 12:20 AM
Answer

Victor Zorin

Rank: Liferay Legend

Posts: 1176

Join Date: April 14, 2008

Recent Posts

What you can do is, inherit your class from a new class which you may call OriginalPortletAction.
Create this class and cut and paste the content from com.liferay.portal.struts.PortletAction into it and make sure that it compiles in your environment without dependencies from classes in portal-impl.jar. This may also involve changing from com.liferay.portlet.PortletConfigImpl to your own PortletConfigImpl by the same cut-n-paste approach.

It is possible because this is exactly what we did. So, in a way, you are still inheriting from com.liferay.portal.struts.PortletAction but your own implementation.
And I think our OriginalPortletAction class is still using the original code from Liferay V.4, and everything works fine.

If you are stuck, I can email to you code of our OriginalPortletAction and associated classes. Currently, the only dependencies left are:
- portal-service.jar
- portals-bridges.jar
- portlet.jar
- servlet-api.jar, and
- struts.jar

No need to move away from what you have to something new, because next year Liferay may decide to push towards different approach.

And by the way, for most OOTB portlets Liferay uses struts 1, why to move away from what is currently running the entire portal?
Alex Belt
RE: Using Struts in 6.x
June 20, 2013 6:02 AM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

Funny you should mention that - I looked at doing something similar yesterday with another class. It seemed like every class I looked at had additional dependencies on classes within the portal-impl.jar. I'll take a look at your suggestion and see if I can reasonably do it. I don't like duplicating the code like that, but I don't see a better choice. I'll let you know how it goes.

Thanks a lot Victor, you've been a very big help.

Alex
Alex Belt
RE: Using Struts in 6.x
June 20, 2013 11:09 AM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

Ok, I tried your suggestion and I got farther, but now I'm getting different problems. The first problem I ran into was it was complaining about a ServletContextProvider not being configured. So I copied the code from LiferayServletContextProviderWrapper, whcih has worked - mostly. I also was getting a 'No Default View defined' error for the portlets as well. I added a default-view mapping along with the servletcontextprovider param in the portlet.xml, and it works - mostly. I still get errors, and the information I've found here and on Google hasn't been very informative. Here's the errors I'm getting:

17:51:41,354 INFO [PortletHotDeployListener:220] Registering portlets for CM-portlet
17:51:42,488 ERROR [PortletBagFactory:293] javax.portlet.PortletException: Portlet TrainingIFrame is incorrectly configured. No default View page is defined.
javax.portlet.PortletException: Portlet TrainingIFrame is incorrectly configured. No default View page is defined.
at org.apache.portals.bridges.struts.StrutsPortlet.init(StrutsPortlet.java:166)
at com.liferay.portlet.InvokerPortletImpl.init(InvokerPortletImpl.java:245)
at com.liferay.portlet.PortletInstanceFactoryImpl.init(PortletInstanceFactoryImpl.java:216)
at com.liferay.portlet.PortletInstanceFactoryImpl.create(PortletInstanceFactoryImpl.java:139)
at com.liferay.portlet.PortletInstanceFactoryUtil.create(PortletInstanceFactoryUtil.java:40)
at com.liferay.portlet.PortletBagFactory.create(PortletBagFactory.java:290)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.initPortlet(PortletHotDeployListener.java:456)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.doInvokeDeploy(PortletHotDeployListener.java:253)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.invokeDeploy(PortletHotDeployListener.java:101)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._doFireDeployEvent(HotDeployUtil.java:109)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._fireDeployEvent(HotDeployUtil.java:182)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:38)
at com.liferay.portal.kernel.servlet.PortletContextListener.doPortalInit(PortletContextListener.java:99)
at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:42)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:52)
at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:50)
at com.liferay.portal.kernel.servlet.PortletContextListener.contextInitialized(PortletContextListener.java:55)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4135)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4630)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1041)
at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:964)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1345)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
at java.lang.Thread.run(Thread.java:679)
17:51:42,495 ERROR [HotDeployUtil:112] com.liferay.portal.kernel.deploy.hot.HotDeployException: Error registering portlets for CM-portlet
com.liferay.portal.kernel.deploy.hot.HotDeployException: Error registering portlets for CM-portlet
at com.liferay.portal.kernel.deploy.hot.BaseHotDeployListener.throwHotDeployException(BaseHotDeployListener.java:45)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.invokeDeploy(PortletHotDeployListener.java:104)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._doFireDeployEvent(HotDeployUtil.java:109)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil._fireDeployEvent(HotDeployUtil.java:182)
at com.liferay.portal.kernel.deploy.hot.HotDeployUtil.fireDeployEvent(HotDeployUtil.java:38)
at com.liferay.portal.kernel.servlet.PortletContextListener.doPortalInit(PortletContextListener.java:99)
at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:42)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:52)
at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:50)
at com.liferay.portal.kernel.servlet.PortletContextListener.contextInitialized(PortletContextListener.java:55)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4135)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4630)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1041)
at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:964)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1345)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
at java.lang.Thread.run(Thread.java:679)
Caused by: javax.portlet.PortletException: Portlet TrainingIFrame is incorrectly configured. No default View page is defined.
at org.apache.portals.bridges.struts.StrutsPortlet.init(StrutsPortlet.java:166)
at com.liferay.portlet.InvokerPortletImpl.init(InvokerPortletImpl.java:245)
at com.liferay.portlet.PortletInstanceFactoryImpl.init(PortletInstanceFactoryImpl.java:216)
at com.liferay.portlet.PortletInstanceFactoryImpl.create(PortletInstanceFactoryImpl.java:139)
at com.liferay.portlet.PortletInstanceFactoryUtil.create(PortletInstanceFactoryUtil.java:40)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.initPortletApp(PortletHotDeployListener.java:522)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.doInvokeDeploy(PortletHotDeployListener.java:260)
at com.liferay.portal.deploy.hot.PortletHotDeployListener.invokeDeploy(PortletHotDeployListener.java:101)
... 24 more
17:51:42,499 ERROR [PortletContextFactory:75] Portlet CaseList_WAR_CMportlet has a null portlet bag
17:51:42,499 ERROR [BasePortalLifecycle:45] java.lang.NullPointerException
java.lang.NullPointerException
at com.liferay.portlet.PortletContextFactory._create(PortletContextFactory.java:82)
at com.liferay.portlet.PortletContextFactory.create(PortletContextFactory.java:41)
at com.liferay.portlet.PortletConfigFactoryImpl.create(PortletConfigFactoryImpl.java:52)
at com.liferay.portlet.PortletConfigFactoryUtil.create(PortletConfigFactoryUtil.java:31)
at com.liferay.portal.servlet.filters.language.LanguageFilter.init(LanguageFilter.java:70)
at com.liferay.portal.kernel.servlet.PortalClassLoaderFilter.doPortalInit(PortalClassLoaderFilter.java:95)
at com.liferay.portal.kernel.util.BasePortalLifecycle.portalInit(BasePortalLifecycle.java:42)
at com.liferay.portal.kernel.util.PortalLifecycleUtil.register(PortalLifecycleUtil.java:52)
at com.liferay.portal.kernel.util.BasePortalLifecycle.registerPortalLifecycle(BasePortalLifecycle.java:50)
at com.liferay.portal.kernel.servlet.PortalClassLoaderFilter.init(PortalClassLoaderFilter.java:63)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:295)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:422)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:115)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4001)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4651)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:546)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1041)
at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:964)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:502)
at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1345)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1337)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1601)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1610)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1590)
at java.lang.Thread.run(Thread.java:679)


What's confusing me is, you can clearly see from the extract below, there is a default view defined. Here is a small part of the portlet.xml for the plugin:

<portlet-name>CaseList</portlet-name>
<display-name>Case List</display-name>
<portlet-class>org.apache.portals.bridges.struts.StrutsPortlet</portlet-class>
<init-param>
<name>view-action</name>
<value>/CaseList/login/view</value>
</init-param>
<init-param>
<name>ServletContextProvider</name>
<value>com.gc.struts.ServletContextProviderWrapper</value>
</init-param>
<init-param>
<name>default-view</name>
<value>/view.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Case List</title>
<short-title>CaseList</short-title>
<keywords>CaseList</keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
<portlet>
<portlet-name>TrainingIFrame</portlet-name>
<display-name>Training iFrame</display-name>
<portlet-class>org.apache.portals.bridges.struts.StrutsPortlet</portlet-class>
<init-param>
<name>view-action</name>
<value>/TrainingIFrame/view</value>
</init-param>
<init-param>
<name>ServletContextProvider</name>
<value>com.gc.struts.ServletContextProviderWrapper</value>
</init-param>
<init-param>
<name>default-view</name>
<value>/view.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>Training iFrame</title>
<short-title>TrainingIFrame</short-title>
<keywords>TrainingIFrame</keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>


Clearly there's a default view defined for the portlet, so I don't understand why it's complaining. I don't get the null portlet bag either. I thought I'd copied all the relevant classes from Liferay to remove the dependence on the portal-impl.jar, but if I understand what I've read correctly, the portlet isn't initializing correctly?

I really have no idea now what I'm doing wrong.
Victor Zorin
RE: Using Struts in 6.x
June 20, 2013 3:59 PM
Answer

Victor Zorin

Rank: Liferay Legend

Posts: 1176

Join Date: April 14, 2008

Recent Posts

We have slightly different configuration.
Download for example Dynamic content viewer portlet (link), open up the war file and check files under WEB-INF/ directory. As you would see the 'default' and 'preferences' views are defined in a different way (portlet.xml).
Alex Belt
RE: Using Struts in 6.x
June 21, 2013 6:06 AM
Answer

Alex Belt

Rank: Junior Member

Posts: 49

Join Date: October 9, 2012

Recent Posts

I see what you did, but the util-bridges.jar is in the ROOT application the same as the portal-impl.jar. How did you get around the Classloader change in V6 that stops you from linking to libraries in the ROOT app? They added a deployXML="false" parameter to the Host entry in server.xml that prevents Tomcat from reading the application's context.xml, which is where the PortalClassLoader declaration is. Without using Liferay's PortalClassLoader, I can't access the ROOT application's libraries. Do I need to copy the util-bridges.jar to my project? This issue is the crux of my problem.

Thanks,
Alex

UPDATE: After searching around on the forums some more, I found these:
http://issues.liferay.com/browse/LPS-17916
http://issues.liferay.com/browse/LPS-29750
http://issues.liferay.com/browse/LPS-29103

Given that there are multiple issues open or fixed in versions that we don't have that directly affect the way our plugin is coded, this may have been an exercise in futility. I need to seriously re-evaluate our plan to upgrade using the currently available releases. I feel now that I have no choice but to consider recommending delaying the upgrade until the 6.2 release is finalized, or even possibly switching away from Liferay to another portal platform, like a pure Spring portal implementation. It would be a lot of work and lost time in our Liferay investment, but Liferay makes things so difficult to do something that doesn't fit with their vision, it may be worth it.