Chapter 8. Scopes and contexts

Associated with every Web Beans scope type is a context object. The context object determines the lifecycle and visibility of instances of all Web Beans with that scope. In particular, the context object defines:

Each context object is represented by an instance of the Context interface.

8.1. The Context interface

The Context interface provides an operation for obtaining contextual instances of any Web Bean with a particular scope.

public interface Context {
    
    public Class<? extends Annotation> getScopeType();
    
    public <T> T get(Bean<T> bean, boolean create);
    
    boolean isActive();
    
}

The Context SPI is called by the Web Bean manager. It should not be called directly by the application.

User instance = context.get(userBean, true);

The get() method may either:

  • return an existing instance of the given Web Bean, or

  • if the value of the create parameter is false, return a null value, or

  • if the value of the create parameter is true, create a new instance of the given Web Bean by calling Bean.create() and return the new instance.

The get() method may not return a null value unless the create parameter is false or Bean.create() returns a null value.

The get() method may not create a new instance of the given Web Bean unless the create parameter is true.

The Context implementation is responsible for destroying any Web Bean instance it creates by passing the instance to the destroy() method of the Bean object representing the Web Bean. A destroyed instance must not subsequently be returned by the get() method.

At a particular point in the execution of the program a scope may be inactive with respect to the current thread. When a scope is inactive, any invocation of the get() from the current thread upon the Context object for that scope results in a ContextNotActiveException.

Otherwise, we say that the scope is active.

The isActive() method returns false when the scope of the context object is inactive, and true when it is active.

8.2. Normal scopes and pseudo-scopes

Most scopes are normal scopes. The context object for a normal scope type is a mapping from each enabled Web Bean with that scope type to an instance of that Web Bean. This mapping may be associated with a single thread or with a set of threads. There may be no more than one mapped instance per Web Bean per thread. The mapped instance of a Web Bean associated with the current thread is called the current instance of the Web Bean. The set of all current instances for a certain thread is called the context associated with that thread. A context is said to propagate when the set of current instances is preserved.

The get() operation of the Context object for an active normal scope returns the current instance of the given Web Bean.

At certain points in the execution of the program a context associated with the current thread may be destroyed. When a context is destroyed, all current instances of Web Beans with that scope type are destroyed by passing them to the Bean.destroy() method.

Contexts with normal scopes must obey the following rule:

Suppose Web Beans A, B and Z all have normal scopes. Suppose A has an injection point x, and B has an injection point y. Suppose further that both x and y resolve to Web Bean Z according to the typesafe resolution algorithm. If a is the current instance of A, and b is the current instance of B, then both a.x and b.y refer to the same instance of Z. This instance is the current instance of Z.

Any scope that is not a normal scope is called a pseudo-scope. The concept of a current instance is not well-defined in the case of a pseudo-scope.

All pseudo-scopes must be explicitly declared @ScopeType(normal=false), to indicate to the Web Bean manager that no client proxy is required.

All scopes defined by the Web Beans specification, except for the @Dependent pseudo-scope, are normal scopes.

8.3. Dependent pseudo-scope

The @Dependent scope type is a pseudo-scope. Components declared with scope type @Dependent behave differently to Web Beans with other built-in scope types.

When a Web Bean is declared to have @Dependent scope:

  • No injected instance of the Web Bean is ever shared between multiple injection points.

  • Any injected instance of the Web Bean is bound to the lifecycle of the Web Bean, Servlet or EJB bean into which it is injected.

  • Any instance of the Web Bean that is used to evaluate a Unified EL expression exists to service that evaluation only.

  • Any instance of the Web Bean that receives a producer or observer method invocation exists to service that invocation only.

Every invocation of the get() operation of the Context object for the @Dependent scope with the value true for the create parameter returns a new instance of the given Web Bean.

Every invocation of the get() operation of the Context object for the @Dependent scope with the value false for the create parameter returns a null value.

