Author Archives: Peter Allan Horsfield

About Peter Allan Horsfield

Peter is a long-time developer of everything from real-time machine control systems, to games, WPF apps, public web sites, distributed processing systems and enterprise data warehouses.

Optimizing Richfaces AJAX a4j

Just a quick post because there doesn’t seem to be much on the web about this.

RichFaces AJAX library, originally a separate project called Ajax4JSF, is a well integrated engine for AJAX-enabling a JSF web page.

The library adapts standard JSF/HTML forms so that the POST is sent back to the server via a background request (e.g. XmlHttpRequest ). All requests handled by the server are wrapped in a filter that runs what is mostly the normal JSF lifecycle. The response is then processed by the filter to encode aspects of the JSF response that are not in the returned HTML – like HTTP redirects. This post-processed response is returned to the client which then parses the response and applies it to the page, updating elements, triggering redirects, and so on.

This is fast because JSF builds and holds an in-memory representation of the web page through out the page lifecycle, so the original JSF page does not need to be re-parsed.

Never-the-less, there’s always a need for more speed, and as you expand your AJAX enabled page to include more and more dynamic controls, you may encounter some slow down as both the server and the client need to parse more and more data.

In our application, and on a single page, we have 20 externally included sections, each with a couple of independent forms, and a corresponding number of modal panels, again each with their own forms. Since these forms have been independently developed, performance issues have arisen.

Luckily the designers of the AJAX enabled components within Richfaces have kept this in mind and have provided a full set of attributes that allow you to control what is included in the AJAX lifecycle. Unfortunately, the documentation is somewhat sparse on the various core attributes and how they interact so I hope to use this page to detail how these tags can be used together to optimize the AJAX JSF lifecycle. It’s a work in progress that I will populate as a I update our application.

Core Lifecycle Tags

[RAW]

Behaviour Tag Applies to Performance impact
Establish an AJAX form a4j:form JSF page When any AJAX event defined within an a4j:form is submitted – only form fields from within that form will be submitted. This is the only way to limit the data sent to the server.
Restrict server-side processing a4j:region JSF page Isolate a section of the component tree so that during the AJAX request the server only has to process a subset of the page. Attributes on this tag identify how that isolation affects the individual JSF phases – including determining what is to be included in the HTTP AJAX response. selfRendered appears to disregard non-verbatim code, but it may work well with Facelets since it already stores HTML in the component tree.
Identify a dynamic output region a4j:outputPanel JSF page The outputPanel marks a place in the component tree for which the server might send a response, and thus for which the client may have to perform a partial page update. Setting the ajaxRendered=true attribute on this tag bloats all AJAX request from the page and thus slows client and server processing.

[/RAW]

In the next post I will follow up with information about the attributes on these tags. Several attributes on the above tags interact with each other; for example what is the effect of combining a form inside an a4j:region renderRegionOnly=”true” and a4j:outputPanel ajaxRendered=”true”?

JBoss Seam and conversation boundaries

In the web site we are building we have a set of search pages to identify records, and a long list of CRUD pages for various aspects of those records. This section of the application looks and feels just as a standard web application, where as a user you are engaged in only one activity at a time and none of the business transactions you engage in span more than a single database transaction (unlike, say, a wizard).

Another section of the application works completely differently – it is a document editor that can edit complex structured documents associated with records in the system. This cries out for the ability to have multiple editors available, which is exactly the kind of thing that can be modeled by a Conversation in Seam .

Supporting the document editor feature we have several command buttons distributed throughout the application that allow you to add, edit, or view (in PDF form) these documents.  Once in a document editor, you can leave the editor, visiting the rest of the application, and resume it with a click of a button.

Implementing this turned out to be a little trickier than expected and required a solid understanding of conversation boundaries, or when a conversation comes into existence, and when it leaves.

Here are the key players in the architecture:

SeamEditorCD1

So the navigation flow is very simple – the user visits a search results page, and from there opens an editor. In between the visit to the search-results page and the editor being ready to use in the browser,  the various other components shown are accessed. I’ve explicitly omitted conversation boundaries from this diagram since there are so many ways to start and stop the conversation and it’s the core of what I want to talk about.

