Chapter 6. The contextual component model
The two core concepts of Seam 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, that allows component trees to be dynamically assembled and reassembled by Seam.
6.1. Seam contexts
Seam has many built-in contexts that are created and destroyed by the framework. The application does not control context demarcation through explicit Java API calls. Contexts are usually implicit. In some cases, however, contexts are demarcated with annotations.
There are many basic contexts as follows:
- Stateless context
- Event (for instance, a request) context
- Page context
- Conversation context
- Session context
- Application context
Some basic contexts serve similar purposes in Servlet and related specifications. One you may not have encountered previously is the conversation context. One reason that the state management in web applications is fragile and error-prone, is that, the three built-in contexts (request, session, and application) are not 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, as these are the most meaningful contexts in terms of the application.
6.1.1. Stateless context
Components that 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.
6.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.
6.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 serialized to the client, so this construct is extremely robust with respect to multi-window operation and the back button.
6.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 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 states from different conversations do 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.
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.
6.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.
6.1.6. 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.
6.1.7. Context variables
A context defines a namespace through a set of context variables. These work similar to the 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 through injection. Component instances are subsequently given to contexts through outjection.
6.1.8. 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
- 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.
6.1.9. Concurrency model
Neither the Servlet, nor EJB specifications, define facilities for managing concurrent requests from the same client. The Servlet container allows all threads to run concurrently, without ensuring thread-safeness. The EJB container allows concurrent access of stateless components, and generates 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. 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.
As 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.
Important
Be warned that requests to stateful session beans are not serialized by Seam anymore. Serialization of requests to Stateful session beans are controlled by EJB container, so there is no need for Seam to duplicate that. So
@Synchronized annotation is ignored on stateful session beans.