The @Dependent scope is inactive except:

  • when an instance of a Web Bean with scope @Dependent is created by the Web Bean manager to receive a producer method or observer method invocation, or

  • while a Unified EL expression is evaluated, or

  • while an observer method is invoked, or

  • when the Web Bean manager is creating or destroying a Web Bean instance or injecting its dependencies, or

  • when the Web Bean manager is injecting dependencies of an EJB bean or Servlet or when an EJB bean @PostConstruct or @PreDestroy callback is invoked by the EJB container.

8.3.1. Dependent objects of a simple or enterprise Web Bean

A Web Bean may create an instance of a Web Bean with scope type @Dependent by calling Manager.getInstance() from the Web Bean constructor, the Web Bean remove method, initializer methods, producer methods, disposal methods, @PostConstruct and @PreDestroy callbacks and Web Beans interceptors or decorators for any of these methods.

An instance of a @Dependent scoped Web Bean is said to be a dependent object of a simple or enterprise Web Bean instance if:

  • it was injected into any field, the Web Bean constructor, the Web Bean remove method, any observer method or any initializer method of the simple or enterprise Web Bean instance, or

  • it was created by a direct call to Manager.getInstance() during invocation of the Web Bean constructor, the Web Bean remove method, any observer method, any initializer method or any @PostConstruct or @PreDestroy callback of the simple or enterprise Web Bean instance.

8.3.2. Dependent objects of a producer method

An instance of a @Dependent scoped Web Bean is said to be a dependent object of a producer method Web Bean instance if:

  • it was injected into the producer method or disposal method call that produced or disposed the instance, or

  • it was created by a direct call to Manager.getInstance() during invocation of the producer method or disposal method that produced or disposed the instance.

8.3.3. Dependent objects of an EJB bean or Servlet

An EJB bean may create an instance of a Web Bean with scope type @Dependent by calling Manager.getInstance() from initializer methods and @PostConstruct and @PreDestroy callbacks.

An Servlet may create an instance of a Web Bean with scope type @Dependent by calling Manager.getInstance() from initializer methods.

An instance of a @Dependent scoped Web Bean is said to be a dependent object of an EJB bean or Servlet if:

  • it was injected into any field or initializer method of the EJB bean or Servlet, or

  • it was created by a direct call to Manager.getInstance() during invocation of any initializer method of the EJB bean or Servlet or during invocation of any @PostConstruct or @PreDestroy callback of the EJB bean.

8.3.4. Dependent object destruction

The Web Bean manager is responsible for destroying @Dependent scoped Web Bean instances by passing them to the Bean.destroy() method.

The Web Bean manager must:

  • destroy all dependent objects of a Web Bean instance when the instance is destroyed,

  • destroy all dependent objects of an EJB bean or Servlet when the EJB bean or Servlet is destroyed,

  • destroy all @Dependent scoped Web Bean instances created during an EL expression evaluation when the evaluation completes, and

  • destroy any @Dependent scoped Web Bean instance created to receive a producer or observer method invocation when the invocation completes.

Finally, the Web Bean manager is permitted to destroy any @Dependent scoped Web Bean instance at any time if the instance is no longer referenced by the application (excluding weak, soft and phantom references).

8.4. Passivating scopes and serialization

A passivating scope requires that instances of Web Beans with that scope be serializable, so that their state may be stored to disk when the scope becomes inactive. The process of storing the state of Web Bean instances belonging to a scope that is about to become inactive to disk is called context passivation. Passivating scopes must be explicitly declared @ScopeType(passivating=true).

For example, the built-in session and conversation scopes defined in Section 8.5, “Context management for built-in scopes” are passivating scopes.

The Web Bean manager must validate that every Web Bean declared with a passivating scope truly is serializable:

  • EJB local objects are serializable. Therefore, an enterprise Web Bean may declare any passivating scope.

  • Simple Web Beans are not required to be serializable. If a simple Web Bean declares a passivating scope, and the implementation class is not serializable, a DefinitionException is thrown by the Web Bean manager at initialization time.

  • If a producer method declares a passivating scope and returns a non-serializable object at runtime, an IllegalProductException is thrown by the Web Bean manager.

The built-in session and conversation scopes are passivating. No other built-in scope is passivating.

A Web Bean instance may be serialized under one of two circumstances:

  • the Web Bean declares a passivating scope type, and context passivation occurs, or

  • the Web Bean is an EJB stateful session bean, and it is passivated by the EJB container.

In either case, any non-transient field that holds a reference to another Web Bean must be serialized along with the Web Bean that is being serialized. Therefore, the reference must be to a serializable type.

Web Beans client proxies are serializable. Therefore, any reference to a Web Bean which declares a normal scope type is serializable. On the other hand, dependent objects (including interceptors and decorators with scope @Dependent) of a stateful session bean or of a Web Bean with a passivating scope must be serialized and deserialized along with their owner:

  • EJB local objects are serializable. Therefore, any reference to an enterprise Web Bean of scope @Dependent is serializable.

  • A simple Web Bean of scope @Dependent may or may not be serializable. If a simple Web Bean of scope @Dependent and a non-serializable implementation class is injected into a stateful session bean, into a non-transient field, Web Bean constructor parameter or initializer method parameter of a Web Bean which declares a passivating scope type, or into a parameter of a producer method which declares a passivating scope type, an UnserializableDependencyException must be thrown by the Web Bean manager at initialization time.

  • If a producer method of scope @Dependent returns a non-serializable object for injection into a stateful session bean, into a non-transient field, Web Bean constructor parameter or initializer method parameter of a Web Bean which declares a passivating scope type, or into a parameter of a producer method which declares a passivating scope type, an IllegalProductException is thrown by the Web Bean manager.

  • The Web Bean manager must guarantee that JMS endpoint proxy objects are serializable.

The method Bean.isSerializable() may be used to detect if a Web Bean is serializable.

8.5. Context management for built-in scopes

The Web Bean manager provides an implementation of the Context interface for each of the built-in scopes.

For each of the built-in normal scopes, contexts propagate across any Java method call, including invocation of EJB local business methods. The built-in contexts do not propagate across remote method invocations or to asynchronous processes such as JMS message listeners or EJB timer service timeouts.

An integrated Web Bean manager may, but is not required to, utilize standard Java EE APIs such as servlet filters and listeners, JSF phase listeners and EJB interceptors to perform context management. A plugin Web Bean manager must use only standard Java EE APIs.

8.5.1. Request context lifecycle

The Web Beans request context is provided by a built-in context object for the built-in scope type javax.webbeans.RequestScoped.

  • The request scope is active during the service() method of any Servlet in the web application. The request context is destroyed at the end of the servlet request, after the Servlet service() method returns.

  • The request scope is active during any Java EE web service invocation. The request context is destroyed after the web service invocation completes.

  • The request scope is active during any remote method invocation of any EJB bean, during any call to an EJB timeout method and during message delivery to any EJB message driven bean. The request context is destroyed after the remote method invocation, timeout or message delivery completes.

Open issue: currently it is impossible to intercept timeout methods. This needs to be fixed in EJB 3.1.

In a Java EE 5 environment, the Web Bean manager is not required to support an active request context during timeout method invocation.

Open issue: is the request context (and application context) active during servlet filter execution?

8.5.2. Session context lifecycle

The Web Beans session context is provided by a built-in context object for the built-in passivating scope type javax.webbeans.SessionScoped.

The session scope is active during the service() method of any servlet in the web application.

The session context is shared between all servlet requests that occur in the same HTTP servlet session. The session context is destroyed when the HTTPSession is invalidated or times out.

8.5.3. Application context lifecycle

The Web Beans application context is provided by a built-in context object for the built-in scope type javax.webbeans.ApplicationScoped.

  • The application scope is active during the service() method of any servlet in the web application.

  • The application scope is active during any Java EE web service invocation.

  • The application scope is also active during any remote method invocation of any EJB bean, during any call to an EJB timeout method and during message delivery to any EJB message driven bean.