In the diagram, the component classes are omitted since they are irrelevant in Seam.

  • editorCollection: Keep track of conversations associated with specific documents.
  • search-results.xhtml: Display a list data items, each with action buttons.
  • editorActions: Contains the code backing the buttons in search-results.xhtml, acts on documents before they are being edited.
  • document: An entity instance of a document being edited or viewed
  • editorManager: Contains the code backing the buttons in editor.xhtml, allowing operations to be performed on a document while it is being edited.
  • editor.xhtml: The actual editor page – consists of a range of buttons to act on the document or to leave the editor, along with document specific widgets that allow data to be entered into the document.
  • pages.xml: This is the global Seam page configuration file, similar to faces-config.xml in JSF.

Navigation

pages.xml is the central piece that establishes navigation among pages in terms of responses to actions triggered by buttons on the page. A simple example might simply be:

[xml]<pages>
<page view-id="search-results.xhtml">
<navigation from-action="#{editorActions.edit(documentId)}">
<redirect view-id="editor.xhtml" />
</navigation>
</page>
</pages>[/xml]

This action would correspond to a link from search-results.xhtml:

[xhtml]<s:link action="#{editorActions.edit(documentId)}" />[/xhtml]

The from-action attribute in pages.xml is not executed – it simply identifies the operation that the navigation rule applies to by being the same exact string. When the link is clicked, the edit() function is executed, and the editor.xhtml view is loaded.

Starting a conversation

This navigation rule and the code listed so far does not actually start a conversation, which means that anything the edit() function does is going to do will act on the session as a whole (since it is a Seam SESSION component). So we have no segregation between document editor instances.

Ignoring the ability to declare that a conversation is required (that’s really just defensive coding, and who wants to see exception handling code?); there are three main places you can instruct Seam to start up a conversation:

* Java 1.5 Annotations provided by Seam (@Begin) on the components
* Attributes on s:link and s:button or tags applied to JSF components; all provided by the Seam UI tag library
* Within page rules in pages.xml using directives like

There are good reasons for using each, but the necessarily page and component spanning nature of conversations make the third option a good choice. The declarative features of pages.xml allow the start and end points of conversations to be placed in a single file, centralizing the lifetime of a conversation, while still allowing the option of implementing conditional navigation logic with EL expressions.

Document editor pages.xml with conversations

[xml]<pages>
<page view-id="search-results.xhtml">
<navigation from-action="#{editorActions.edit(documentId)}">
<start-conversation />
<redirect view-id="editor.xhtml" />
</navigation>
</page>
<page view-id="editor.xhtml">
<navigation from-action="#{editorManager.discard()}">
<end-conversation />
<redirect view-id="search-results.xhtml" />
</navigation>
</page>
</pages>[/xml]

This simple fragment easily shows the ability to cycle between the two pages, starting a conversation before being in the editor and ending a conversation when leaving.

Exactly when does a conversation come to exist?

Upon a click from the search results page, an action method on the editorActions component is invoked. Since the editorAction methods are working on any of the iterated search results, we need to pass the selected record to the action method.

This data is the documentId of the document being edited, (or equivalently the documentTypeId of the document being added). Using this parameter we retrieve from persistence all the data required to display and format the document. Obviously all this information needs to be scoped to the current conversation context in order for it to be segregated from other instances of editors.

Which poses the question: is the conversation context active when the editorActions.edit(documentId) method is executing? If the answer is yes, we should be able to place variables into the conversation context from within editorActions.edit(documentId).

Unfortunately for our system the answer is no, which means this code is bad:

[java]import org.jboss.seam.annotations.*;
import static org.jboss.seam.ScopeType.*;
@Name("editorActions") public class EditorActions {
@In(required = false)
Conversation conversation;
public void edit(int documentId)
{
assert conversation != null;
// record the conversation editor instance
}
}[/java]

We find that during this method, access to the conversation object is unavailable. The obvious inference is that there is no active Seam conversation at this time.

