Details
Description
In testing the Liferay Faces bridge with his own samples, Neil found that one them that was working with our 3.0.1 release is now failing with the 3.1.0-RC1 release. The problem is that when, after successfully filling out the form, clicking submit should result in a non-redirect navigation to a new view. While this worked with the 3.0.1 release, it now causes:
(note, line numbers may not match as this stack trace is from classes that have extra debugging lines in them)
java.lang.NullPointerException
at org.icefaces.impl.util.DOMUtils.printNode(DOMUtils.java:291)
at org.icefaces.impl.util.DOMUtils.printNodeCDATA(DOMUtils.java:278)
at org.icefaces.impl.context.DOMPartialViewContext.processPartial(DOMPartialViewContext.java:189)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:981)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:391)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at com.liferay.faces.bridge.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:45)
at com.liferay.faces.bridge.BridgePhaseResourceImpl.execute(BridgePhaseResourceImpl.java:115)
at com.liferay.faces.bridge.BridgeImpl.doFacesRequest(BridgeImpl.java:115)
at javax.portlet.faces.GenericFacesPortlet.serveResource(GenericFacesPortlet.java:178)
(note, line numbers may not match as this stack trace is from classes that have extra debugging lines in them)
java.lang.NullPointerException
at org.icefaces.impl.util.DOMUtils.printNode(DOMUtils.java:291)
at org.icefaces.impl.util.DOMUtils.printNodeCDATA(DOMUtils.java:278)
at org.icefaces.impl.context.DOMPartialViewContext.processPartial(DOMPartialViewContext.java:189)
at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:981)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1757)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:391)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at com.liferay.faces.bridge.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:45)
at com.liferay.faces.bridge.BridgePhaseResourceImpl.execute(BridgePhaseResourceImpl.java:115)
at com.liferay.faces.bridge.BridgeImpl.doFacesRequest(BridgeImpl.java:115)
at javax.portlet.faces.GenericFacesPortlet.serveResource(GenericFacesPortlet.java:178)
The real problem turned out to be in the DOMPartialViewContext. As part of the fix for ICE-8132, "full page" udpates were split into separate <head> and <body> updates. As part of the changes, the following lines were included:
Node body = newDOM.getElementsByTagName("body").item(0);
partialWriter.startUpdate(JAVAX_FACES_VIEW_BODY);
Unfortunately, when a new DOM is generated for a portlet, there is no "body" to get which leads to the NPE. The old way of doing it just used the whole document (which is why the fix was required).
So to fix this, I went back to a version of the original way if there is no body and where running as a portlet:
Deryks-MacBook-Pro:core deryk$ svn diff -r30043:30044
{ private static final String JAVAX_FACES_VIEW_HEAD = "javax.faces.ViewHead"; private static final String JAVAX_FACES_VIEW_BODY = "javax.faces.ViewBody"; + private static final String JAVAX_FACES_VIEW_ROOT = PartialResponseWriter.RENDER_ALL_MARKER; private static final Logger log = Logger.getLogger(DOMPartialViewContext.class.getName()); private static final Pattern SPACE_SEPARATED = Pattern.compile("[ ]+"); private static final Pattern OPTION_TAG = @@ -181,7 +182,18 @@ }Index: src/main/java/org/icefaces/impl/context/DOMPartialViewContext.java
===================================================================
— src/main/java/org/icefaces/impl/context/DOMPartialViewContext.java (revision 30043)
+++ src/main/java/org/icefaces/impl/context/DOMPartialViewContext.java (revision 30044)
@@ -46,6 +46,7 @@
public class DOMPartialViewContext extends PartialViewContextWrapper
Node body = newDOM.getElementsByTagName("body").item(0);
+ String target = JAVAX_FACES_VIEW_BODY;
+
+ //
ICE-8379: If there is no body in the new DOM, then it's likely were running+ // in a portlet so get the document as it will be a "fragment" of the page. We
+ // also need to just target the ViewRoot rather than the ViewBody for the update.
+ if (body == null &&
+ EnvUtils.instanceofPortletRequest(facesContext.getExternalContext().getRequest())) { + body = newDOM.getDocumentElement(); + target = JAVAX_FACES_VIEW_ROOT; + }
+
+ partialWriter.startUpdate(target);
DOMUtils.printNodeCDATA(body, outputWriter);
partialWriter.endUpdate();
} else if (null != diffs) {