6.2. Seam components

Seam components are Plain Old Java Objects (POJOs). Specifically, they are JavaBeans, or Enterprise JavaBean 3.0 (EJB3). While Seam does not require components to be EJBs, and can be used without an EJB3-compliant container, Seam was designed with EJB3 in mind, and includes deep integration with EJB3. Seam supports the following component types:
  • EJB3 stateless session beans
  • EJB3 stateful session beans
  • EJB3 entity beans (for instance, JPA entity classes)
  • JavaBeans
  • EJB3 message-driven beans

6.2.1. Stateless session beans

Stateless session bean components cannot hold state across multiple invocations, so they usually operate upon the state of other components in the various Seam contexts. They can be used as JSF action listeners, but cannot provide properties to JSF components for display.
Stateless session beans always exist in the stateless context. They can be accessed concurrently as a new instance is used for each request. The EJB3 container assigns instances to requests. (Normally, instances are allocated from a reuseable pool, so instance variables can retain data from previous uses of the bean.)
Seam stateless session bean components are instantiated with either Component.getInstance() or @In(create=true). They should not be directly instantiated via JNDI look up or the new operator.

6.2.2. Stateful session beans

Stateful session bean components can not only hold state across multiple invocations of the bean, but also across multiple requests. Any application state that does not belong to the database is held by stateful session beans. This is a major difference between Seam and many other web application frameworks. Current conversation data should be stored in the instance variables of a stateful session bean bound to the conversation context, rather than in the HttpSession. This feature allows Seam to manage state life cycle, and ensures that there are no collisions between states related to concurrent conversations.
Stateful session beans are often used as JSF action listeners, and as backing beans to provide properties to JSF components for display or form submission.
By default, stateful session beans are bound to the conversation context. They may never be bound to the page, or to stateless contexts.
Concurrent requests to session-scoped stateful session beans are not serialized by Seam as long as EJB 3.1 has changed that. This is a difference in comparison to previous Seam 2.2.x.
Seam stateful session bean components are instantiated with either Component.getInstance() or @In(create=true). They should not be directly instantiated via JNDI look up or the new operator.

6.2.3. Entity beans

Entity beans can function as a Seam component when bound to a context variable. As entities have a persistent identity in addition to their contextual identity, entity instances are bound explicitly in Java code, rather than being instantiated implicitly by Seam.
Entity bean components do not support bijection, context demarcation, and invocation of an entity bean trigger validation.
Entity beans are not usually used as JSF action listeners, but often function as backing beans to provide properties to JSF components for display or form submission. They are commonly used as a backing bean coupled with a stateless session bean action listener to implement create/update/delete-type functionality.
By default, entity beans are bound to the conversation context, and can never be bound to the stateless context.

Note

In a clustered environment, it is less efficient to bind an entity bean directly to a conversation (or session-scoped Seam context variable) than it is to refer to the entity bean with a stateful session bean. Not all Seam applications define entity beans as Seam components for this reason.
Seam entity bean components are instantiated with Component.getInstance() or @In(create=true), or directly instantiated with the new operator.

6.2.4. JavaBeans

JavaBeans are used similarly to stateless or stateful session beans. However, they do not provide functions such as declarative transaction demarcation, declarative security, efficient clustered state replication, EJB3 persistence, timeout methods, and so on.
A later chapter discusses the use of Seam and Hibernate without an EJB container. In this case, components are JavaBeans rather than session beans.

Note

In a clustered environment, it is less efficient to cluster conversation-scoped or session-scoped Seam JavaBean components than it is to cluster stateful session bean components.
By default, JavaBeans are bound to the event context. Seam always serializes concurrent requests to session-scoped JavaBeans.
Seam JavaBean components are instantiated with Component.getInstance() or @In(create=true). They should not be directly instantiated using the new operator.

6.2.5. Message-driven beans

Message-driven beans can function as Seam components. However, their call method differs from that of other Seam components — rather than being invoked with the context variable, they listen for messages sent to JMS queues or topics.
Message-driven beans cannot be bound to Seam contexts, nor can they access the session or conversation state of their caller. However, they do support bijection and some other Seam functionality.
Message-driven beans are never instantiated by the application; they are instantiated by the EJB container when a message is received.

6.2.6. Interception

To perform actions such as bijection, context demarcation, and validation, Seam must intercept component invocations. For JavaBeans, Seam controls component instantiation completely, and no special configuration is required. For entity beans, interception is not required, as bijection and context demarcation are not defined. For session beans, an EJB interceptor must be registered for the session bean component. This can be done with an annotation, as follows:
@Stateless @Interceptors(SeamInterceptor.class) public class LoginAction implements Login { ... }
However, it is better to define the interceptor in ejb-jar.xml:
<interceptors> 
  <interceptor> 
    <interceptor-class>
      org.jboss.seam.ejb.SeamInterceptor
    </interceptor-class> 
  </interceptor> 
