Some time ago I posted about the number of times the rendered property gets calculated during the JSF lifecycle and the benefits of partial execution. (One caveat is that I haven’t re-tried that since 8.5.x, so more optimisation may have been built into the XPages runtime engine.)
One way of optimising calculations in the rendered property is to ensure they are not run during other phases of the lifecycle. I have always been a little confused about why it is calculated so many times. The assumption I had was that the rendered property only affected whether the component and its children were outputted to the browser. So why not just return false in other phases? There are a couple of ways to do that.
In my particular situation I had a set of links calling a Java method from an onClick event. But in some scenarios I didn’t want the links to show. So I set a rendered property and, to optimise it, only ran the full calculation based on the result of
view.isRenderingPhase(), otherwise just returning false. That meant the full calculation only happened during the Render Response phase.
But when I tested the code, clicking triggered a partial refresh, but my Java code didn’t run. Debugging the Java method proved it was not even triggered. Using a PhaseListener showed all six phases were being processed though. When I removed the rendered property, it was fine.
The lesson learned is that the rendered property doesn’t just define whether or not the property is outputted to the browser. It seems like it determines whether or not the component is added to the component tree. But because I was returning false in the rendered calculation for every phase except Render Response, it meant the server-side code was not in the component tree when the Invoke Application phase was being run. So the server didn’t see any code to run, just a partial refresh.
The lesson learned is to either return true or skip based on the phase. But how do you know what phase is running? There is view.isRenderingPhase(), but not any other built-in way to identify which phase is running.
However, a Phase Listener runs before and after every phase. There is also requestScope which is accessible during the lifecycle and discarded at the end of each request. The
beforePhase(PhaseEvent event) method also knows which phase is being run, and the PhaseEvent object allows
getPhaseID().getOrdinal() to capture the number of the phase. Adding this to the beforePhase method:
will mean you can test whether requestScope.currPhase < 4, to ensure the code doesn’t run before the Invoke Application phase. Testing for view.isRenderingPhase() and just returning true is a cleaner method for this. But in the next blog post I’ll show a scenario where running the code only during Invoke Application onwards is more important.