Now it is possible that the tag in pages.xml acts differently to placing an @Begin annotation on an action method. However, the following code acts no differently:

[java]@Begin public void edit(int documentId)
{
assert conversation != null;
// record the conversation editor instance
}[/java]

The problem, and neglected alternate approaches

Event with a conversation context in place, the code performs a significant amount of startup of other components that rely on Conversation scoped data, but because Seam manages outjection through interceptors around method calls, any @Out annotated variables will not actually be placed into the conversation scope until the method returns. So all those other components cannot perform the work they need to do in response to code in the editorActions.edit(documentId) action method.

The issue could be resolved by starting the conversation on one page, and redirecting the user to a temporary page in which a document is not yet loaded, but in which the Seam conversation is fully active. We have tried this approach before, but routing the user indirectly does not give the application the slick feel we are looking for.

One thing we tried when creating a workaround that would allow us to place the loaded document into the conversation context was to observe the built-in seam event that is fired when a new conversation is created. This turned out to be a complicated path to take because the component dealing with creating the document is in the SESSION scope, meaning that it synchronized by Seam to ensure that there are no concurrent accesses. This prevented our observer from interacting with the session scoped editorActions bean as the action method was already executing.

Establishing and populating a Seam conversation context in one go

What we finally tried and have discovered to work well is to access directly the Conversation context from within the editorAction.edit(documentId) method:

[java]public void edit(int documentId)
{
Document d = loadDocument(documentId);
Context conversationContext = Contexts.getConversationContext();
conversationContext.set("documentData", d);
d.activate();
}[/java]

The d.activate() function can access conversation scoped variables manually placed in the conversation context by this method, despite the conversation not having been fully created, and despite any outjections (@Out annotated variables) not having yet been processed.

This is inline with Seam’s published behaviour in which there is always a conversation context present, but that it is temporary unless it has been converted to a long running conversation.

Final Solution

In the end we opted to leverage the Seam @Begin annotation on the editorActions methods that trigger a switch to an editor.  In this manner we ensure the creation of a Conversation is co-located with the functionality that is so tightly coupled to it. We did not do the same for the end of the conversation, since there are various buttons and links on the editor that assist with leaving the page, not all of which have action methods associated with them.  In addition, we decided to sink exceptions and internally log and email them, and altered the action methods to return an outcome string. This allows us to conditionally return to the results page if an error occurs creating an editor and also be able to display an appropriate message. This works nicely with Richfaces/A4J .

The pages.xml now looks like this:

[xml]<pages>
<page view-id="search-results.xhtml">
<navigation from-action="#{editorActions.edit(documentId)}">
<rule if-outcome="success">
<redirect view-id="editor.xhtml" />
<rule>
<rule if-outcome="bad-template">
<message severity="ERROR">Failed to create the editor because template #{errorTemplate} is broken</message>
</rule>
</navigation>
</page>
<page view-id="editor.xhtml">
<navigation from-action="#{editorManager.discard()}">
<end-conversation />
<redirect view-id="search-results.xhtml" />
</navigation>
</page>
</pages>[/xml]

As was mentioned above, we also opted to create a separate editorCollection bean. This bean was necessary purely to avoid concurrent access to a single Seam component. When a conversation is created, this bean manages the process of figuring out a human readable name for the conversation for use in conversation switcher components (i.e., to switch editors).

More on concurrent access to conversation components

As I’ve noted, a SESSION scoped bean cannot be accessed concurrently. Really, no Seam component can be treated as re-entrant. Synchronization on SESSION components is provided to you by Seam because it is likely that a user may double click a link or otherwise trigger multiple concurrent requests. Seam components in lower scopes like PAGE and EVENT do not need synchronization since there will be multiple instances of them created to respond to each activity.

CONVERSATION scoped components are synchronized by Seam by locking the whole conversation while the request is ongoing. New requests for the same conversation are blocked for up to 500ms (configurable), and if the conversation is still not free, then Seam returns a message. In my experience, those web requests received a blank document.

This is critical to understand if you need to make back-end round-trip requests to the web server – you cannot use the same conversation for those. But that’s a topic for another time.