</interceptors> 
<assembly-descriptor> 
  <interceptor-binding> 
    <ejb-name>*</ejb-name> 
    <interceptor-class>
      org.jboss.seam.ejb.SeamInterceptor
    </interceptor-class> 
  </interceptor-binding> 
</assembly-descriptor>

6.2.7. Component names

All Seam components require names. Assign a name with the @Name annotation:
@Name("loginAction") 
@Stateless 
public class LoginAction implements Login { ... }
This is the Seam component name, and does not relate to any other name defined by the EJB specification. However, Seam component names work like JSF managed bean names, and can be thought of in identical terms.
@Name is not the only way to define a component name, but the name must always be specified. No other Seam annotation will function if a name is not defined.
When Seam instantiates a component, it binds the new instance to a variable matching the component name in the component's configured scope. This is identical to JSF managed bean behavior, except that Seam allows you to configure this mapping with annotations rather than XML. You can also programmatically bind a component to a context variable. This is useful if a particular component serves multiple roles within the system. For example, the current User might be bound to the currentUser session context variable, while a User that is the subject of some administration functionality might be bound to the user conversation context variable. Take care when binding programmatically, because it is possible to overwrite context variables that reference Seam components.
For very large applications, and for built-in Seam components, qualified component names are often used to avoid naming conflicts.
@Name("com.jboss.myapp.loginAction") 
@Stateless 
public class LoginAction implements Login { ... }
The qualified component name can be used both in Java code and in JSF's expression language:
<h:commandButton type="submit" value="Login" 
action="#{com.jboss.myapp.loginAction.login}"/>
As this is noisy, Seam also provides a means of aliasing a qualified name to a simple name. Add a line like this to the components.xml file:
<factory name="loginAction" scope="STATELESS" value="#{com.jboss.myapp.loginAction}"/>
All built-in Seam components have qualified names, but can be accessed through their unqualified names with Seam's namespace-import feature. The components.xml file included in the Seam JAR defines the following namespaces:
<components xmlns="http://jboss.org/schema/seam/components"> 
  <import>org.jboss.seam.core</import> 
  <import>org.jboss.seam.cache</import> 
  <import>org.jboss.seam.transaction</import> 
  <import>org.jboss.seam.framework</import> 
  <import>org.jboss.seam.web</import> 
  <import>org.jboss.seam.faces</import> 
  <import>org.jboss.seam.international</import> 
  <import>org.jboss.seam.theme</import> 
  <import>org.jboss.seam.jms</import> 
  <import>org.jboss.seam.mail</import> 
  <import>org.jboss.seam.security</import> 
  <import>org.jboss.seam.security.management</import>  
  <import>org.jboss.seam.security.permission</import> 
  <import>org.jboss.seam.captcha</import> 
  <import>org.jboss.seam.excel.exporter</import> 
  <!-- ... ---> 
</components>
When attempting to resolve an unqualified name, Seam checks each of these namespaces, in order. Additional application-specific namespaces can be included in your application's components.xml file.

6.2.8. Defining the component scope

The @Scope annotation allows you to override the scope (context) of a component to define the context a component instance is bound to when instantiated by Seam.
@Name("user") 
@Entity 
@Scope(SESSION) 
public class User { ... }
org.jboss.seam.ScopeType defines an enumeration of possible scopes.

6.2.9. Components with multiple roles

Some Seam component classes can fulfill multiple roles in the system. For example, the User class is usually a session-scoped component representing the current user, but in user administration screens it becomes a conversation-scoped component. The @Role annotation allows you to define an additional named role for a component, with a different scope — it allows you to bind the same component class to different context variables. (Any Seam component instance can be bound to multiple context variables, but this allows you to do it at the class level to take advantage of automatic instantiation.)
@Name("user") 
@Entity 
@Scope(CONVERSATION) 
@Role(name="currentUser", scope=SESSION)
public class User { ... }
The @Roles annotation allows you to specify additional roles as required.
@Name("user") 
@Entity 
@Scope(CONVERSATION) 
@Roles({ @Role(name="currentUser", scope=SESSION), 
         @Role(name="tempUser", scope=EVENT)}) 
public class User { ... }

6.2.10. Built-in components

Seam is implemented as a set of built-in interceptors and components. This makes it easy for applications to interact with built-in components at runtime, or to customize basic Seam functionality by replacing the built-in components with custom implementations. The built-in components are defined in the Seam namespace org.jboss.seam.core, and in the Java package of the same name.
The built-in components may be injected like any other Seam component, but they also provide convenient static instance() methods:
FacesMessages.instance().add("Welcome back, #{user.name}!");