ICEfaces
  1. ICEfaces
  2. ICE-4604

Navigation clearing current lifecycle state

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.1
    • Fix Version/s: 1.8.2-RC1, 1.8.2
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      Tomcat 6, JSF 1.1

      Description

      This is the underlying problem for ICE-4565. It looks like, when a commandLink is pressed, that a redirect navigation rule is executed, which causes the current view to be cleaned-up:

      com.icesoft.faces.context.BridgeFacesContext.resetLastViewID(BridgeFacesContext.java:839)
      com.icesoft.faces.context.BridgeExternalContext.redirect(BridgeExternalContext.java:412)
      com.sun.faces.application.NavigationHandlerImpl.handleNavigation(NavigationHandlerImpl.java:149)
      com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:109)
      javax.faces.component.UICommand.broadcast(UICommand.java:332)
      com.icesoft.faces.component.panelseries.UISeries$RowEvent.broadcast(UISeries.java:617)

      The problem is that UIData/UISeries still does more processing after the ActionEvent is broadcasted. Because the UIViewRoot in BridgeFacesContext has been nulled out, then the RenderKit is no longer accessible, so the clientId calculation code throws a NPE.

      java.lang.NullPointerException
      javax.faces.component.UIComponentBase.getRenderer(UIComponentBase.java:1093)
      javax.faces.component.UIComponentBase.getClientId(UIComponentBase.java:272)
      com.icesoft.faces.component.panelseries.UISeries.restoreChild(UISeries.java:523)
      com.icesoft.faces.component.panelseries.UISeries.restoreChildState(UISeries.java:475)
      com.icesoft.faces.component.panelseries.UISeries.restoreChildState(UISeries.java:478)
      com.icesoft.faces.component.panelseries.UISeries.restoreChildState(UISeries.java:478)
      com.icesoft.faces.component.panelseries.UISeries.restoreChildrenState(UISeries.java:463)
      com.icesoft.faces.component.panelseries.UISeries.setRowIndex(UISeries.java:139)
      com.icesoft.faces.component.panelseries.UISeries$RowEvent.broadcast(UISeries.java:644)
      com.icesoft.faces.component.panelseries.UISeries.broadcast(UISeries.java:286)
      com.icesoft.faces.component.paneltabset.PanelTabSet.broadcast(PanelTabSet.java:303)
      javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:287)
      javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:401)
      com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:95)

      Even if we swap out our ICEfaces container components for stock JSF ones, like h:dataTable, it still has the same problem:

      java.lang.NullPointerException
      javax.faces.component.UIComponentBase.getRenderer(UIComponentBase.java:1093)
      javax.faces.component.UIComponentBase.getClientId(UIComponentBase.java:272)
      javax.faces.component.UIData.restoreDescendantState(UIData.java:1095)
      javax.faces.component.UIData.restoreDescendantState(UIData.java:1111)
      javax.faces.component.UIData.restoreDescendantState(UIData.java:1071)
      javax.faces.component.UIData.setRowIndex(UIData.java:416)
      javax.faces.component.UIData.broadcast(UIData.java:678)
      javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:287)
      javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:401)
      com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:95)

      I think that somehow we have to defer the cleanup in BridgeFacesContext.resetLastViewID() until later on, instead of doing it right in BridgeExternalContext.redirect().

      But, I was able to make a simple work-around, that keeps this from being an issue within ICEfaces container components, it's just that it won't help within a stock JSF container, like h:dataTable. First, in UISeries.RowEvent.broadcast(), we omit the row state saving code when we detect the JSF lifecycle is being short-circuited:

              public void broadcast() {
                  int oldRowIndex = getRowIndex();
                  setRowIndex(eventRowIndex);
                  event.getComponent().broadcast(event);
      + // If we're doing a navigation rule, don't alter state
      + FacesContext facesContext = FacesContext.getCurrentInstance();
      + if (facesContext == null ||
      + facesContext.getRenderResponse() ||
      + facesContext.getResponseComplete()) {
      + return;
      + }
                  setRowIndex(oldRowIndex);
              }

      Secondly, I believe I found a bug, whereby UISeries.queueEvent(FacesEvent) is redundantly having its superclass UIData do similar processing, which has to be fixed. Basically, instead of calling super.queueEvent(FacesEvent), which will call UIData.queueEvent(FacesEvent), just do what UIComponentBase.queueEvent(FacesEvent) will do, inline.

          public void queueEvent(FacesEvent event) {
              FacesEvent rowEvent = new RowEvent(this, event, getRowIndex());
      - super.queueEvent(rowEvent);
      + UIComponent parent = getParent();
      + if (parent == null) {
      + throw new IllegalStateException();
      + } else {
      + parent.queueEvent(rowEvent);
      + }
          }

        Issue Links

          Activity

          Hide
          Mark Collette added a comment -

          For assignment to the core team.

          Show
          Mark Collette added a comment - For assignment to the core team.
          Hide
          Mark Collette added a comment -

          ICE-4565 has the sales info, the test WAR, and the ammended web.xml and faces-config.xml files for duplicating the issue.

          Show
          Mark Collette added a comment - ICE-4565 has the sales info, the test WAR, and the ammended web.xml and faces-config.xml files for duplicating the issue.
          Hide
          Mircea Toma added a comment -

          Delay resetting viewRoot variable until the end of lifecycle.

          Show
          Mircea Toma added a comment - Delay resetting viewRoot variable until the end of lifecycle.

            People

            • Assignee:
              Mircea Toma
              Reporter:
              Mark Collette
            • Votes:
              1 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: