Chapter 5. The contextual component model

Seam's two core concepts are the notions of a context and a component. Components are stateful objects, usually Enterprise JavaBeans (EJBs). An instance of a component is associated with a context, and assigned a name within that context. Bijection provides a mechanism for aliasing internal component names (instance variables) to contextual names, which allows component trees to be dynamically assembled and reassembled by Seam.

5.1. Seam contexts

Seam has several built-in contexts, which are created and destroyed by the framework. The application does not control context demarcation via explicit Java API calls. Contexts are usually implicit. In some cases, however, contexts are demarcated with annotations.
There are a number of basic contexts:
  • Stateless context
  • Event (for instance, a request) context
  • Page context
  • Conversation context
  • Session context
  • Business process context
  • Application context
Some of these contexts serve similar purposes in Servlet and related specifications. Two you may not have encountered previously are the conversation context and the business process context. One reason that state management in web applications is so fragile and error-prone is that the three built-in contexts (request, session, and application) are not especially meaningful for business logic. A user login session, for example, is an arbitrary construct in terms of the application workflow. Therefore, most Seam components are scoped to the conversation or business process contexts, since these are the most meaningful contexts in terms of the application.

5.1.1. Stateless context

Components which are truly stateless (primarily stateless session beans) always operate in the stateless context — the absence of a context, since the instance Seam resolves is not stored. Stateless components are arguably object-oriented, but they are developed regularly and thus form an important part of any Seam application.

5.1.2. Event context

The event context is the "narrowest" stateful context, and expands the notion of the web request to cover other event types. The event context associated with the life cycle of a JSF request is the most important example of an event context, and the one you will work with most often. Components associated with the event context are destroyed at the end of the request, but their state is available and well- defined for at least the life cycle of the request.
When you invoke a Seam component with RMI, or Seam Remoting, the event context is created and destroyed just for the invocation.

5.1.3. Page context

The page context allows you to associate state with a particular instance of a rendered page. You can initialize state in your event listener, or while rendering the page, and can then access it from any event that originates from that page. This is especially useful for functionality such as clickable lists, where the list is backed by changing data on the server side. The state is actually serialized to the client, so this construct is extremely robust with respect to multi-window operation and the back button.

5.1.4. Conversation context

The conversation context is a central concept to Seam. A conversation is a single unit of work from the user's perspective. In reality, it may span several interactions with a user — several requests and several data transactions. But to the user, a conversation solves a single problem. For example, the processes of booking a hotel, approving a contract, and creating an order are all conversations. It may help to think of a conversation as implementing a single "use case", although the relationship is not necessarily this exact.
A conversation holds state associated with the user's present task, in the current window. A single user may have multiple conversations in progress at any point in time, usually spanning multiple windows. The conversation context ensures that state from the different conversations does not collide and cause bugs.
Some conversations last only for a single request. Conversations that span multiple requests must be demarcated with annotations provided by Seam.
Some conversations are also tasks. A task is a conversation that is significant to a long-running business process, and can trigger a business process state transition when completed successfully. Seam provides a special set of annotations for task demarcation.
Conversations can be nested, with one conversation taking place inside a broader conversation. This is an advanced feature.
Between requests, conversation state is usually held in the Servlet session. Seam implements configurable conversation timeout to automatically destroy inactive conversations, which ensures that the state held by a single user login session does not continue to grow if a user abandons a conversation. In the same process, Seam serializes the processing of concurrent requests in the same long-running conversation context.
Alternatively, Seam can also be configured to store conversational state in the client browser.

5.1.5. Session context

A session context holds state associated with the user login session. There are some cases where it is useful for state to be shared between several conversations. However, session context should not usually hold components other than global information about the logged in user.
In a JSR-168 portal environment, the session context represents the portlet session.

5.1.6. Business process context

The business process context holds state associated with long-running business processes. This state is managed and made persistent by the BPM engine (in this case, JBoss jBPM). The business process spans multiple interactions with multiple users. State is shared between multiple users in a well-defined manner. The current task determines the current business process instance, and the business process life cycle is defined externally with process definition language, so there are no special annotations for business process demarcation.

5.1.7. Application context

The application context is the Servlet context from the Servlet specification. Application context is used primarily to hold static information such as configuration data, reference data or metamodels. For example, Seam stores its own configuration and metamodel in the application context.

5.1.8. Context variables

A context defines a namespace through a set of context variables. These work similarly to session or request attributes in the Servlet specification. Any value may be bound to a context variable, but they are usually bound to Seam component instances.
The context variable name identifies a component instance within a context. (The context variable name usually matches the component name.) You can programmatically access a named component instance in a particular scope with the Contexts class, which provides access to several thread-bound instances of the Context interface:
User user = (User) Contexts.getSessionContext().get("user");
You may also set or change the value associated with a name:
Contexts.getSessionContext().set("user", user);
However, components are usually obtained from a context via injection. Component instances are subsequently given to contexts via outjection.

5.1.9. Context search priority

Sometimes, component instances are obtained from a particular known scope. At other times, all stateful scopes are searched, in the following order of priority:
  • Event context
  • Page context
  • Conversation context
  • Session context
  • Business process context
  • Application context
You can perform a priority search by calling Contexts.lookupInStatefulContexts(). Whenever you access a component by name from a JSF page, a priority search occurs.

5.1.10. Concurrency model

Neither the Servlet, nor EJB specifications, define facilities for managing concurrent requests from the same client. The Servlet container lets all threads run concurrently, without ensuring thread-safeness. The EJB container allows concurrent access of stateless components, and throws an exception when multiple threads access a stateful session bean. This is sufficient for web applications based around fine-grained, synchronous requests. However, for modern applications, which frequently use asynchronous (AJAX) requests, concurrency support is vital. Therefore, Seam adds a concurrency management layer to its context model.
Session and application contexts are multi-threaded in Seam, allowing concurrent requests to be processed concurrently. Event and page contexts are single-threaded. Strictly, the business process context is multi-threaded, but concurrency here is rare, and can usually be disregarded. Seam serializes concurrent requests within a long-running conversation context in order to enforce a single thread per conversation per process model for the conversation context.
Because session context is multi-threaded and often contains volatile state, Seam always protects session-scoped components from concurrent access while Seam interceptors are enabled. If interceptors are disabled, any required thread safety must be implemented by the component itself. By default, Seam serializes requests to session-scoped session beans and JavaBeans, and detects and breaks any deadlocks that occur. However, this is not default behavior for application-scoped components, since they do not usually hold volatile state, and global synchronization is extremely expensive. Serialized threading models can be forced on any session bean or JavaBean component by adding the @Synchronized annotation.
This concurrency model means that AJAX clients can safely use volatile session and conversational state, without the need for any special work on the part of the developer.