ICEfaces
  1. ICEfaces
  2. ICE-8107

NullPointerException when using DataPaginator.gotoFirstPage() in the thread

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: EE-1.8.2.GA_P04
    • Fix Version/s: EE-1.8.2.GA_P05
    • Component/s: ICE-Components
    • Labels:
      None
    • Environment:
      ICEfaces EE 1.8.2 P04
    • Assignee Priority:
      P2
    • Workaround Exists:
      Yes
    • Workaround Description:
      Use Ajax Push APIs (e.g. SessionRenderer) on non-JSF threads.

      Description

      A NullPointerException is thrown when calling DataPaginator.gotoFirstPage() in a thread.

      Customer Use case/Scenario: In a few scenarios we need to get data from database in a thread. After successful get we call gotoFirstPage() on the DataPaginator to move to the first page.

      Error Stack Trace:

      Exception in thread "Thread-13" java.lang.NullPointerException
      at com.icesoft.faces.component.datapaginator.DataPaginatorGroup.execute(DataPaginatorGroup.java:33)
      at com.icesoft.faces.component.datapaginator.DataPaginator.gotoFirstPage(DataPaginator.java:963)
      at com.icefaces.test.SearchManager$1.run(SearchManager.java:55)

      Issue is likely due to the changes made in ICE-7378

        Activity

        Hide
        Arran Mccullough added a comment -

        Attached test case that shows issue.

        Steps:

        • Run welcomeICEfaces.iface url
        • Click on the top button (Refresh Icon)
        • Wait 3 seconds and error is thrown in server logs.
        Show
        Arran Mccullough added a comment - Attached test case that shows issue. Steps: Run welcomeICEfaces.iface url Click on the top button (Refresh Icon) Wait 3 seconds and error is thrown in server logs.
        Hide
        Deryk Sinotte added a comment -

        The DataPaginatorGroup class was only recently added to support the desired behaviour described in ICE-7378 and contains the following method where the NPE occurs:

        public static void execute(UIData uiData, Invoker invoker) {
        if (uiData== null || !uiData.getAttributes().containsKey(DataPaginatorGroup.class.getName())) return;
        List dataPaginatorClientIdList = (List) uiData.getAttributes().get(DataPaginatorGroup.class.getName());
        Iterator it = dataPaginatorClientIdList.iterator();
        while (it.hasNext()) {
        UIComponent component = D2DViewHandler.findComponent(":" + it.next(), FacesContext.getCurrentInstance().getViewRoot());
        if (component != null && component.isRendered() &&
        component instanceof DataPaginator)

        { invoker.invoke((DataPaginator)component); }


        }
        }

        The problem is that, since this is a non-JSF thread, there is no FacesContext so FacesContext.getCurrentInstance() returns null. In order to achieve the desired result, the call will have to be made on a JSF thread, which may mean using a Push + PortableRenderer.

        Show
        Deryk Sinotte added a comment - The DataPaginatorGroup class was only recently added to support the desired behaviour described in ICE-7378 and contains the following method where the NPE occurs: public static void execute(UIData uiData, Invoker invoker) { if (uiData== null || !uiData.getAttributes().containsKey(DataPaginatorGroup.class.getName())) return; List dataPaginatorClientIdList = (List) uiData.getAttributes().get(DataPaginatorGroup.class.getName()); Iterator it = dataPaginatorClientIdList.iterator(); while (it.hasNext()) { UIComponent component = D2DViewHandler.findComponent(":" + it.next(), FacesContext.getCurrentInstance().getViewRoot()); if (component != null && component.isRendered() && component instanceof DataPaginator) { invoker.invoke((DataPaginator)component); } } } The problem is that, since this is a non-JSF thread, there is no FacesContext so FacesContext.getCurrentInstance() returns null. In order to achieve the desired result, the call will have to be made on a JSF thread, which may mean using a Push + PortableRenderer.
        Hide
        Deryk Sinotte added a comment -

        Sorry...this is ICEfaces 1.8 so there is no PortableRenderer. I'll have to look closer at the test case and see if there's a way to workaround it using Push or something.

        Show
        Deryk Sinotte added a comment - Sorry...this is ICEfaces 1.8 so there is no PortableRenderer. I'll have to look closer at the test case and see if there's a way to workaround it using Push or something.
        Hide
        Deryk Sinotte added a comment -

        Re-opening to attach a possible workaround.

        The test case shows what can happen when attempting to do JSF based operations on a non-JSF thread. While it can work (like it did in the past) it's certainly not guaranteed. Especially when the components need access to a valid FacesContext to do the work.

        However, it is possible to use Ajax Push in many of these situations and it's what we generally recommend when trying to offload long running operations onto another thread. When the work completes, call a server-side render to ensure the most recent state is sent back to the client.

        I'm attaching a modified version of the SearchManager class that uses the SessionRenderer API to accomplish the same goal as the original test case. I've added comments where appropriate. Hopefully this type of approach can be used to get around the problem.

        Show
        Deryk Sinotte added a comment - Re-opening to attach a possible workaround. The test case shows what can happen when attempting to do JSF based operations on a non-JSF thread. While it can work (like it did in the past) it's certainly not guaranteed. Especially when the components need access to a valid FacesContext to do the work. However, it is possible to use Ajax Push in many of these situations and it's what we generally recommend when trying to offload long running operations onto another thread. When the work completes, call a server-side render to ensure the most recent state is sent back to the client. I'm attaching a modified version of the SearchManager class that uses the SessionRenderer API to accomplish the same goal as the original test case. I've added comments where appropriate. Hopefully this type of approach can be used to get around the problem.
        Hide
        Deryk Sinotte added a comment -

        Modified SearchManager class that uses SessionRenderer and some other logic to reset the DataPaginator location when appropriate.

        Show
        Deryk Sinotte added a comment - Modified SearchManager class that uses SessionRenderer and some other logic to reset the DataPaginator location when appropriate.
        Hide
        Deryk Sinotte added a comment -

        Closing again. Added example of alternative approach and related comments.

        Show
        Deryk Sinotte added a comment - Closing again. Added example of alternative approach and related comments.

          People

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

            Dates

            • Created:
              Updated:
              Resolved: