There have been a few questions lately on StackOverflow trying to troubleshoot activity during the initial page load. So I thought I’d write a post to try to clarify the process. This certainly helps me pre-empt some functionality and provides an explanation for some of the questions I’ve seen. Using code from Jesse Gallagher’s XPages Scaffolding in projects has really helped give me this understanding, so I’d like to give Jesse a shoutout for his work.

ViewHandlers and CreateView

If you’ve worked with XPages for a while, you’re probably aware that the XML markup in the source pane is not the code that runs. The XML markup is compiled down to Java code which comprises methods to create each component you’ve dropped on the page. Each of those components, as well as eventHandler, datasources, dataContexts etc are separate Java objects. Their properties (ignoreRequestParams, documentId, value, rendered, loaded etc) are properties of those Java objects set as and when required. And a server-side map – the component tree – is created for the XPage and stored either in memory or on disk to allow interaction between the browser and the backend database.

A ViewHandler is what creates that component tree, via the createView method. That basically starts from the relevant XPage (the xp:view component) and assigns any properties it needs at this stage that are defined on the All Properties panel for the XPage. It creates Java objects for the meta tags, resources, data and dataContexts allocated at that top level. It then starts creating the other children of the XPage, the components. It processes them in the same order, creating the Java object for the component, assigning any properties needed at this stage, then doing the same for any children of that component before going onto the next sibling component.

A Custom Control is also a component, so if the next sibling it needs to create is a Custom Control, it will create a Java object for that and assign any custom properties you’ve defined on the Custom Control and set values for on the XPage. In the same way as for other components, it then creates Java objects for any children of the Custom Control. Once it’s created all components for the Custom Control, it goes back to the XPage and creates the next sibling.

At this point let’s talk languages. If you define a property as a literal value (e.g. loaded="false", ignoreRequestParams="true"), it’s simply applied. If you compute the value on page load ("${...}"), the expression is passed directly to the relevant parser and the result applied as a literal value. A caveat at this point, if you combine page load and dynamic bindings – $ and # – the page load binding gets calculated, the literal value applied and no subsequent calculation happens. The dynamic binding never gets updated, any assignment via a theme never occurs, it is whatever was set on page load. I’ve covered that before, in this blog post.

If you compute a value dynamically, it creates a value binding and assigns that to the property. The computation itself is not run at this point. It just makes a note to calculate it later. But this means the property does not at this point have a value. So if subsequent components or properties need to use the value, they can’t. This can happen with custom properties on Custom Controls – compositeData.myProperty may not work in some circumstances, if it’s dependent on something that’s not loaded yet. I encountered that early on in my XPages work trying to pass contents of repeat controls into a Custom Control via compositeData.

beforePageLoad and afterPageLoad

As part of building the component tree, the beforePageLoad event is attached to the relevant Java object and run. Again, this will run in order, so the beforePageLoad of the XPage first, then the first Custom Control etc. After the component tree has been fully created, the afterPageLoad events run, but this time in reverse order.

The important point to bear in mind is that all of this is outside of the JSF lifecycle. So phase-specific code in PhaseListeners will not be triggered at this point. It also means this code will not be run during a partial refresh, only on a full page load.

JSF Lifecycle: Render Response

After the createView method of the ViewHandler has completed, the Render Response phase of the JSF lifecycle will usually run. This will again iterate the component tree, running beforeRenderResponse on XPages and Custom Controls, processing themes and calculating dynamic bindings.

The caveat here is that if your code calculated in the page load events calls a context.redirectToPage(“page2.xsp”), you’re telling the server to go to a different page, page2, instead. So that first page’s Render Response phase is not triggered. Instead it goes to page2 immediately and processes the ViewHandler against that page, loading page2’s component tree, running page2’s beforePageLoad and afterPageLoad events and then, unless its told to do otherwise, running page2’s Render Response.

Also, and more importantly to bear in mind, page2 is a new request. So the requestScope for the first page – any requestScope variables set while creating the component tree or any parameters passed in the original URL – is trashed.

That was a problem I came up against with XPages OpenLog Logger, if a developer was catching an error and redirecting to a new page. I collect all SSJS errors in openLogBean and log them out before and after Render Response, to ensure I only get a list of errors that is unique for the error message and the component the error is triggered from. So for an error triggered in multiple JSF phases, it will only log once, for the earliest phase. So when a developer was redirecting on error, the requestScope was trashed before the Render Response could run. Which is why openLogBean is now sessionScoped, and I re-initialise openLogBean at the end of any request.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top