Often a logical operation consists of multiple JSF requests to the server. For example, purchasing an insurance policy requires completing a number of related forms (often referred to as a "conversation" or a "dialog"), during which the same java objects need to be kept in memory.
However JSF provides only three scopes for data to be stored in:
Application scope is only rarely of use; such data is shared across all users of that JSF application. Request scope is not useful for the above scenario; all data stored in request scope is discarded at the end of each "command".
Session scope can be used to hold data across multiple requests (a conversation), but suffers from a number of other issues:
The Tomahawk library provides a partial solution to this conversation problem with the t:saveState tag, which allows data stored in request scope to be passed through to a subsequent request. However this can be difficult to use, as every bean that needs to be part of the conversation needs to be explicitly tracked.
The Orchestra library provides another alternative. This solution works across all JSF implementations (particularly Apache MyFaces and the Sun Reference Implementation). It works for Java 1.4 or later. If java1.5 is being used then custom annotations are available to make its use even easier.
Orchestra does require conversation-scoped managed beans to be declared via a good dependency-injection (aka IOC) framework with AOP support. The standard JSF managed-beans facility does not provide sufficient flexibility. While it should be possible for Orchestra to be integrated with any appropriate such framework it initially supports only Spring 2.x. This is no great drawback as there are many other good reasons to use Spring! In the remainder of this document we shall assume Spring is the dependency-injection framework being used.
Various other projects (JBoss Seam, Apache Shale Dialogs, Spring WebFlow) provide conversation/dialog support that is similar to Orchestra. See the Orchestra wiki pages for up-to-date comparisons of Orchestra with other projects.
The normal behaviour for JSF is that when an EL expression references a bean that cannot be found anywhere in the current scopes, the managed bean declarations are searched for the specified name. If a match is found then the bean declaration is used to create an appropriate object instance and insert it into the appropriate scope. The JSF standard provides a way for variable lookup to be extended, and Spring provides an adapter that makes Spring bean declarations accessable to JSF just like managed beans declared in the standard manner.
While "managed beans" declared using the standard JSF syntax can only be declared with app, session or request scope it is possible with Spring 2.0 to declare custom scopes. Orchestra makes a scope of "conversation" available for use. When a bean is instantiated which is declared to be part of "conversation Foo" then the conversation with that name is looked up and the bean inserted into it. This scope is user-specific (ie is a child of the session scope) and is created if it doesn't yet exist.
So far, the effect is just the same as using "session" scope for these beans. However a conversation acts as a "container" for all the beans configured with a particular conversation name. When a conversation ends, all beans associated with that conversation can then be discarded together which is difficult to achieve with simple session storage. A conversation can be terminated in a number of ways:
Conversation names are declared simply by specifying attribute orchestra:conversationName on the Spring bean definition. If no name is provided, then the bean is placed in its own private conversation (which happens to have a name equal to the bean name).
A conversation can have a "policy" of "flash" or "manual". A "flash" conversation is automatically ended (ie deleted) if a request is executed which does not reference any bean in that conversation's scope. This is very convenient when a sequence of pages all have at least one reference to a bean of that conversation scope. If the user navigates to any other page (via direct url entry, or clicking a link, etc) then after that new page is rendered the old (obsolete) conversation scope is automatically discarded. Only when a user's path through the application can reference pages that do not reference conversation-scoped beans is the manual conversation necessary - and in that case, an explicit endConversation component (or direct API call) must be used to discard beans when no longer needed.
Orchestra also provides the concept of a "conversation context", which holds a set of named conversations. A "separateConversationContext" JSF component creates a new context. When this is a parent of any command component (eg a commandLink) then a new conversation context is automatically created when that command is executed. This allows multiple windows to access the same site while having completely independent sets of objects that are of "conversation scope". A hidden "id" emitted into pages specifies what the current conversation context is, ensuring the new windows "sticks" with its associated conversation context.