The application context is shared between all servlet requests, web service invocations, EJB remote method invocations, EJB timeouts and message deliveries to message driven beans that execute within the same application. The application context is destroyed when the application is undeployed.

8.5.4. Conversation context lifecycle

The Web Beans conversation context is provided by a built-in context object for the built-in passivating scope type javax.webbeans.ConversationScoped.

  • For a JSF faces request, the context is active from the beginning of the apply request values phase, until the response is complete.

  • For a JSF non-faces request, the context is active during the render response phase.

The conversation context provides access to state associated with a particular conversation. Every JSF request has an associated conversation. This association is managed automatically by the Web Bean manager according to the following rules:

  • Any JSF request has exactly one associated conversation

  • The conversation associated with a JSF request is determined at the end of the restore view phase and does not change during the request

Any conversation is in one of two states: transient or long-running.

  • By default, a conversation is transient

  • A transient conversation may be marked long-running by calling Conversation.begin()

  • A transient conversation may be marked transient by calling Conversation.end()

All long-running conversations have a string-valued unique identifier, which may be set by the application when the conversation is marked long-running, or generated by the Web Bean manager.

The Web Bean manager provides a built-in Web Bean with API type javax.webbeans.Conversation, scope @RequestScoped, deployment type @Standard and binding type @Current, named javax.webbeans.conversation.

public interface Conversation {
   public void begin();
   public void begin(String id);
   public void end();
   public boolean isLongRunning();
   public String getId();
   public long getTimeout();
   public void setTimeout(long milliseconds);
}

If the conversation associated with the current JSF request is in the transient state at the end of a JSF request, it is destroyed, and the conversation context is also destroyed.

If the conversation associated with the current JSF request is in the long-running state at the end of a JSF request, it is not destroyed. Instead, it may be propagated to other requests according to the following rules:

  • The long-running conversation context associated with a request that renders a JSF view is automatically propagated to any faces request (JSF form submission) that originates from that rendered page.

  • The long-running conversation context associated with a request that results in a JSF redirect (via a navigation rule) is automatically propagated to the resulting non-faces request, and to any other subsequent request to the same URL. This is accomplished via use of a GET request parameter named cid containing the unique identifier of the conversation.

  • The long-running conversation associated with a request may be propagated to any non-faces request via use of a GET request parameter named cid containing the unique identifier of the conversation. In this case, the application must manage this request parameter.

When no conversation is propagated to a JSF request, the request is associated with a new transient conversation.

All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries.

In the following cases, a propagated long-running conversation cannot be restored and reassociated with the request:

  • When the HTTP servlet session is invalidated, all long-running conversation contexts created during the current session are destroyed.

  • The Web Bean manager is permitted to arbitrarily destroy any long-running conversation that is associated with no current JSF request, in order to conserve resources.

If the propagated conversation cannot be restored, the request is associated with a new transient conversation.

The method Conversation.setTimeout() is a hint to the Web Bean manager that a conversation should not be destroyed if it has been active within the last given interval in milliseconds.

Open issue: allow the request to be blocked if the conversation cannot be restored.

The Web Bean manager ensures that a long-running conversation may be associated with at most one request at a time, by blocking or rejecting concurrent requests.

Open issue: define a mechanism for "blocking" requests. For example, allow the request to be redirected.

8.6. Context management for custom scopes

A custom implementation of Context may be associated with any scope type at any point in the execution of a Web Beans application, by calling Manager.addContext().

public interface Manager {
    
    public Manager addContext(Context context);
    
    ...
    
}

For example:

manager.addContext(new MethodContext());

Every time Manager.getInstance() is called, for example, during instance or EL name resolution, the Web Bean manager must call Manager.getContext() to retrieve an active context object associated with the Web Bean scope. The getContext() method searches for an active context object for the given scope type. If no active context object exists for the given scope type, getContext() must throw a ContextNotActiveException. If more than one active context object exists for the given scope type, getContext() must throw an IllegalStateException.

public interface Manager {
    
    public Context getContext(Class<? extends Annotation> scopeType);
    
    ...
    
}