During the initial test run of the portlet version of Component Showcase, the application deployed without incident but when attempting to render the first portlets, I hit this:
18:17:07,565 ERROR [jsp:154] java.lang.NullPointerException
at org.apache.myfaces.context.servlet.FacesContextImpl.isPostback(FacesContextImpl.java:381)
at org.portletfaces.bridge.BridgeImpl.doFacesRequest(BridgeImpl.java:360)
at org.portletfaces.bridge.GenericFacesPortlet.doView(GenericFacesPortlet.java:181)
at javax.portlet.GenericPortlet.doDispatch(GenericPortlet.java:328)
at javax.portlet.GenericPortlet.render(GenericPortlet.java:233)
at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:101)
at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:64)
at com.liferay.portal.kernel.servlet.PortletServlet.service(PortletServlet.java:92)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
at org.apache.catalina.core.ApplicationDispatcher.doInclude(ApplicationDispatcher.java:551)
at org.apache.catalina.core.ApplicationDispatcher.include(ApplicationDispatcher.java:488)
at com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:638)
at com.liferay.portlet.InvokerPortletImpl.invokeRender(InvokerPortletImpl.java:723)
at com.liferay.portlet.InvokerPortletImpl.render(InvokerPortletImpl.java:425)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
The code responsible is:
353 @Override
354 public boolean isPostback()
355 {
356 assertNotReleased();
357
358 RenderKit renderKit = getRenderKit();
359 if (renderKit == null)
360
{
361 // NullPointerException with StateManager, because
362 // to restore state it first restore structure,
363 // then fill it and in the middle of the two previous
364 // process there is many calls from _ComponentChildrenList.childAdded
365 // to facesContext.isPostback, and getViewRoot is null.
366 //
367 // Setting a "phantom" UIViewRoot calling facesContext.setViewRoot(viewRoot)
368 // to avoid it is bad, because this is work of RestoreViewExecutor,
369 // and theorically ViewHandler.restoreView must return an UIViewRoot
370 // instance.
371 //
372 // The problem with this is if the user changes the renderkit directly
373 // using f:view renderKitId param, the ResponseStateManager returned
374 // will be the one tied to faces-config selected RenderKit. But the usual
375 // method to check if a request is a postback, is always detect the param
376 // javax.faces.ViewState, so there is no problem after all.
377 String renderKitId = this.getApplication().getViewHandler().calculateRenderKitId(this);
378 RenderKitFactory factory = (RenderKitFactory)
379 FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
380 renderKit = factory.getRenderKit(this, renderKitId);
381 }
382 return renderKit.getResponseStateManager().isPostback(this);
383 }
Some quick Googling in the PortletFaces forums turned up:
http://www.portletfaces.org/community/forums/-/message_boards/view_message/80005
I have an email into Neil regarding this issue.
So the changes to the DynamicResourceDispatcher were relying on storage in the session for keeping a reference to the session based dispatcher. Unfortunately, the ExternalContext.getSessionMap() method returns the PORTLET-scoped session map which differs from portlet to portlet and there is no way to directly access the APPLICATION-scoped session in the JSF API. So I created a ProxySession that uses reflection to access the method we want when faced with storing things in the session. We use the same proxy approach in other areas for requests and responses.
By adding this new ProxySession and updating the PortletFaces Bridge to the latest 2.0.2 SNAPSHOT, it solves nearly all the issues with resources noted above. The exception is that the CKEditor still appears to have some issues. There have been recent changes in this area (
ICE-7293) to support not having the CKEditor resources loaded proactively unless desired. These changes seem to impact the use of the editor in portlets so this still requires investigation.