ICEfaces
  1. ICEfaces
  2. ICE-4251

Lifecycle needs to be running before doing navigation/redirection in PersistentFacesState

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8RC2
    • Fix Version/s: 1.8
    • Component/s: Framework
    • Labels:
      None
    • Environment:
      ICEFaces + any external code trying to do navigation using API exposed by PersistentFacesState for navigation/redirection
    • Workaround Exists:
      Yes
    • Workaround Description:
      Hide
      Client reports success with this workaround:

      public static void checkViewRoot(PersistentFacesState state, String viewId) {
               FacesContext ctx = state.getFacesContext();
               if (ctx.getViewRoot() == null) {
                   UIViewRoot viewRoot = ctx.getApplication().getViewHandler().createView(ctx, viewId);
                   if (viewRoot != null) {
                       ctx.setViewRoot(viewRoot);
                   }
               }
           }


      There may be future problems with this as a full JSF lifecycle is not running.
      Show
      Client reports success with this workaround: public static void checkViewRoot(PersistentFacesState state, String viewId) {          FacesContext ctx = state.getFacesContext();          if (ctx.getViewRoot() == null) {              UIViewRoot viewRoot = ctx.getApplication().getViewHandler().createView(ctx, viewId);              if (viewRoot != null) {                  ctx.setViewRoot(viewRoot);              }          }      } There may be future problems with this as a full JSF lifecycle is not running.

      Description

      Client has a long running process trying to do navigation. With the introduction of StateSaving, the ViewRoot is no longer maintained between user requests.

      The PersistentFacesState class has been modified to keep a reference to the information required to start a JSF lifecycle. This is necessary for all server push operations but in this case, the navigateTo and redirectTo methods don't start a JSF lifecycle and the client hasn't the means to start one in the long running thread hence the ViewRoot reference will be null.

        Activity

        Hide
        Greg Dick added a comment -

        I've found a way to check if a lifecycle is currently in process and to start a lifecycle if not. This seems to work well.

        /**

        • Navigate browser to a different page using an outcome argument to
        • select the navigation rule. The mechanism for navigation depends on
        • the navigation rule. <p>
          *
        • If there is no JSF lifecycle in progress when this method is called,
        • this method will manage one. Otherwise, it is the callers responsibility
        • to call the <code>execute</code> method before, and <code>render</code> method
        • after this navigation method.
          *
        • @param outcome the 'from-outcome' field in the navigation rule.
          */
          public void navigateTo(String outcome) {
          warnIfSynchronous();
          try
          Unknown macro: { BridgeFacesContext facesContext = view.getFacesContext(); FacesContext fc = FacesContext.getCurrentInstance(); // #4251 start a lifecycle to re-establish the ViewRoot before // trying navigation if a lifecycle is not already running. if (fc == null) { execute(); } facesContext.getApplication().getNavigationHandler(). handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome); if (fc == null) { render(); } }

          catch (Exception e)

          { throw new RuntimeException(e); }

          }

        I've removed the threadLocal management code in this method since it already is in place in the execute and render
        methods.

        Show
        Greg Dick added a comment - I've found a way to check if a lifecycle is currently in process and to start a lifecycle if not. This seems to work well. /** Navigate browser to a different page using an outcome argument to select the navigation rule. The mechanism for navigation depends on the navigation rule. <p> * If there is no JSF lifecycle in progress when this method is called, this method will manage one. Otherwise, it is the callers responsibility to call the <code>execute</code> method before, and <code>render</code> method after this navigation method. * @param outcome the 'from-outcome' field in the navigation rule. */ public void navigateTo(String outcome) { warnIfSynchronous(); try Unknown macro: { BridgeFacesContext facesContext = view.getFacesContext(); FacesContext fc = FacesContext.getCurrentInstance(); // #4251 start a lifecycle to re-establish the ViewRoot before // trying navigation if a lifecycle is not already running. if (fc == null) { execute(); } facesContext.getApplication().getNavigationHandler(). handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome); if (fc == null) { render(); } } catch (Exception e) { throw new RuntimeException(e); } } I've removed the threadLocal management code in this method since it already is in place in the execute and render methods.
        Hide
        Ed Hillmann added a comment -

        I've tried updating a local copy of the ICEfaces source with this, and I'm still getting the NullPointerException. I added some calls to system.out to see what was going on....

        public void navigateTo(String outcome) {
        warnIfSynchronous();
        try {
        BridgeFacesContext facesContext = view.getFacesContext();
        FacesContext fc = FacesContext.getCurrentInstance();
        System.out.println("fc = " + fc);
        if (fc != null)

        { System.out.println("fc.getViewRoot() = " + fc.getViewRoot()); }

        // #4251 start a lifecycle to re-establish the ViewRoot before
        // trying navigation if a lifecycle is not already running
        if (fc == null)

        { execute(); }

        facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome);
        if (fc == null)

        { render(); }

        } catch (Exception e)

        { throw new RuntimeException(e); }

        }

        When I look at the system log, I'm getting

        core render service created:
        core pool size : 10
        max pool size : 15
        keep alive time: 300000
        fc = com.icesoft.faces.context.BridgeFacesContext@19b7f7f
        fc.getViewRoot() = null

        So this isn't working in my instance.

        If I change the check to

        if ((fc == null) || (fc.getViewRoot() == null)) {

        It never completes (so the navigation never works).

        From what I'm seeing, the BridgeFacesContext never goes away.

        Show
        Ed Hillmann added a comment - I've tried updating a local copy of the ICEfaces source with this, and I'm still getting the NullPointerException. I added some calls to system.out to see what was going on.... public void navigateTo(String outcome) { warnIfSynchronous(); try { BridgeFacesContext facesContext = view.getFacesContext(); FacesContext fc = FacesContext.getCurrentInstance(); System.out.println("fc = " + fc); if (fc != null) { System.out.println("fc.getViewRoot() = " + fc.getViewRoot()); } // #4251 start a lifecycle to re-establish the ViewRoot before // trying navigation if a lifecycle is not already running if (fc == null) { execute(); } facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome); if (fc == null) { render(); } } catch (Exception e) { throw new RuntimeException(e); } } When I look at the system log, I'm getting core render service created: core pool size : 10 max pool size : 15 keep alive time: 300000 fc = com.icesoft.faces.context.BridgeFacesContext@19b7f7f fc.getViewRoot() = null So this isn't working in my instance. If I change the check to if ((fc == null) || (fc.getViewRoot() == null)) { It never completes (so the navigation never works). From what I'm seeing, the BridgeFacesContext never goes away.
        Hide
        Ed Hillmann added a comment -

        Hi. I've slightly changed the solution in order for it to work in my scenario:

        public void navigateTo(String outcome) {
        warnIfSynchronous();
        try {
        BridgeFacesContext facesContext = view.getFacesContext();
        FacesContext fc = FacesContext.getCurrentInstance();
        // #4251 start a lifecycle to re-establish the ViewRoot before
        // trying navigation if a lifecycle is not already running
        boolean manageLifecycle = ((fc == null) || (fc.getViewRoot() == null));
        if (manageLifecycle)

        { execute(); }

        facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome);
        if (manageLifecycle)

        { render(); }

        } catch (Exception e)

        { throw new RuntimeException(e); }

        }

        This works for my situation. All I've done is add an additional check for where the facesContext is not null, but the viewRoot is null.

        Show
        Ed Hillmann added a comment - Hi. I've slightly changed the solution in order for it to work in my scenario: public void navigateTo(String outcome) { warnIfSynchronous(); try { BridgeFacesContext facesContext = view.getFacesContext(); FacesContext fc = FacesContext.getCurrentInstance(); // #4251 start a lifecycle to re-establish the ViewRoot before // trying navigation if a lifecycle is not already running boolean manageLifecycle = ((fc == null) || (fc.getViewRoot() == null)); if (manageLifecycle) { execute(); } facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, facesContext.getViewRoot().getViewId(), outcome); if (manageLifecycle) { render(); } } catch (Exception e) { throw new RuntimeException(e); } } This works for my situation. All I've done is add an additional check for where the facesContext is not null, but the viewRoot is null.
        Hide
        Greg Dick added a comment -

        I've changed the code to the customers example.

        Show
        Greg Dick added a comment - I've changed the code to the customers example.

          People

          • Assignee:
            Unassigned
            Reporter:
            Greg Dick
          • Votes:
            1 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: