1
votes

I'm new to JSF programming and have designed a rather simplistic JSF 2.0 web application. It features a rich:tree on the left which acts as a hierarchical menu. When the user clicks something in the tree, a selection handler is fired and a partial reload of the page is triggered which shows content related to what you just clicked.

The problem is that the interface feels sluggish, so I enabled some logging and added a custom phase listener to give me some idea of where the bottlenecks are.

2012-05-21 07:58:05.516 DEBUG NodeBean - Retrieving properties
2012-05-21 07:58:05.516 DEBUG CustomPhaseListener - Before phase: APPLY_REQUEST_VALUES 2
2012-05-21 07:58:05.876 DEBUG RepositoryBean - Selection change event invoked (size: 1)
2012-05-21 07:58:05.876 DEBUG RepositoryBean - Selection change event handled
2012-05-21 07:58:05.876 DEBUG CustomPhaseListener - After phase: APPLY_REQUEST_VALUES 2
2012-05-21 07:58:05.876 DEBUG CustomPhaseListener - Before phase: PROCESS_VALIDATIONS 3
2012-05-21 07:58:06.469 DEBUG CustomPhaseListener - After phase: PROCESS_VALIDATIONS 3
2012-05-21 07:58:06.469 DEBUG CustomPhaseListener - Before phase: UPDATE_MODEL_VALUES 4
2012-05-21 07:58:06.844 DEBUG CustomPhaseListener - After phase: UPDATE_MODEL_VALUES 4
2012-05-21 07:58:06.844 DEBUG CustomPhaseListener - Before phase: INVOKE_APPLICATION 5
2012-05-21 07:58:06.844 DEBUG CustomPhaseListener - After phase: INVOKE_APPLICATION 5
2012-05-21 07:58:06.860 DEBUG CustomPhaseListener - Before phase: RENDER_RESPONSE 6
2012-05-21 07:58:06.985 DEBUG NodeBean - Retrieving properties
2012-05-21 07:58:07.001 DEBUG RepositoryBean - Retrieving content
2012-05-21 07:58:07.001 DEBUG RepositoryBean - Content retrieved
2012-05-21 07:58:07.376 DEBUG CustomPhaseListener - After phase: RENDER_RESPONSE 6

The NodeBean is a request scoped bean which has a "getProperties()" method. I have no idea why it is being called in the beginning, but its overhead is minimal so that's a problem for another time.

As you can see the JSF lifecycle takes ages to complete while the custom code is rather trivial overhead-wise. After some googling, I found that "immediate='true'" would allow you to skip some steps but adding it to the rich:tree has no effect. I assume that I'm doing something wrong but for the life of me, I can't figure out what.

On a sidenote: from time to time (usually after some inactivity from the user) the process will stop after phase 3 which means no content is returned to the user. Any selection in the rich:tree will have the same behavior until the user reloads the page.

EDIT:

After some further debugging, it appears that the richfaces tree is rebuilt several times on each request. It is related to this issue: JSF2 Richfaces 4.1.0 Ajax partial rendering of tree

My usecase is: the tree is largely static and if you select an item, the properties & content related to that item should appear on the right. So basically I have a selectionchange listener which registers what you selected and a rerender of a central component that uses that setting to load properties & content. The tree should (almost) never be refreshed. What actually happens though is that the entire tree is rebuilt for stage 2, 3, 4 and 6 even though the partial rerender does not mention or reference the tree.

Initially I had this:

<rich:tree id="tree" var="node"
        value="#{repository.browser}" 
        render="node" 
        toggleType="client" selectionType="ajax"

If you set "selectionType" to client, the problem disappears but of nothing is rerendered or called in the backend. I tried adding something like

<f:ajax event="click" render=":node"/>

But that failed as well (the tree was still rebuilt in the background). Is there a way to cache the tree or simply not to rebuild it for every request?

1
Try mode="client". Do you really need the server round-trip? - user207421
immediate=true will bypass validation and wont update the bean, but you would only like to do these when you cancel operation on a page - mprabhat
I'm not entirely where to set the attribute? The rich tree is configured with toggleType="client" and selectionType="ajax". But either way to retrieve the content, a roundtrip to the server must be made. - nablex
I think @EJP meant state saving at client or server - mprabhat
Ah, you mean the "javax.faces.STATE_SAVING_METHOD" context-param? It is indeed set to "server". There is a non-serializable application scoped bean which throws an exception when set to client (PS: the web application is only used by a handful of people) - nablex

1 Answers

1
votes

I have fixed the issue for my particular usecase though I'm not sure how applicable it is to others. I have updated the org.richfaces.component.TreeRange.shouldIterateChildren() method from:

public boolean shouldIterateChildren() {
    if (tree.getRowKey() == null) {
        return true;
    }

    if (tree.isLeaf()) {
        return false;
    }

    return traverseAll || tree.isExpanded();
}

To:

public boolean shouldIterateChildren() {
    if (tree.isLeaf())
        return false;
    else {
        char separatorChar = UINamingContainer.getSeparatorChar(FacesContext.getCurrentInstance());
        String clientId = tree.getClientId();
        boolean render = false;
        for (String idToRender : FacesContext.getCurrentInstance().getPartialViewContext().getRenderIds()) {
            // render the tree if you explicitly mention either the client id (e.g. "menuForm:tree") or the parent component client id (e.g. "menuForm")
            // note that when clicking on an object in the tree, the following render target is requested: menuForm:tree@selection
            if (clientId.equals(idToRender) || clientId.matches(idToRender + separatorChar + ".*")) {
                render = true;
                break;
            }
        }
        // always render if it's not a postback
        return render || !FacesContext.getCurrentInstance().isPostback();
    }
}

I still have no idea whether I'm using rich:tree wrong or if it's actually a bug, I have sent a mail to the jboss-users mailing list and will create a jira issue if it turns out to actually be a bug. At least now my web application responds quickly even with a large tree.