ICEfaces
  1. ICEfaces
  2. ICE-8379

Non-redirect navigation fails for portlet

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1.0.RC1
    • Fix Version/s: 3.1
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      Liferay LiferayFaces
    • Assignee Priority:
      P1

      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)

        Activity

        Hide
        Deryk Sinotte added a comment -

        I could reproduce the behaviour initially reported by Neil and it looked like it was related to navigation and our PropagatingNavigationHandler.

        The form submission triggers a non-redirect navigation (to a thank-you type confirmation screen after the form has been successfully filled out). For this type of navigation, we rely on storing the original DOM in the view map and pulling it out to do the comparison and then basically replacing the contents of the body. The DOM is put into the view map in PropagatingNavigationHandler.handleNavigation():

        ...
        NavigationCase navigationCase = getNavigationCase(context, fromAction, outcome);
        if (navigationCase != null && !navigationCase.isRedirect()) {
        viewMap = viewRoot.getViewMap();
        viewMap.putAll(propagated);
        if (null != oldDOM)

        { viewMap.put(DOMResponseWriter.OLD_DOM, oldDOM); }

        ...

        Logging the various bits before and after the NavigationHandlers have all run:

        PropagatingNavigationHandler.handleNavigation: PRE
        oldDOM get: [#document: null]
        view root : com.liferay.faces.bridge.component.UIViewRootBridgeImpl@61fa0030
        from : #

        {applicantBackingBean.submit}
        outcome : success

        20:34:53,493 DEBUG [ViewHandlerImpl:55] Creating view for viewId=[/views/confirmation.xhtml]

        PropagatingNavigationHandler.handleNavigation: POST
        oldDOM get: null
        view root : com.liferay.faces.bridge.component.UIViewRootBridgeImpl@1b541798
        from : #{applicantBackingBean.submit}

        outcome : success

        PropagatingNavigationHandler.handleNavigation
        navigation case: null

        The navigationCase is currently coming back null so the oldDOM is not being added back in to the new view map for the new view root. However, this behaviour was the same as with ICEfaces 3.0.1 and I went back and confirmed that the example app works with that version. So this is not the actual problem.

        Show
        Deryk Sinotte added a comment - I could reproduce the behaviour initially reported by Neil and it looked like it was related to navigation and our PropagatingNavigationHandler. The form submission triggers a non-redirect navigation (to a thank-you type confirmation screen after the form has been successfully filled out). For this type of navigation, we rely on storing the original DOM in the view map and pulling it out to do the comparison and then basically replacing the contents of the body. The DOM is put into the view map in PropagatingNavigationHandler.handleNavigation(): ... NavigationCase navigationCase = getNavigationCase(context, fromAction, outcome); if (navigationCase != null && !navigationCase.isRedirect()) { viewMap = viewRoot.getViewMap(); viewMap.putAll(propagated); if (null != oldDOM) { viewMap.put(DOMResponseWriter.OLD_DOM, oldDOM); } ... Logging the various bits before and after the NavigationHandlers have all run: PropagatingNavigationHandler.handleNavigation: PRE oldDOM get: [#document: null] view root : com.liferay.faces.bridge.component.UIViewRootBridgeImpl@61fa0030 from : # {applicantBackingBean.submit} outcome : success 20:34:53,493 DEBUG [ViewHandlerImpl:55] Creating view for viewId= [/views/confirmation.xhtml] PropagatingNavigationHandler.handleNavigation: POST oldDOM get: null view root : com.liferay.faces.bridge.component.UIViewRootBridgeImpl@1b541798 from : #{applicantBackingBean.submit} outcome : success PropagatingNavigationHandler.handleNavigation navigation case: null The navigationCase is currently coming back null so the oldDOM is not being added back in to the new view map for the new view root. However, this behaviour was the same as with ICEfaces 3.0.1 and I went back and confirmed that the example app works with that version. So this is not the actual problem.
        Hide
        Deryk Sinotte added a comment -

        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
        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

        { 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 @@ }

        Node body = newDOM.getElementsByTagName("body").item(0);

        • partialWriter.startUpdate(JAVAX_FACES_VIEW_BODY);
          + 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) {

        Show
        Deryk Sinotte added a comment - 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 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 { 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 @@ } Node body = newDOM.getElementsByTagName("body").item(0); partialWriter.startUpdate(JAVAX_FACES_VIEW_BODY); + 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) {

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Deryk Sinotte
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: