SeamFramework.orgCommunity Documentation

Seam


1. Seam
1.1. Overview
I. Seam Configuration
2. Seam Config Introduction
2.1. Getting Started
2.2. The Princess Rescue Example
3. Seam Config XML provider
3.1. XML Namespaces
3.2. Adding, replacing and modifying beans
3.3. Applying annotations using XML
3.4. Configuring Fields
3.4.1. Initial Field Values
3.4.2. Inline Bean Declarations
3.5. Configuring methods
3.6. Configuring the bean constructor
3.7. Overriding the type of an injection point
3.8. Configuring Meta Annotations
3.9. Virtual Producer Fields
3.10. More Information
II. Seam Persistence
4. Seam Persistence Reference
4.1. Introduction
4.2. Getting Started
4.3. Transaction Management
4.3.1. Configuration
4.3.2. Declarative Transaction Management
4.4. Seam-managed persistence contexts
4.4.1. Using a Seam-managed persistence context with JPA
4.4.2. Seam-managed persistence contexts and atomic conversations
4.4.3. Using EL in EJB-QL/HQL
4.4.4. Setting up the EntityManager
III. Seam Servlet
Introduction
5. Installation
5.1. Maven dependency configuration
5.2. Pre-Servlet 3.0 configuration
6. Servlet event propagation
6.1. Servlet context lifecycle events
6.2. Application initialization
6.3. Servlet request lifecycle events
6.4. Servlet response lifecycle events
6.5. Servlet request context lifecycle events
6.6. Session lifecycle events
6.7. Session activation events
7. Injectable Servlet objects and request state
7.1. @Inject @RequestParam
7.2. @Inject @HeaderParam
7.3. @Inject ServletContext
7.4. @Inject ServletRequest / HttpServletRequest
7.5. @Inject ServletResponse / HttpServletResponse
7.6. @Inject HttpSession
7.7. @Inject HttpSessionStatus
7.8. @Inject @ContextPath
7.9. @Inject List<Cookie>
7.10. @Inject @CookieParam
7.11. @Inject @ServerInfo
7.12. @Inject @Principal
8. Exception handling: Seam Catch integration
8.1. Background
8.2. Defining a exception handler for a web request
9. Retrieving the BeanManager from the servlet context
IV. Seam Faces
Introduction
10. Installation
10.1. Maven dependency configuration
10.2. Pre-Servlet 3.0 configuration
11. Faces Events Propagation
11.1. JSF Phase events
11.1.1. Seam Faces Phase events
11.1.2. Phase events listing
11.2. JSF system events
11.2.1. Seam Faces System events
11.2.2. System events listing
11.2.3. Component system events
12. Faces Scoping Support
12.1. @RenderScoped
12.2. @Inject javax.faces.contet.Flash flash
12.3. @ViewScoped
13. Messages API
13.1. Adding Messages
13.2. Displaying pending messages
14. Faces Artifact Injection
14.1. @*Scoped and @Inject in Validators and Converters
14.2. @Inject'able Faces Artifacts
15. Seam Faces Components
15.1. Introduction
15.2. <s:validateForm>
15.3. <s:viewAction>
15.3.1. Motivation
15.3.2. Usage
15.3.3. View actions vs the PreRenderViewEvent
15.4. UI Input Container
V. Seam International
Introduction
16. Installation
17. Locales
17.1. Default Locale
17.2. User Locale
17.3. Available Locales
18. Timezones
18.1. Default TimeZone
18.2. User TimeZone
18.3. Available TimeZones
19. Messages
VI. Seam Catch
20. Seam Catch - Introduction
21. Seam Catch - Installation
21.1. Maven dependency configuration
22. Seam Catch - Usage
22.1. Exception handlers
22.2. Exception handler annotations
22.2.1. @HandlesExceptions
22.2.2. @Handles
22.3. Exception stack trace processing
22.4. Exception handler ordering
22.4.1. Traversal of exception type hierarchy
22.4.2. Handler precendence
22.5. APIs for exception information and flow control
22.5.1. CaughtException
22.5.2. ExceptionStack
23. Seam Catch - Framework Integration
23.1. Creating and Firing an ExceptionToCatch event
23.2. Default Handlers and Qualifiers
23.2.1. Default Handlers
23.2.2. Qualifiers
23.3. Supporting ServiceHandlers
Seam Catch - Glossary
VII. Seam Remoting
24. Seam Remoting - Basic Features
24.1. Configuration
24.1.1. Dynamic type loading
24.2. The "Seam" object
24.2.1. A Hello World example
24.2.2. Seam.createBean
24.3. The Context
24.3.1. Setting and reading the Conversation ID
24.3.2. Remote calls within the current conversation scope
24.4. Working with Data types
24.4.1. Primitives / Basic Types
24.4.2. JavaBeans
24.4.3. Dates and Times
24.4.4. Enums
24.4.5. Collections
24.5. Debugging
24.6. Handling Exceptions
24.7. The Loading Message
24.7.1. Changing the message
24.7.2. Hiding the loading message
24.7.3. A Custom Loading Indicator
24.8. Controlling what data is returned
24.8.1. Constraining normal fields
24.8.2. Constraining Maps and Collections
24.8.3. Constraining objects of a specific type
24.8.4. Combining Constraints
25. Seam Remoting - Model API
25.1. Introduction
25.2. Model Operations
25.3. Fetching a model
25.3.1. Fetching a bean value
25.4. Modifying model values
25.5. Expanding a model
25.6. Applying Changes
26. Seam Remoting - Bean Validation
26.1. Validating a single object
26.2. Validating a single property
26.3. Validating multiple objects and/or properties
26.4. Validation groups
26.5. Handling validation failures
VIII. Seam Rest
Introduction
27. Installation
27.1. Basics
27.2. Transitive dependencies
27.3. Registering JAX-RS components explicitly
28. Exception Handling
28.1. Seam Catch Integration
28.2. Declarative Exception Mapping
28.2.1. Annotation-based configuration
28.2.2. XML configuration
28.2.3. Declarative exception mapping processing
29. Bean Validation Integration
29.1. Validating HTTP requests
29.1.1. Validating entity body
29.1.2. Validating resource fields
29.1.3. Validating other method parameters
29.2. Validation configuration
29.3. Using validation groups
30. Templating support
30.1. Creating JAX-RS responses using templates
30.1.1. Accessing the model
30.2. Built-in support for templating engines
30.2.1. FreeMarker
30.2.2. Apache Velocity
30.2.3. Pluggable support for templating engines
30.2.4. Selecting prefered templating engine
31. RESTEasy Client Framework Integration
31.1. Using RESTEasy Client Framework with Seam REST
31.2. Manual ClientRequest API
31.3. ClientExecutor Configuration
32. Seam REST Dependencies
32.1. Transitive Dependencies
32.2. Optional dependencies
32.2.1. Seam Catch
32.2.2. Seam Config
32.2.3. FreeMarker
32.2.4. Apache Velocity
32.2.5. RESTEasy
IX. Seam Wicket
Introduction
33. Installation
34. Seam for Apache Wicket Features
34.1. Injection
34.2. Conversation Control
34.3. Conversation Propagation
X. Seam Solder
35. Getting Started
35.1. Maven dependency configuration
35.2. Transitive dependencies
35.3. Pre-Servlet 3.0 configuration
36. Enhancements to the CDI Programming Model
36.1. Preventing a class from being processed
36.1.1. @Veto
36.1.2. @Requires
36.2. @Exact
36.3. @Client
36.4. Named packages
36.5. @FullyQualified bean names
37. Annotation Literals
38. Evaluating Unified EL
39. Resource Loading
39.1. Extending the resource loader
40. Logging
41. Annotation and AnnotatedType Utilities
41.1. Annotated Type Builder
41.2. Annotation Instance Provider
41.3. Annotation Inspector
41.4. Synthetic Qualifiers
41.5. Reflection Utilities
42. Obtaining a reference to the BeanManager
43. Bean Utilities
44. Properties
44.1. Working with properties
44.2. Querying for properties
44.3. Property Criteria
44.3.1. AnnotatedPropertyCriteria
44.3.2. NamedPropertyCriteria
44.3.3. TypedPropertyCriteria
44.3.4. Creating a custom property criteria
44.4. Fetching the results
45. Unwrapping Producer Methods
46. Default Beans
47. Generic Beans
47.1. Using generic beans
47.2. Defining Generic Beans
48. Service Handler

Seam provides a method for configuring JSR-299 beans using alternate metadata sources, such as XML configuration. (Currently, the XML provider is the only alternative available, though others are planned). Using a "type-safe" XML syntax, it's possible to add new beans, override existing beans, and add extra configuration to existing beans.

No special configuration is required, all that is required is to include the JAR file and the Seam Solder JAR in your project. For Maven projects, that means adding the following dependencies to your pom.xml:



         <dependency>
            <groupId>org.jboss.seam.config</groupId>
            <artifactId>seam-config-xml</artifactId>
            <version>${seam.config.version}</version>
            <scope>runtime</scope>
         </dependency>

         <dependency>
            <groupId>org.jboss.seam.solder</groupId>
            <artifactId>seam-solder</artifactId>
            <version>${weld.extensions.version}</version>
         </dependency>
      

To take advantage of Seam Config, the first thing we need is some metadata sources in the form of XML files. By default these are discovered from the classpath in the following locations:

The beans.xml file is the preferred way of configuring beans via XML, however it may be possible that some JSR-299 implementations will not allow this, so seam-beans.xml is provided as an alternative.

Let's start with a simple example. Say we have the following class that represents a report:

class Report {

    String filename;
    
    @Inject
    Datasource datasource;
    
    //getters and setters
}

And the following support classes:

interface Datasource {

    public Data getData();
}
@SalesQualifier
class SalesDatasource implements Datasource {
  public Data getData()
  {
    //return sales data
  }
}
class BillingDatasource implements Datasource {
  public Data getData()
  {
    //return billing data
  }
}

Our Report bean is fairly simple. It has a filename that tells the report engine where to load the report definition from, and a datasource that provides the data used to fill the report. We are going to configure up multiple Report beans via xml.

Example 2.1. 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s(1)="urn:java:ee" 
       xmlns:r(2)="urn:java:org.example.reports">

 	<r:Report>  (3)
 		<s:modifies(4)/>
 		<r:filename(5)>sales.jrxml<r:filename>
 		<r:datasource>
 			<r:SalesQu(6)alifier/>
 		</r:datasource>
  	</r:Report>
  	
 	<r:Report fi(7)lename="billing.jrxml">
 		<s:replaces(8)/>
 		<r:datasource>
 			<s:Inject/(9)>
 			<s:Exact>o(10)rg.example.reports.BillingDatasource</s:Exact>
 		</r:datasource>
  	</r:Report>  	
</beans>
    
         

1

The namespace urn:java:ee is Seam Config's root namespace. This is where the built-in elements and CDI annotations live.

2

There are now multiple namespaces in the beans.xml file. These namespaces correspond to java package names.

The namespace urn:java:org.example.reports corresponds to the package org.example.reports, where our reporting classes live. Multiple java packages can be aggregated into a single namespace declaration by seperating the package names with colons, e.g. urn:java:org.example.reports:org.example.model. The namespaces are searched in the order they are specified in the xml document, so if two packages in the namespace have a class with the same name, the first one listed will be resolved. For more information see Namespaces.

3

The <Report> declaration configures an instance of our Report class as a bean.

4

Beans installed using <s:modifies> read annotations from the existing class, and merge them with the annotations defined via xml. In addition if a bean is installed with <s:modifies> it prevents the original class being installed as a bean. It is also possible to add new beans and replace beans altogether, for more information see Adding, modifying and replacing beans.

5

The <r:filename> element sets the initial value of the filename field. For more information on how methods and fields are resolved see Configuring Methods, and Configuring Fields.

6

The <r:SalesQualifier> element applies the @SalesQualifier to the datasource field. As the field already has an @Inject on the class definition this will cause the SalesDatasource bean to be injected.

7

This is the shorthand syntax for setting a field value.

8

Beans installed using <s:replaces> do not read annotations from the existing class. In addition if a bean is installed with <s:replaces> it prevents the original class being installed as a bean.

9

The <s:Inject> element is needed this bean was installed with <s:replaces>, so annotations are not read from the class definition.

10

The <s:Exact> annotation restricts the type of bean that is availible for injection without using qualifiers. In this case BillingDatasource will be injected. This is provided as part of weld-extensions.


It is possible to both apply qualifiers to and set the initial value of a field. Fields reside in the same namespace as the declaring bean, and the element name must exactly match the field name. For example if we have the following class:

class RobotFactory {

  Robot robot;
}

The following xml will add the @Produces annotation to the robot field:


<my:RobotFactory>
  <my:robot>
    <s:Produces/>
  </my:robot>
</my:RobotFactory/>

Inital field values can be set three different ways as shown below:


<r:MyBean company="Red Hat Inc" />

<r:MyBean>
  <r:company>Red Hat Inc</r:company>
</r:MyBean>

<r:MyBean>
  <r:company>
    <s:value>Red Hat Inc<s:value>
    <r:SomeQualifier/>
  </r:company>
</r:MyBean>

The third form is the only one that also allows you to add annotations such as qualifiers to the field.

It is possible to set Map,Array and Collection field values. Some examples:


<my:ArrayFieldValue>

    <my:intArrayField>
        <s:value>1</s:value>
        <s:value>2</s:value>
    </my:intArrayField>
    
    <my:classArrayField>
        <s:value>java.lang.Integer</s:value>
        <s:value>java.lang.Long</s:value>
    </my:classArrayField>
    
    <my:stringArrayField>
        <s:value>hello</s:value>
        <s:value>world</s:value>
    </my:stringArrayField>
    
</my:ArrayFieldValue>

<my:MapFieldValue>

    <my:map1>
        <s:entry><s:key>1</s:key><s:value>hello</s:value></s:entry>
        <s:entry><s:key>2</s:key><s:value>world</s:value></s:entry>
    </my:map1>
    
    <my:map2>
        <s:e><s:k>1</s:k><s:v>java.lang.Integer</s:v></s:e>
        <s:e><s:k>2</s:k><s:v>java.lang.Long</s:v></s:e>
    </my:map2>
    
</my:MapFieldValue>

Type conversion is done automatically for all primitives and primitive wrappers, Date, Calendar,Enum and Class fields.

The use of EL to set field values is also supported:


<m:Report>
   <m:name>#{reportName}</m:name>
   <m:parameters>
      <s:key>#{paramName}</s:key>
      <s:value>#{paramValue}</s:key>
   </m:parameters>
</m:Report>

Internally field values are set by wrapping the InjectionTarget for a bean. This means that the expressions are evaluated once, at bean creation time.

It is also possible to configure methods in a similar way to configuring fields:

class MethodBean {


   public int doStuff() {
      return 1;
   }
   public int doStuff(MethodValueBean bean) {
      return bean.value + 1;
   }
   
   public void doStuff(MethodValueBean[][] beans) {
      /*do stuff */
   }
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:s="urn:java:ee" 
       xmlns:my="urn:java:org.jboss.seam.config.xml.test.method">
    <my:MethodBean>
    
        <my:doStuff>
            <s:Produces/>
        </my:doStuff>
        
        <my:doStuff>
            <s:Produces/>
            <my:Qualifier1/>
            <s:parameters>
                <my:MethodValueBean>
                    <my:Qualifier2/>
                </my:MethodValueBean>
            </s:parameters>
        </my:doStuff>
        
        <my:doStuff>
            <s:Produces/>
            <my:Qualifier1/>
            <s:parameters>
                <s:array dimensions="2">
                    <my:Qualifier2/>
                    <my:MethodValueBean/>
                </s:array>
            </s:parameters>
        </my:doStuff>
        
    </my:MethodBean>
</beans>

In this instance MethodBean has three methods, all of them rather imaginatively named doStuff.

The first <test:doStuff> entry in the XML file configures the method that takes no arguments. The <s:Produces> element makes it into a producer method.

The next entry in the file configures the method that takes a MethodValueBean as a parameter and the final entry configures a method that takes a two dimensional array ofMethodValueBean's as a parameter. For both these methods a qualifier was added to the method parameter and they were made into producer methods.

Method parameters are specified inside the <s:parameters> element. If these parameters have annotation children they are taken to be annotations on the parameter.

The corresponding Java declaration for the XML above would be:

class MethodBean {

            
    @Produces
    public int doStuff() {/*method body */}            
                
    @Produces
    @Qualifier1
    public int doStuff(@Qualifier2 MethodValueBean param) {/*method body */}
    
    @Produces
    @Qualifier1
    public int doStuff(@Qualifier2 MethodValueBean[][] param) {/*method body */}
}

Array parameters can be represented using the <s:array> element, with a child element to represent the type of the array. E.g. int method(MethodValueBean[] param); could be configured via xml using the following:


<my:method>
    <s:array>
      <my:MethodValueBean/>
    </s:array>
</my:method>
      

Seam provides extensive support for the two most popular persistence architectures for Java: Hibernate3, and the Java Persistence API introduced with EJB 3.0. Seam's unique state-management architecture allows the most sophisticated ORM integration of any web application framework.

Seam grew out of the frustration of the Hibernate team with the statelessness typical of the previous generation of Java application architectures. The state management architecture of Seam was originally designed to solve problems relating to persistence — in particular problems associated with optimistic transaction processing. Scalable online applications always use optimistic transactions. An atomic (database/JTA) level transaction should not span a user interaction unless the application is designed to support only a very small number of concurrent clients. But almost all interesting work involves first displaying data to a user, and then, slightly later, updating the same data. So Hibernate was designed to support the idea of a persistence context which spanned an optimistic transaction.

Unfortunately, the so-called "stateless" architectures that preceded Seam and EJB 3.0 had no construct for representing an optimistic transaction. So, instead, these architectures provided persistence contexts scoped to the atomic transaction. Of course, this resulted in many problems for users, and is the cause of the number one user complaint about Hibernate: the dreaded LazyInitializationException. What we need is a construct for representing an optimistic transaction in the application tier.

EJB 3.0 recognizes this problem, and introduces the idea of a stateful component (a stateful session bean) with an extended persistence context scoped to the lifetime of the component. This is a partial solution to the problem (and is a useful construct in and of itself) however there are two problems:

Seam solves the first problem by providing conversations, and stateful session bean components scoped to the conversation. (Most conversations actually represent optimistic transactions in the data layer.) This is sufficient for many simple applications (such as the Seam booking demo) where persistence context propagation is not needed. For more complex applications, with many loosly-interacting components in each conversation, propagation of the persistence context across components becomes an important issue. So Seam extends the persistence context management model of EJB 3.0, to provide conversation-scoped extended persistence contexts.

Unlike EJB session beans CDI beans are not transactional by default. Seam brings declarative transaction management to CDI beans by enabling them to use @TransactionAttribute. Seam also provides the @Transactional annotation, for environments where java EE APIs are not present.

In order to enable declarative transaction management for managed beans you need to list the transaction interceptor in beans.xml:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://docs.jboss.org/cdi/beans_1_0.xsd">
   <interceptors>
      <class>org.jboss.seam.persistence.transaction.TransactionInterceptor</class>
   </interceptors>
</beans>

If you are in a Java EE 6 environment then you are good to go, no additional configuration is required.

If you are not in a Java EE environment you may need to configure some things with seam-xml. You may need the following entries in your beans.xml file:


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:ee" 
   xmlns:t="urn:java:org.jboss.seam.persistence.transaction"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://docs.jboss.org/cdi/beans_1_0.xsd">

      <t:SeSynchronizations>
         <s:modifies/>
      </t:SeSynchronizations>

      <t:EntityTransaction>
         <s:modifies />         
      </t:EntityTransaction>
      
</beans>

Lets look at these individually.


<t:SeSynchronizations>
  <s:modifies/>
</t:SeSynchronizations>

Seam will attempt to use JTA synchronizations if possible. If not then you need to install the SeSynchronzations bean to allow seam to handle synchronizations manually. Synchronizations allow seam to respond to transaction events such as beforeCompletion() and afterCompletion(), and are needed for the proper operation of the Seam Managed Persistence Context.


<t:EntityTransaction>
   <s:modifies />         
</t:EntityTransaction>

By default seam will attempt to look up java:comp/UserTransaction from JNDI (or alternatively retrieve it from the EJBContext if a container managed transaction is active). Installing EntityTransaction tells seam to use the JPA EntityTransaction instead. To use this you must have a Seam Managed Persistence Context installed with qualifier @Default.

TODO: document how to use different qualifiers.

Note

You should avoid EntityTransaction if you have more than one persistence unit in your application. Seam does not support installing multiple EntityTransaction beans, and the EntityTransaction interface does not support two phase commit, so unless you are careful you may have data consistency issues. If you need multiple persistence units in your application then we highly recommend using a Java EE 6 compatible server, such as Jboss 6.

Seam adds declarative transaction support to managed beans. Seam re-uses the EJB @TransactionAttribute for this purpose, however it also provides an alternative @Transactional annotation for environments where the EJB APIs are not available. An alternative to @ApplicationException, @SeamApplicationException is also provided. Unlike EJBs, managed beans are not transactional by default, you can change this by adding the @TransactionAttribute to the bean class.

TODO: Add section on exceptions and transaction rollback

If you are using seam managed transactions as part of the seam-faces module you do not need to worry about declarative transaction management. Seam will automatically start a transaction for you at the start of the faces request, and commit it before the render response phase.

Let's have a look at some code. Annotations applied at a method level override annotations applied at the class level.

@TransactionAttribute /*Defaults to TransactionAttributeType.REQUIRED */

class TransactionaBean
{
   /* This is a transactional method, when this method is called a transaction
    * will be started if one does not already exist.
    * This behavior is inherited from the @TransactionAttribute annotation on
    * the class.
    */
    void doWork()
    {
      ...
    }
    
    /* A transaction will not be started for this method, however it      */
    /* will not complain if there is an existing transaction active.      */
    @TransactionAttributeType(TransactionAttributeType.SUPPORTED)
    void doMoreWork()
    {
      ...
    }
    
    /* This method will throw an exception if there is no transaction active when */
    /* it is invoked.                                                             */
     
    @TransactionAttributeType(TransactionAttributeType.MANDATORY)
    void doEvenMoreWork()
    {
      ...
    }  
    
    /* This method will throw an exception if there is a transaction active when */
    /* it is invoked.                                                            */
    @TransactionAttributeType(TransactionAttributeType.NOT_SUPPORTED)
    void doOtherWork()
    {
      ...
    }
}         

If you're using Seam outside of a Java EE environment, you can't rely upon the container to manage the persistence context lifecycle for you. Even if you are in an EE environment, you might have a complex application with many loosely coupled components that collaborate together in the scope of a single conversation, and in this case you might find that propagation of the persistence context between component is tricky and error-prone.

In either case, you'll need to use a managed persistence context (for JPA) or a managed session (for Hibernate) in your components. A Seam-managed persistence context is just a built-in Seam component that manages an instance of EntityManager or Session in the conversation (or any other) context. You can inject it with @Inject.

@SeamManaged
@Produces
@PersistenceUnit
@ConversationScoped
EntityManagerFactory producerField;
         

This is just an ordinary resource producer field as defined by the CDI specification, however the presence of the @SeamManaged annotation tells seam to create a seam managed persistence context from this EntityManagerFactory. This managed persistence context can be injected normally, and has the same scope and qualifiers that are specified on the resource producer field.

This will work even in a SE environment where @PersistenceUnit injection is not normally supported. This is because the seam persistence extensions will bootstrap the EntityManagerFactory for you.

Now we can have our EntityManager injected using:

@Inject EntityManager entityManager;

Persistence contexts scoped to the conversation allows you to program optimistic transactions that span multiple requests to the server without the need to use the merge() operation , without the need to re-load data at the beginning of each request, and without the need to wrestle with the LazyInitializationException or NonUniqueObjectException.

As with any optimistic transaction management, transaction isolation and consistency can be achieved via use of optimistic locking. Fortunately, both Hibernate and EJB 3.1 make it very easy to use optimistic locking, by providing the @Version annotation.

By default, the persistence context is flushed (synchronized with the database) at the end of each transaction. This is sometimes the desired behavior. But very often, we would prefer that all changes are held in memory and only written to the database when the conversation ends successfully. This allows for truly atomic conversations. Unfortunately there is currently no simple, usable and portable way to implement atomic conversations using EJB 3.1 persistence. However, Hibernate provides this feature as a vendor extension to the FlushModeTypes defined by the specification, and it is our expectation that other vendors will soon provide a similar extension.

Seam lets you specify FlushModeType.MANUAL when beginning a conversation. Currently, this works only when Hibernate is the underlying persistence provider, but we plan to support other equivalent vendor extensions.

TODO: The next section needs to be updated to seam 3.

@Inject EntityManager em; //Seam-managed persistence context

   
   @Begin(flushMode=MANUAL)
   public void beginClaimWizard() {
       claim = em.find(Claim.class, claimId);
   }

Now, the claim object remains managed by the persistence context for the rest of the conversation. We can make changes to the claim:

public void addPartyToClaim() {

       Party party = ....;
       claim.addParty(party);
   }

But these changes will not be flushed to the database until we explicitly force the flush to occur:

@End

   public void commitClaim() {
       em.flush();
   }

Of course, you could set the flushMode to MANUAL from pages.xml, for example in a navigation rule:


<begin-conversation flush-mode="MANUAL" />

You can set any Seam Managed Persistence Context to use manual flush mode:

<components xmlns="http://jboss.com/products/seam/components"
            xmlns:core="http://jboss.com/products/seam/core">
            <core:manager conversation-timeout="120000" default-flush-mode="manual" />
         </components>

To use the Seam Servlet module, you need to put the API and implementation JARs on the classpath of your web application. Most of the features of Seam Servlet are enabled automatically when it's added to the classpath. Some extra configuration, covered below, is required if you are not using a Servlet 3-compliant container.

If you are using Maven as your build tool, you can add the following single dependency to your pom.xml file to include Seam Servlet:


<dependency>
   <groupId>org.jboss.seam.servlet</groupId>
   <artifactId>seam-servlet</artifactId>
   <version>${seam.servlet.version}</version>
</dependency>

Tip

Substitute the expression ${seam.servlet.version} with the most recent or appropriate version of Seam Servlet. Alternatively, you can create a Maven user-defined property to satisfy this substitution so you can centrally manage the version.

Alternatively, you can use the API at compile time and only include the implementation at runtime. This protects you from inadvertantly depending on an implementation class.


<dependency>
   <groupId>org.jboss.seam.servlet</groupId>
   <artifactId>seam-servlet-api</artifactId>
   <version>${seam.servlet.version}</version>
   <scope>compile</scope>
</dependency>

<dependency>
   <groupId>org.jboss.seam.servlet</groupId>
   <artifactId>seam-servlet-impl</artifactId>
   <version>${seam.servlet.version}</version>
   <scope>runtime</scope>
</dependency>

If you are deploying to a platform other than JBoss AS, you also need to add the JBoss Logging implementation (a portable logging abstraction).


<dependency>
   <groupId>org.jboss.logging</groupId>
   <artifactId>jboss-logging</artifactId>
   <version>3.0.0.Beta4</version>
   <scope>compile</scope>
</dependency>

In a Servlet 3.0 or Java EE 6 environment, your configuration is now complete!

You're now ready to dive into the Servlet enhancements provided for you by the Seam Servlet module!

By including the Seam Servlet module in your web application (and performing the necessary listener configuration for pre-Servlet 3.0 environments), the servlet lifecycle events will be propagated to the CDI event bus so you can observe them using observer methods on CDI beans. Seam Servlet also fires additional lifecycle events not offered by the Servlet API, such as when the response is initialized and destroyed.

This category of events corresponds to the event receivers on the javax.servlet.ServletContextListener interface. The event propagated is a javax.servlet.ServletContext (not a javax.servlet.ServletContextEvent, since the ServletContext is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.seam.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet context.

The servlet context lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletContextThe servlet context is initialized or destroyed
@Initializedjavax.servlet.ServletContextThe servlet context is initialized
@Destroyedjavax.servlet.ServletContextThe servlet context is destroyed

If you want to listen to both lifecycle events, leave out the qualifiers on the observer method:

public void observeServletContext(@Observes ServletContext ctx) {

   System.out.println(ctx.getServletContextName() + " initialized or destroyed");
}

If you are interested in only a particular lifecycle phase, use one of the provided qualifers:

public void observeServletContextInitialized(@Observes @Initialized ServletContext ctx) {

   System.out.println(ctx.getServletContextName() + " initialized");
}

As with all CDI observers, the name of the method is insignificant.

These events are fired using a built-in servlet context listener. The CDI environment will be active when these events are fired (including when Weld is used in a Servlet container). The listener is configured to come before listeners in other extensions, so the initialized event is fired before other servlet context listeners are notified and the destroyed event is fired after other servlet context listeners are notified. However, this order cannot be not guaranteed if another extension library is also configured to be ordered before others.

The servlet context initialized event described in the previous section provides an ideal opportunity to perform startup logic as an alterative to using an EJB 3.1 startup singleton. Even better, you can configure the bean to be destroyed immediately following the initialization routine by leaving it as dependent scoped (dependent-scoped observers only live for the duration of the observe method invocation).

Here's an example of entering seed data into the database in a development environment (as indicated by a stereotype annotation named @Development).

@Stateless

@Development
public class SeedDataImporter {
   @PersistenceContext
   private EntityManager em;
   public void loadData(@Observes @Initialized ServletContext ctx) {
      em.persist(new Product(1, "Black Hole", 100.0));
   }
}

If you'd rather not tie yourself to the Servlet API, you can observe the org.jboss.seam.servlet.WebApplication rather than the ServletContext. WebApplication is a informational object provided by Seam Servlet that holds select information about the ServletContext such as the application name, context path, server info and start time.

The web application lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)WebApplicationThe web application is initialized, started or destroyed
@InitializedWebApplicationThe web application is initialized
@StartedWebApplicationThe web application is started (ready)
@DestroyedWebApplicationThe web application is destroyed

Here's the equivalent of receiving the servlet context initialized event without coupling to the Servlet API:

public void loadData(@Observes @Initialized WebApplication webapp) {

   System.out.println(webapp.getName() + " initialized at " + new Date(webapp.getStartTime()));
}

If you want to perform initialization as late as possible, after all other initialization of the application is complete, you can observe the WebApplication event qualified with @Started.

public void onStartup(@Observes @Started WebApplication webapp) {

   System.out.println("Application at " + webapp.getContextPath() + " ready to handle requests");
}

The @Started event is fired in the init method of a built-in Servlet with a load-on-startup value of 1000.

You can also use WebApplication with the @Destroyed qualifier to be notified when the web application is stopped. This event is fired by the aforementioned built-in Servlet during it's destroy method, so likely it should fire when the application is first released.

public void onShutdown(@Observes @Destroyed WebApplication webapp) {

   System.out.println("Application at " + webapp.getContextPath() + " no longer handling requests");
}

This category of events corresponds to the event receivers on the javax.servlet.ServletRequestListener interface. The event propagated is a javax.servlet.ServletRequest (not a javax.servlet.ServletRequestEvent, since the ServletRequest is the only relevant information this event provides).

There are two qualifiers provided in the org.jboss.seam.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet request and a secondary qualifier to filter events by servlet path (@Path).

The servlet request lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletRequestA servlet request is initialized or destroyed
@Initializedjavax.servlet.ServletRequestA servlet request is initialized
@Destroyedjavax.servlet.ServletRequestA servlet request is destroyed
@Default (optional)javax.servlet.http.HttpServletRequestAn HTTP servlet request is initialized or destroyed
@Initializedjavax.servlet.http.HttpServletRequestAn HTTP servlet request is initialized
@Destroyedjavax.servlet.http.HttpServletRequestAn HTTP servlet request is destroyed
@Path(PATH)javax.servlet.http.HttpServletRequestSelects HTTP request with servlet path matching PATH (drop leading slash)

If you want to listen to both lifecycle events, leave out the qualifiers on the observer:

public void observeRequest(@Observes ServletRequest request) {

   // Do something with the servlet "request" object
}

If you are interested in only a particular lifecycle phase, use a qualifer:

public void observeRequestInitialized(@Observes @Initialized ServletRequest request) {

   // Do something with the servlet "request" object upon initialization
}

You can also listen specifically for a javax.servlet.http.HttpServletRequest simply by changing the expected event type.

public void observeRequestInitialized(@Observes @Initialized HttpServletRequest request) {

   // Do something with the HTTP servlet "request" object upon initialization
}

You can associate an observer with a particular servlet request path (exact match, no leading slash).

public void observeRequestInitialized(@Observes @Initialized @Path("offer") HttpServletRequest request) {

   // Do something with the HTTP servlet "request" object upon initialization
   // only when servlet path /offer is requested
}

As with all CDI observers, the name of the method is insignificant.

These events are fired using a built-in servlet request listener. The listener is configured to come before listeners in other extensions, so the initialized event is fired before other servlet request listeners are notified and the destroyed event is fired after other servlet request listeners are notified. However, this order cannot be not guaranteed if another extension library is also configured to be ordered before others.

The Servlet API does not provide a listener for accessing the lifecycle of a response. Therefore, Seam Servlet simulates a response lifecycle listener using CDI events. The event object fired is a javax.servlet.ServletResponse.

There are two qualifiers provided in the org.jboss.seam.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet response and a secondary qualifier to filter events by servlet path (@Path).

The servlet response lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)javax.servlet.ServletResponseA servlet response is initialized or destroyed
@Initializedjavax.servlet.ServletResponseA servlet response is initialized
@Destroyedjavax.servlet.ServletResponseA servlet response is destroyed
@Default (optional)javax.servlet.http.HttpServletResponseAn HTTP servlet response is initialized or destroyed
@Initializedjavax.servlet.http.HttpServletResponseAn HTTP servlet response is initialized
@Destroyedjavax.servlet.http.HttpServletResponseAn HTTP servlet response is destroyed
@Path(PATH)javax.servlet.http.HttpServletResponseSelects HTTP response with servlet path matching PATH (drop leading slash)

If you want to listen to both lifecycle events, leave out the qualifiers.

public void observeResponse(@Observes ServletResponse response) {

   // Do something with the servlet "response" object
}

If you are interested in only a particular one, use a qualifer

public void observeResponseInitialized(@Observes @Initialized ServletResponse response) {

   // Do something with the servlet "response" object upon initialization
}

You can also listen specifically for a javax.servlet.http.HttpServletResponse simply by changing the expected event type.

public void observeResponseInitialized(@Observes @Initialized HttpServletResponse response) {

   // Do something with the HTTP servlet "response" object upon initialization
}

If you need access to the ServletRequest and/or the ServletContext objects at the same time, you can simply add them as parameters to the observer methods. For instance, let's assume you want to manually set the character encoding of the request and response.

public void setupEncoding(@Observes @Initialized ServletResponse res, ServletRequest req) throws Exception {

   if (this.override || req.getCharacterEncoding() == null) {
      req.setCharacterEncoding(encoding);
      if (override) {
         res.setCharacterEncoding(encoding);
      }
   }
}

As with all CDI observers, the name of the method is insignificant.

Rather than having to observe the request and response as separate events, or include the request object as an parameter on a response observer, it would be convenient to be able to observe them as a pair. That's why Seam Servlet fires an synthetic lifecycle event for the wrapper type ServletRequestContext. The ServletRequestContext holds the ServletRequest and the ServletResponse objects, and also provides access to the ServletContext.

There are two qualifiers provided in the org.jboss.seam.servlet.event package (@Initialized and @Destroyed) that can be used to observe a specific lifecycle phase of the servlet request context and a secondary qualifier to filter events by servlet path (@Path).

The servlet request context lifecycle events are documented in the table below.

QualifierTypeDescription
@Default (optional)ServletRequestContextA request is initialized or destroyed
@InitializedServletRequestContextA request is initialized
@DestroyedServletRequestContextA request is destroyed
@Default (optional)HttpServletRequestContextAn HTTP request is initialized or destroyed
@InitializedHttpServletRequestContextAn HTTP request is initialized
@DestroyedHttpServletRequestContextAn HTTP request is destroyed
@Path(PATH)HttpServletRequestContextSelects HTTP request with servlet path matching PATH (drop leading slash)

Let's revisit the character encoding observer and examine how it can be simplified by this event:

public void setupEncoding(@Observes @Initialized ServletRequestContext ctx) throws Exception {

   if (this.override || ctx.getRequest().getCharacterEncoding() == null) {
      ctx.getRequest().setCharacterEncoding(encoding);
      if (override) {
         ctx.getResponse().setCharacterEncoding(encoding);
      }
   }
}

You can also observe the HttpServletRequestContext to be notified only on HTTP requests.

Since observers that have access to the response can commit it, an HttpServletRequestContext observer that receives the initialized event can effectively work as a filter or even a Servlet. Let's consider a primitive welcome page filter that redirects visitors to the start page:

public void redirectToStartPage(@Observes @Path("") @Initialized HttpServletRequestContext ctx)

      throws Exception {
   String startPage = ctx.getResponse().encodeRedirectURL(ctx.getContextPath() + "/start.jsf");
   ctx.getResponse().sendRedirect(startPage);
}

Now you never have to write a Servlet listener, Servlet or Filter again!

Seam Servlet provides producers that expose a wide-range of information available in a Servlet environment (e.g., implicit objects such as ServletContext and HttpSession and state such as HTTP request parameters) as beans. You access this information by injecting the beans produced. This chapter documents the Servlet objects and request state that Seam Servlet exposes and how to inject them.

The @RequestParam qualifier allows you to inject an HTTP request parameter (i.e., URI query string or URL form encoded parameter).

Assume a request URL of /book.jsp?id=1.

@Inject @RequestParam("id")

private String bookId;

The value of the specified request parameter is retrieved using the method ServletRequest.getParameter(String). It is then produced as a dependent-scoped bean of type String qualified @RequestParam.

The name of the request parameter to lookup is either the value of the @RequestParam annotation or, if the annotation value is empty, the name of the injection point (e.g., the field name).

Here's the example from above modified so that the request parameter name is implied from the field name:

@Inject @RequestParam

private String id;

If the request parameter is not present, and the injection point is annotated with @DefaultValue, the value of the @DefaultValue annotation is returned instead.

Here's an example that provides a fall-back value:

@Inject @RequestParam @DefaultValue("25")

private String pageSize;

If the request parameter is not present, and the @DefaultValue annotation is not present, a null value is injected.

Seam Catch provides a simple, yet robust foundation for modules and/or applications to establish a customized exception handling process. Seam Servlet ties into the exception handling model by forwarding all unhandled Servlet exceptions to Catch so that they can be handled in a centralized, extensible and uniform manner.

You can define an exception handler for a web request using the normal syntax of a Catch exception handler. Let's catch any exception that bubbles to the top and respond with a 500 error.

@HandlesExceptions

public class ExceptionHandlers {
   void handleAll(@Handles CaughtException<Throwable> caught, HttpServletResponse response) {
      response.sendError(500, "You've been caught by Catch!"); 
   }
}

That's all there is to it! If you only want this handler to be used for exceptions raised by a web request (excluding web service requests like JAX-RS), then you can add the @WebRequest qualifier to the handler:

@HandlesExceptions

public class ExceptionHandlers {
   void handleAll(@Handles @WebRequest
         CaughtException<Throwable> caught, HttpServletResponse response) {
      response.sendError(500, "You've been caught by Catch!"); 
   }
}

Let's consider another example. When the custom AccountNotFound exception is thrown, we'll send a 404 response using this handler.

void handleAccountNotFound(@Handles @WebRequest

      CaughtException<AccountNotFound> caught, HttpServletResponse response) {
   response.sendError(404, "Account not found: " + caught.getException().getAccountId()); 
}

In a future release, Seam Servlet will include annotations that can be used to configure these responses declaratively.

Typically, the BeanManager is obtained using some form of injection. However, there are scenarios where the code being executed is outside of a managed bean environment and you need a way in. In these cases, it's necessary to lookup the BeanManager from a well-known location.

The standard mechanism for locating the BeanManager from outside a managed bean environment, as defined by the JSR-299 specification, is to look it up in JNDI. However, JNDI isn't the most convenient technology to depend on when you consider all popular deployment environments (think Tomcat and Jetty).

As a simpler alternative, Seam Servlet binds the BeanManager to the following servlet context attribute (whose name is equivalent to the fully-qualified class name of the BeanManager interface:

javax.enterprise.inject.spi.BeanManager

Seam Servlet also includes a provider that retrieves the BeanManager from this location. Anytime the Seam Servlet module needs a reference to the BeanManager, it uses this lookup mechanism to ensure that the module works consistently across deployment environments, especially in Servlet containers.

You can retrieve the BeanManager in the same way. If you want to hide the lookup, you can extend the BeanManagerAware class and retrieve the BeanManager from the the method getBeanManager(), as shown here:



public class NonManagedClass extends BeanManagerAware {
   public void fireEvent() {
      getBeanManager().fireEvent("Send me to a managed bean");
   }
}
   

Alternatively, you can retrieve the BeanManager from the method getBeanManager() on the BeanManagerLocator class, as shown here:



public class NonManagedClass {
   public void fireEvent() {
      new BeanManagerLocator().getBeanManager().fireEvent("Send me to a managed bean");
   }
}
   

Under the covers, these classes look for the BeanManager in the servlet context attribute covered in this section, amongst other available strategies. Refer to the BeanManager provider chapter of the Seam Solder reference guide for information on how to leverage the servlet context attribute provider to access the BeanManager from outside the CDI environment.

To use the Seam Faces module, you need to put the API and implementation JARs on the classpath of your web application. Most of the features of Seam Faces are enabled automatically when it's added to the classpath. Some extra configuration, covered below, is required if you are not using a Servlet 3-compliant container.

If you are using Maven as your build tool, you can add the following single dependency to your pom.xml file to include Seam Faces:


<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces</artifactId>
   <version>${seam.faces.version}</version>
</dependency>

Tip

Substitute the expression ${seam.faces.version} with the most recent or appropriate version of Seam Faces. Alternatively, you can create a Maven user-defined property to satisfy this substitution so you can centrally manage the version.

Alternatively, you can use the API at compile time and only include the implementation at runtime. This protects you from inadvertantly depending on an implementation class.


<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-api</artifactId>
   <version>${seam.faces.version}</version>
   <scope>compile</scope>
</dependency>

<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-impl</artifactId>
   <version>${seam.faces.version}</version>
   <scope>runtime</scope>
</dependency>

In a Servlet 3.0 or Java EE 6 environment, your configuration is now complete!

You're now ready to dive into the JSF enhancements provided for you by the Seam Faces module!

When the seam-faces module is installed in a web application, JSF events will automatically be propagated via the CDI event-bridge, enabling managed beans to easily observe all Faces events.

There are two categories of events: JSF phase events, and JSF system events. Phase events are triggered as JSF processes each lifecycle phase, while system events are raised at more specific, fine-grained events during request processing.

A JSF phase listener is a class that implements javax.faces.event.PhaseListener and is registered in the web application's faces-config.xml file. By implementing the methods of the interfaces, the user can observe events fired before or after any of the six lifecycle phases of a JSF request: restore view, apply request values, process validations, update model values, invoke application or render view.

What Seam provides is propagation of these Phase events to the CDI event bus; therefore, you can observe events using normal CDI @Observes methods. Bringing the events to CDI beans removes the need to register phase listener classes via XML, and gives the added benefit of injection, alternatives, interceptors and access to all other features of CDI.

Creating an observer method in CDI is simple; just provide a method in a managed bean that is annotated with @Observes. Each observer method must accept at least one method parameter: the event object; the type of this object determines the type of event being observed. Additional parameters may also be specified, and their values will be automatically injected by the container as per the CDI specification.

In this case, the event object passed along from the phase listener is a javax.faces.event.PhaseEvent. The following example observes all Phase events.



public void observeAll(@Observes PhaseEvent e)
{
    // Do something with the event object
} 

Events can be further filtered by adding Qualifiers. The name of the method itself is not significant. (See the CDI Reference Guide for more information on events and observing.)

Since the example above simply processes all events, however, it might be appropriate to filter out some events that we aren't interested in. As stated earlier, there are six phases in the JSF lifecycle, and an event is fired before and after each, for a total of 12 events. The @Before and @After "temporal" qualifiers can be used to observe events occurring only before or only after a Phase event. For example:



public void observeBefore(@Observes @Before PhaseEvent e)
{
    // Do something with the "before" event object
}
public void observeAfter(@Observes @After PhaseEvent e)
{
    // Do something with the "after" event object
} 

If we are interested in both the "before" and "after" event of a particular phase, we can limit them by adding a "lifecycle" qualifier that corresponds to the phase:



public void observeRenderResponse(@Observes @RenderResponse PhaseEvent e)
{
    // Do something with the "render response" event object
} 

By combining a temporal and lifecycle qualifier, we can achieve the most specific qualification:



public void observeBeforeRenderResponse(@Observes @Before @RenderResponse PhaseEvent e)
{
    // Do something with the "before render response" event object
} 

This is the full list of temporal and lifecycle qualifiers

QualifierTypeDescription
@BeforetemporalQualifies events before lifecycle phases
@AftertemporalQualifies events after lifecycle phases
@RestoreViewlifecycleQualifies events from the "restore view" phase
@ApplyRequestValueslifecycleQualifies events from the "apply request values" phase
@ProcessValidationslifecycleQualifies events from the "process validations" phase
@UpdateModelValueslifecycleQualifies events from the "update model values" phase
@InvokeApplicationlifecycleQualifies events from the "invoke application" phase
@RenderResponselifecycleQualifies events from the "render response" phase

The event object is always a javax.faces.event.PhaseEvent and according to the general CDI principle, filtering is tightened by adding qualifiers and loosened by omitting them.

Similar to JSF Phase Events, System Events take place when specific events occur within the JSF life-cycle. Seam Faces provides a bridge for all JSF System Events, and propagates these events to CDI.

Since all JSF system event objects are distinct, no qualifiers are needed to observe them. The following events may be observed:

Event objectContextDescription
SystemEventallAll events
ComponentSystemEventcomponentAll component events
PostAddToViewEventcomponentAfter a component was added to the view
PostConstructViewMapEventcomponentAfter a view map was created
PostRestoreStateEventcomponentAfter a component has its state restored
PostValidateEventcomponentAfter a component has been validated
PreDestroyViewMapEventcomponentBefore a view map has been restored
PreRemoveFromViewEventcomponentBefore a component has been removed from the view
PreRenderComponentEventcomponentAfter a component has been rendered
PreRenderViewEventcomponentBefore a view has been rendered
PreValidateEventcomponentBefore a component has been validated
ExceptionQueuedEventsystemWhen an exception has been queued
PostConstructApplicationEventsystemAfter the application has been constructed
PostConstructCustomScopeEventsystemAfter a custom scope has been constructed
PreDestroyApplicationEventsystemBefore the application is destroyed
PreDestroyCustomScopeEventsystemBefore a custom scope is destroyed

JSF 2.0 introduced the concept of the Flash object and the @ViewScope; however, JSF 2.0 did not provide annotations accessing the Flash, and CDI does not support the non-standard ViewScope by default. The Seam Faces module does both, in addition to adding a new @RenderScoped context. Beans stored in the Render Scope will survive until the next page is rendered. For the most part, beans stored in the ViewScope will survive as long as a user remains on the same page, and data in the JSF 2 Flash will survive as long as the flash survives).

Beans placed in the @RenderScoped context are effectively scoped to, and live through but not after, "the next Render Response phase".

You should think about using the Render scope if you want to store information that will be relevant to the user even after an action sends them to another view. For instance, when a user submits a form, you may want to invoke JSF navigation and redirect the user to another page in the site; if you needed to store a message to be displayed when the next page is rendered -but no longer- you would store that message in the RenderContext. Fortunately, Seam provides RenderScoped messages by default, via the Seam Messages API.

To place a bean in the Render scope, use the @javax.faces.bean.RenderScoped annotation. This means that your bean will be stored in the org.jboss.seam.context.RenderContext object until the next page is rendered, at which point the RenderScope will be cleared.

@RenderScoped

public class Bean {
    // ...
}

@RenderScoped beans are destroyed when the next JSF RENDER_RESPONSE phase ends, however, if a user has multiple browser windows open for the same user-session, multiple RenderContexts will be created, one for each incoming request. Seam Faces keeps track of which RenderContext belongs to each request, and will restore/destroy them appropriately. If there is more than one active RenderContext at the time when you issue a redirect, you will see a URL parameter "?fid=..." appended to the end of the outbound URL, this is to ensure the correct context is restored when the request is received by the server, and will not be present if only one context is active.

Caution

If you want to use the Render Scope with custom navigation in your application, be sure to call ExternalContext.encodeRedirectURL(String url, Map<String, List<String>> queryParams) on any URL before using it to issue a redirect. This will ensure that the RenderContext ID is properly appended to the URL, enabling the RenderContext to be restored on the subsequent request. This is only necessary if issuing a Servlet Redirect; for the cases where Faces non-redirecting navigation is used, no URL parameter is necessary, and the context will be destroyed at the end of the current request.

While JSF already has the concept of adding FacesMessage objects to the FacesContext in order for those messages to be displayed to the user when the view is rendered, Seam Faces takes this concept one step farther with the Messages API provided by the Seam International module. Messages are template-based, and can be added directly via the code, or templates can be loaded from resource bundles using a BundleKey.

Consistent with the CDI programming model, the Messages API is provided via bean injection. To add a new message to be displayed to the user, inject org.jboss.seam.international.status.Messages and call one of the Message factory methods. As mentioned earlier, factory methods accept either a plain-text template, or a BundleKey, specifying the name of the resource bundle to use, and the name of the key to use as a message template.

@Named

public class Example
{
   @Inject
   Messages messages;
   public String action()
   {
      messages.info("This is an {0} message, and will be displayed to {1}.", "INFO", "the user");
      return null;
   }
}

Adds the message: "This is an INFO message, and will be displayed to the user."

Notice how {0}, {1} ... {N} are replaced with the given parameters, and may be used more than once in a given template. In the case where a BundleKey is used to look up a message template, default text may be provided in case the resource cannot be loaded; default text uses the same parameters supplied for the bundle template. If no default text is supplied, a String representation of the BundleKey and its parameters will be displayed instead.

public String action()

{
   messages.warn(new BundleKey("org.jboss.seam.faces.exampleBundle", "messageKey"), "unique");
   return null;
}

classpath:/org/jboss/seam/faces/exampleBundle.properties

messageKey=This {0} parameter is not so {0}, see?

Adds the message: "This unique parameter is not so unique, see?"

One of the goals of the Seam Faces Module is to make support for CDI a more ubiquitous experience, by allowing injection of JSF Lifecycle Artifacts into managed beans, and also by providing support for @Inject where it would not normally be available. This section describes the additional CDI integration for faces artifact injection

Frequently when performing complex validation, it is necessary to access data stored in a database or in other contextual objects within the application itself. JSF does not, by default, provide support for @Inject in Converters and Validators, but Seam Faces makes this available. In addition to injection, it is sometimes convenient to be able to scope a validator just as we would scope a managed bean; this feature is also added by Seam Faces.

Notice how the Validator below is actually @RequestScoped, in addition to using injection to obtain an instance of the UserService with which to perform an email database lookup.

@RequestScoped

@FacesValidator("emailAvailabilityValidator")
public class EmailAvailabilityValidator implements Validator
{
   @Inject
   UserService us;
   @Override
   public void validate(final FacesContext context, final UIComponent component, final Object value)
            throws ValidatorException
   {
      String field = value.toString();
      try
      {
         us.getUserByEmail(field);
         FacesMessage msg = new FacesMessage("That email address is unavailable");
         throw new ValidatorException(msg);
      }
      catch (NoSuchObjectException e)
      {
      }
   }
}

An example Converter using @Inject

@SessionScoped

@FacesConverter("authorConverter")
public class UserConverter implements Converter
{
   @Inject
   private UserService service;
 
   @PostConstruct
   public void setup()
   {
      System.out.println("UserConverter started up");
   }
 
   @PreDestroy
   public void shutdown()
   {
      System.out.println("UserConverter shutting down");
   }
 
   @Override
   public Object getAsObject(final FacesContext arg0, final UIComponent arg1, final String userName)
   {
      // ...
      return service.getUserByName(userName);
   }
 
   @Override
   public String getAsString(final FacesContext context, final UIComponent comp, final Object user)
   {
      // ...
      return ((User)user).getUsername();
   }
}

This is the list of inject-able artifacts provided through Seam Faces. These objects would normally require static method-calls in order to obtain handles, but Seam Faces attempts to break that coupling by providing @Inject'able artifacts. This means it will be possible to more easily provide mocked objects during unit and integration testing, and also simplify bean code in the application itself.

Artifact ClassExample
javax.faces.context.FacesContext
public class Bean {
   @Inject FacesContext context;
}
javax.faces.context.ExternalContext
public class Bean {
   @Inject ExternalContext context;
}
javax.faces.application.NavigationHandler
public class Bean {
   @Inject NavigationHandler handler;
}
javax.faces.context.Flash
public class Bean {
   @Inject Flash flash;
}

While Seam Faces does not provide layout components or other UI-design related features, it does provide functional components designed to make developing JSF applications easier, more functional, more scalable, and more practical.

For layout and design components, take a look at RichFaces, a UI component library specifically tailored for easy, rich web-interfaces.

On many occasions you might find yourself needing to compare the values of multiple input fields on a given page submit: confirming a password; re-enter password; address lookups; and so on. Performing cross-field form validation is simple - just place the <s:validateForm> component in the form you wish to validate, then attach your custom Validator.


<h:form id="locationForm">
   <h:inputText id="city" value="#{bean.city}" />
   <h:inputText id="state" value="#{bean.state}" />
   <h:inputText id="zip" value="#{bean.zip}" />
   <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
                  
   <s:validateForm validatorId="locationValidator" />
</h:form>

The corresponding Validator for the example above would look something like this:

@FacesValidator("locationValidator")

public class LocationValidator implements Validator
{
   @Inject
   Directory directory;
   @Inject
   @InputField
   private Object city;
   @Inject
   @InputField
   private Object state;
   @Inject
   @InputField
   private ZipCode zip;
   @Override
   public void validate(final FacesContext context, final UIComponent comp, final Object values)
         throws ValidatorException
   {
      if(!directory.exists(city, state, zip))
      {
         throw new ValidatorException(
            new FacesMessage("Sorry, that location is not in our database. Please try again."));
      }
   }
}

Notice that the IDs of the inputText components match the IDs of your Validator @InputFields; each @Inject @InputField member will be injected with the value of the form input field who's ID matches the name of the variable.

In other words - the name of the @InputField annotated member variable will automatically be matched to the ID of the input component, unless overridden by using a field ID alias (see below.)


<h:form id="locationForm">
   <h:inputText id="cityId" value="#{bean.city}" />
   <h:inputText id="stateId" value="#{bean.state}" />
   <h:inputText id="zip" value="#{bean.zip}" />
   <h:commandButton id="submit" value="Submit" action="#{bean.submitPost}" />
                  
   <s:validateForm fields="city=cityId state=stateId" validatorId="locationValidator" />
</h:form>

Notice that "zip" will still be referenced normally; you need only specify aliases for fields that differ in name from the Validator @InputFields.

The view action component (UIViewAction) is an ActionSource2 UIComponent that specifies an application-specific command (or action), using using an EL method expression, to be invoked during one of the JSF lifecycle phases proceeding Render Response (i.e., view rendering).

View actions provide a lightweight front-controller for JSF, allowing the application to accommodate scenarios such as registration confirmation links, security and sanity checking a request (e.g., ensuring the resource can be loaded). They also allow JSF to work alongside action-oriented frameworks, and existing applications that use them.

JSF employs an event-oriented architecture. Listeners are invoked in response to user-interface events, such as the user clicking on a button or changing the value of a form input. Unfortunately, the most important event on the web, a URL request (initiated by the user clicking on a link, entering a URL into the browser's location bar or selecting a bookmark), has long been overlooked in JSF. Historically, listeners have exclusively been activated on postback, which has led to the common complaint that in JSF, "everything is a POST."

We want to change that perception.

Processing a URL request event is commonly referred to as bookmarkable or GET support. Some GET support was added to JSF 2.0 with the introduction of view parameters and the pre-render view event. View parameters are used to bind query string parameters to model properties. The pre-render view event gives the developer a window to invoke a listener immediately prior to the view being rendered.

That's a start.

Seam brings the GET support full circle by introducing the view action component. A view action is the compliment of a UICommand for an initial (non-faces) request. Like its cohort, it gets executed by default during the Invoke Application phase (now used on both faces and non-faces requests). A view action can optionally be invoked on postback as well.

View actions (UIViewAction) are closely tied to view parameters (UIViewParameter). Most of the time, the view parameter is used to populate the model with data that is consumed by the method being invoked by a UIViewAction component, much like form inputs populate the model with data to support the method being invoked by a UICommand component.

Let's consider a typical scenario in web applications. You want to display the contents of a blog entry that matches the identifier specified in the URL. We'll assume the URL is:

http://localhost:8080/blog/entry.jsf?id=10

We'll use a view parameter to capture the identifier of the entry from the query string and a view action to fetch the entry from the database.


<f:metadata>
   <f:viewParam name="id" value="#{blogManager.entryId}"/>  
   <s:viewAction action="#{blogManager.loadEntry}"/>  
</f:metadata>

What do we do if the entry can't be found? View actions support declarative navigation just like UICommand components. So you can write a navigation rule that will be consulted before the page is rendered. If the rule matches, navigation occurs just as though this were a postback.


<navigation-rule>
      <from-view-id>/entry.xhtml</from-view-id>
      <navigation-case>
         <from-action>#{blogManager.loadEntry}</from-action>
         <if>#{empty entry}</if>
         <to-view-id>/home.xhtml</to-view-id>
         <redirect/>
      </navigation-case>
   </navigation-rule>

After each view action is invoked, the navigation handler looks for a navigation case that matches the action's EL method signature and outcome. If a navigation case is matched, or the response is marked complete by the action, subsequent view actions are short-circuited. The lifecycle then advances appropriately.

By default, a view action is not executed on postback, since the primary intention of a view action is to support a non-faces request. If your application (or use case) is decidedly stateless, you may need the view action to execute on any type of request. You can enable the view action on postback using the onPostback attribute:


<s:viewAction action="#{blogManager.loadEntry}" onPostback="true"/>

You may only want the view action to be invoked under certain conditions. For instance, you may only need it to be invoked if the conversation is transient. For that, you can use the if attribute, which accepts an EL value expression:


<s:viewAction action="#{blogEditor.loadEntry}" if="#{conversation.transient}"/>

There are two ways to control the phase in which the view action is invoked. You can set the immediate attribute to true, which moves the invocation to the Apply Request Values phase instead of the default, the Invoke Application phase.


<s:viewAction action="#{sessionManager.validateSession}" immediate="true"/>

You can also just specify the phase directly, using the name of the phase constant in the PhaseId class (the case does not matter).


<s:viewAction action="#{sessionManager.validateSession}" phase="APPLY_REQUEST_VALUES"/>

If the phase is set, it takes precedence over the immediate flag.

UIInputContainer is a supplemental component for a JSF 2.0 composite component encapsulating one or more input components (EditableValueHolder), their corresponding message components (UIMessage) and a label (HtmlOutputLabel).

This component takes care of wiring the label to the first input and the messages to each input in sequence. It also assigns two implicit attribute values, "required" and "invalid" to indicate that a required input field is present and whether there are any validation errors, respectively. To determine if a input field is required, both the required attribute is consulted and whether the property has Bean Validation constraints.

Finally, if the "label" attribute is not provided on the composite component, the label value will be derived from the id of the composite component, for convenience.

Composite component definition example (minus layout):


<cc:interface componentType="org.jboss.seam.faces.InputContainer"/>
 <cc:implementation>
   <h:outputLabel id="label" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">
     <h:outputText styleClass="required" rendered="#{cc.attrs.required}" value="*"/>
   </h:outputLabel>
   <cc:insertChildren/>
   <h:message id="message" errorClass="invalid message" rendered="#{cc.attrs.invalid}"/>
 </cc:implementation>

Composite component usage example:


<example:inputContainer id="name">
   <h:inputText id="input" value="#{person.name}"/>
 </example:inputContainer>

Most features of Seam International are installed automatically by including seam-international.jar in the web application library folder. If you are using Maven as your build tool, you can add the following dependency to your pom.xml file:


<dependency>
    <groupId>org.jboss.seam</groupId>
    <artifactId>seam-international</artifactId>
    <version>${seam-international-version}</version>
</dependency>

Tip

Replace ${seam-international-version} with the most recent or appropriate version of Seam International.

In a similar fashion to TimeZones we have an application Locale retrieved by

@Inject

java.util.Locale lc;

accessible via EL with "defaultLocale".

By default the Locale will be set to the JVM default, unless you override the DefaultLocaleProducer Bean via the Seam Config module. Here are a few examples of XML that can be used to define the various types of Locales that are available.

This will set the default language to be French.


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:seam:core" 
   xmlns:lc="urn:java:org.jboss.seam.international.locale"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://docs.jboss.org/cdi/beans_1_0.xsd">

    <lc:DefaultLocaleProducer>
        <s:replaces/>
        <lc:defaultLocaleKey>fr</lc:defaultLocaleKey>
    </lc:DefaultLocaleProducer>
</beans>

This will set the default language to be English with the country of US.


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:seam:core" 
   xmlns:lc="urn:java:org.jboss.seam.international.locale"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee 
      http://docs.jboss.org/cdi/beans_1_0.xsd">

    <lc:DefaultLocaleProducer>
        <s:replaces/>
        <lc:defaultLocaleKey>en_US</lc:defaultLocaleKey>
    </lc:DefaultLocaleProducer>
</beans>

As you can see from the previous examples, you can define the Locale with lang_country_variant. It's important to note that the first two parts of the locale definition are not expected to be greater than 2 characters otherwise an error will be produced and it will default to the JVM Locale.

To support a more developer friendly way of handling TimeZones we have incorporated the use of Joda-Time through their DateTimeZone class. Don't worry, it provides convenience methods to convert to JDK TimeZone if required.

There are currently two ways to create a message within the module.

The first would mostly be used when you don't want to add the generated message directly to the UI, but want to log it out, or store it somewhere else

@Inject

MessageFactory factory;
 
public String getMessage()
{
     MessageBuilder builder = factory.info("There are {0} cars, and they are all {1}; {1} is the best color.", 5, "green");#
     return builder.build().getText();
}

The second is to add the message to a list that will be returned to the UI for display.

@Inject

Messages messages;
 
public void setMessage()
{
     messages.info("There are {0} cars, and they are all {1}; {1} is the best color.", 5, "green");
}

Either of these methods supports the four message levels which are info, warning, error and fatal.

Both the MessageFactory and Messages classes support four ways in which to create a Message:

Examples for each of these are:

The above examples assume that there is a properties file existing at org.jboss.international.seam.test.TestBundle.properties with key1 being a simple text string and key2 including a single parameter.

To use the Seam Catch module, you need to add the Seam Catch API to your project as a compile-time dependency. At runtime, you'll also need the Seam Catch implementation, which you either specify explicitly or through a transitive dependency of another module that depends on it (as part of exposing its own Catch integration).

First, check your application's library dependencies to see whether Seam Catch is already being included by another module (such as Seam Servlet). If not, you'll need to setup the dependencies as described below.

If you are using Maven as your build tool, you can add the following single dependency to your pom.xml file to include Seam Catch:


<dependency>
   <groupId>org.jboss.seam.catch</groupId>
   <artifactId>seam-catch</artifactId>
   <version>${seam.catch.version}</version>
</dependency>

Tip

Substitute the expression ${seam.catch.version} with the most recent or appropriate version of Seam Catch. Alternatively, you can create a Maven user-defined property to satisfy this substitution so you can centrally manage the version.

Alternatively, you can use the API at compile time and only include the implementation at runtime. This protects you from inadvertantly depending on an implementation class.


<dependency>
   <groupId>org.jboss.seam.catch</groupId>
   <artifactId>seam-catch-api</artifactId>
   <version>${seam.catch.version}</version>
   <scope>compile</scope>
</dependency>

<dependency>
   <groupId>org.jboss.seam.catch</groupId>
   <artifactId>seam-catch-impl</artifactId>
   <version>${seam.catch.version}</version>
   <scope>runtime</scope>
</dependency>

Now you're ready to start catching exceptions!

Exception handlers are contained within exception handler beans, which are CDI beans annotated with @HandlesExceptions. Exception handlers are methods which have a parameter which is an instance of CaughtException<T extends Throwable> annotated with the @Handles annotation.

@Handles is a method parameter annotation that designates a method as an exception handler. Exception handler methods are registered on beans annotated with @HandlesExceptions. Catch will discover all such methods at deployment time.

Let's look at an example. The following method is invoked for every exception that Catch processes and prints the exception message to stout. (Throwable is the base exception type in Java and thus represents all exceptions).

(1)@HandlesExceptions

public class MyHandlers
{
(2)   void printExceptions(@Handles CaughtException<Throwable> evt)
   {
      System.out.println("Something bad happened: " +
(3)            evt.getException().getMessage());
(4)      evt.proceed();
   }
}
            

1

The @HandlesExceptions annotation signals that this bean contains exception handler methods.

2

The @Handles annotation on the first parameter designates this method as an exception handler (though it is not required to be the first parameter). This parameter must be of typeCaughtException<T extends Throwable>, otherwise it's detected as a definition error. The type parameter designates which exception the method should handle. This method is notified of all exceptions (requested by the base exception type Throwable).

3

The CaughtException instance provides access to information about the exception and can be used to control exception handling flow. In this case, it's used to read the current exception being handled in the exception stack trace, as returned by getException().

4

This handler does not modify the invocation of subsequent handlers, as designated by invoking proceed() on CaughtException. As this is the default behavior, this line could be omitted.

The @Handles annotation must be placed on a parameter of the method, which must be of typeCaughtException<T extends Throwable>. Handler methods are similar to CDI observers and, as such, follow the same principals and guidelines as observers (such as invocation, injection of parameters, qualifiers, etc) with the following exceptions:

In addition to designating a method as exception handler, the @Handles annotation specifies two pieces of information about when the method should be invoked relative to other handler methods:

Let's take a look at more sophisticated example that uses all the features of handlers to log all exceptions.

(1)@HandlesExceptions

public class MyHandlers
{
(2)   void logExceptions(@Handles(during = TraversalMode.BREADTH_FIRST)
(3)         @WebRequest CaughtException<Throwable> evt,
(4)         Logger log)
   {
      log.warn("Something bad happened: " + evt.getException().getMessage());
   }
}
            

1

The @HandlesExceptions annotation signals that this bean contains exception handler methods.

2

This handler has a default precedence of 0 (the default value of the precedence attribute on @Handles). It's invoked during the breadth first traversal mode. For more information on traversal, see the sectionSection 22.4.1, “Traversal of exception type hierarchy”.

3

This handler is qualified with@WebRequest. When Catch calculates the handler chain, it filters handlers based on the exception type and qualifiers. This handler will only be invoked for exceptions passed to Catch that carry the @WebRequest qualifier. We'll assume this qualifier distinguishes a web page request from a REST request.

4

Any additional parameters of a handler method are treated as injection points. These parameters are injected into the handler when it is invoked by Catch. In this case, we are injecting a Logger bean that must be defined within the application (or by an extension).

A handler is guaranteed to only be invoked once per exception (automatically muted), unless it reenables itself by invoking the unMute() method on the CaughtException instance.

Handlers must not throw checked exceptions, and should avoid throwing unchecked exceptions. Should a handler throw an unchecked exception it will propegate up the stack and all handling done via Catch will cease. Any exception that was being handled will be lost.

When an exception is thrown, chances are it's nested (wrapped) inside other exceptions. (If you've ever examined a server log, you'll appreciate this fact). The collection of exceptions in its entirety is termed an exception stack trace.

The outermost exception of an exception stack trace (e.g., EJBException, ServletException, etc) is probably of little use to exception handlers. That's why Catch doesn't simply pass the exception stack trace directly to the exception handlers. Instead, it intelligently unwraps the stack trace and treats the root exception cause as the primary exception.

The first exception handlers to be invoked by Catch are those that match the type of root cause. Thus, instead of seeing a vagueEJBException, your handlers will instead see an meaningful exception such asConstraintViolationException. This feature, alone, makes Catch a worthwhile tool.

Catch continues to work through the exception stack trace, notifying handlers of each exception in the stack, until a handler flags the exception as handled. Once an exception is marked as handled, Catch stops processing the exception. If a handler instructed Catch to rethrow the exception (by invoking CaughtException#rethrow(), Catch will rethrow the exception outside the Catch infrastructure. Otherwise, it simply returns flow control to the caller.

Consider a stack trace containing the following nested causes (from outer cause to root cause):

Catch will unwrap this exception and notify handlers in the following order:

If there's a handler forPersistenceException, it will likely prevent the handlers for EJBException from being invoked, which is a good thing since what useful information can really be obtained fromEJBException?

While processing one of the causes in the exception stack trace, Catch has a specific order it uses to invoke the handlers, operating on two axes:

We'll first address the traversal of the exception type hierarchy, then cover relative handler precedence.

Catch doesn't simply invoke handlers that match the exact type of the exception. Instead, it walks up and down the type hierarchy of the exception. It first notifies least specific handler in breadth first traversal mode, then gradually works down the type hiearchy towards handlers for the actual exception type, still in breadth first traversal. Once all breadth first traversal handlers have been invoked, the process is reversed for depth first traversal, meaning the most specific handlers are notified first and Catch continues walking up the hierarchy tree.

There are two modes of this traversal:

By default, handlers are registered into the DEPTH_FIRST traversal path. That means in most cases, Catch starts with handlers of the actual exception type and works up towards the handler for the least specific type.

However, when a handler is registered to be notified during the BREADTH_FIRST traversal, as in the example above, Catch will notify that exception handler before the exception handler for the actual type is notified.

Let's consider an example. Assume that Catch is handling theSocketException. It will notify handlers in the following order:

The same type traversal occurs for each exception processed in the stack trace.

In order for a handler to be notified of the IOException before the SocketException, it would have to specify the BREADTH_FIRST traversal path explicitly:



void handleIOException(@Handles(during = TraversalMode.BREADTH_FIRST)
      CaughtException<IOException> evt)
{
   System.out.println("An I/O exception occurred, but not sure what type yet");
}
         

BREADTH_FIRST handlers are typically used for logging exceptions because they are not likely to be short-circuited (and thus always get invoked).

To summarize, here's how Catch determines the order of handlers to invoke (until a handler marks exception as handled):

There are two APIs provided by Catch that should be familiar to application developers:

ExceptionStack contains information about the exception causes relative to the current exception cause. It is also the source of the exception types the invoked handlers are matched against. It is accessed in handlers by calling the method getExceptionStack() on the CaughtException object. Please see API docs for more information, all methods are fairly self-explanatory.

Tip

This object is mutable and can be modified before any handlers are invoked by an observer:

public void modifyStack(@Observes ExceptionStack stack) {

  ...
}
            

Modifying the ExceptionStack may be useful to remove exception types that are effectively meaningless sucsh asEJBException, changing the exception type to something more meaningful such as cases likeSQLException, or wrapping exceptions as custom application exception types.

Integration of Seam Catch with other frameworks consists of one main step, and two other optional (but highly encouraged) steps:

  • creating and firing an ExceptionToCatch
  • adding any default handlers and qualifiers with annotation literals (optional)
  • supporting ServiceHandlers for creating exception handlers

ServiceHandlers make for a very easy and concise way to define exception handlers take the following example comes from the jaxrs example in the distribution:

@HandlesExceptions

@ExceptionResponseService
public interface DeclarativeRestExceptionHandlers
{
               
   @SendHttpResponse(status = 403, message = "Access to resource denied (Annotation-configured response)")
   void onNoAccess(@Handles @RestRequest CaughtException<AccessControlException> e);
   @SendHttpResponse(status = 400, message = "Invalid identifier (Annotation-configured response)")
   void onInvalidIdentifier(@Handles @RestRequest CaughtException<IllegalArgumentException> e);
}
      

All the vital information that would normally be done in the handler method is actually contained in the @SendHttpResponse annotation. The only thing left is some boiler plate code to setup the Response. In a jax-rs application (or even in any web application) this approach helps developers cut down on the amount of boiler plate code they have to write in their own handlers and should be implemented in any Catch integration, however, there may be situtations where ServiceHandlers simply do not make sense.

Note

If ServiceHandlers are implemented make sure to document if any of the methods are called from CaughtException, specifically abort(), handled() or rethrow(). These methods affect invocation of other handlers (or rethrowing the exception in the case of rethrow()).

Seam provides a convenient method of remotely accessing CDI beans from a web page, using AJAX (Asynchronous Javascript and XML). The framework for this functionality is provided with almost no up-front development effort - your beans only require simple annotating to become accessible via AJAX. This chapter describes the steps required to build an AJAX-enabled web page, then goes on to explain the features of the Seam Remoting framework in more detail.

To use remoting, the Seam Remoting servlet must first be configured in your web.xml file:


<servlet>
   <servlet-name>Remoting Servlet</servlet-name>
   <servlet-class>org.jboss.seam.remoting.Remoting</servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
   <servlet-name>Remoting Servlet</servlet-name>
   <url-pattern>/seam/resource/remoting/*</url-pattern>
</servlet-mapping>

The next step is to import the necessary Javascript into your web page. There are a minimum of two scripts that must be imported. The first one contains all the client-side framework code that enables remoting functionality:


<script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>

By default, the client-side JavaScript is served in compressed form, with white space compacted and JavaScript comments removed. For a development environment, you may wish to use the uncompressed version of remote.js for debugging and testing purposes. To do this, simply add the compress=false parameter to the end of the url:


<script type="text/javascript" src="seam/resource/remoting/resource/remote.js?compress=false"></script>

The second script that you need contains the stubs and type definitions for the beans you wish to call. It is generated dynamically based on the method signatures of your beans, and includes type definitions for all of the classes that can be used to call its remotable methods. The name of the script reflects the name of your bean. For example, if you have a named bean annotated with @Named, then your script tag should look like this (for a bean class called CustomerAction):


<script type="text/javascript" 
          src="seam/resource/remoting/interface.js?customerAction"></script>

Otherwise, you can simply specify the fully qualified class name of the bean:


<script type="text/javascript" 
          src="seam/resource/remoting/interface.js?com.acme.myapp.CustomerAction"></script>

If you wish to access more than one bean from the same page, then include them all as parameters of your script tag:


<script type="text/javascript" 
        src="seam/resource/remoting/interface.js?customerAction&accountAction"></script>

Client-side interaction with your beans is all performed via the Seam Javascript object. This object is defined in remote.js, and you'll be using it to make asynchronous calls against your bean. It contains methods for creating client-side bean objects and also methods for executing remote requests. The easiest way to become familiar with this object is to start with a simple example.

Let's step through a simple example to see how the Seam object works. First of all, let's create a new bean called helloAction:

@Named

public class HelloAction implements HelloLocal {
    @WebRemote public String sayHello(String name) {
        return "Hello, " + name;
    }
}

Take note of the @WebRemote annotation on the sayHello() method in the above listing. This annotation makes the method accessible via the Remoting API. Besides this annotation, there's nothing else required on your bean to enable it for remoting.

Now for our web page - create a new JSF page and import the helloAction bean:


<script type="text/javascript" 
        src="seam/resource/remoting/interface.js?helloAction

To make this a fully interactive user experience, let's add a button to our page:


<button onclick="javascript:sayHello()">Say Hello</button>

We'll also need to add some more script to make our button actually do something when it's clicked:


<script type="text/javascript">
  //<![CDATA[

  function sayHello() {
    var name = prompt("What is your name?");
    Seam.createBean("helloAction").sayHello(name, sayHelloCallback);
  }

  function sayHelloCallback(result) {
    alert(result);
  }

   // ]]>
</script>

We're done! Deploy your application and open the page in a web browser. Click the button, and enter a name when prompted. A message box will display the hello message confirming that the call was successful. If you want to save some time, you'll find the full source code for this Hello World example in the /examples/helloworld directory.

So what does the code of our script actually do? Let's break it down into smaller pieces. To start with, you can see from the Javascript code listing that we have implemented two methods - the first method is responsible for prompting the user for their name and then making a remote request. Take a look at the following line:


Seam.createBean("helloAction").sayHello(name, sayHelloCallback);

The first section of this line, Seam.createBean("helloAction") returns a proxy, or "stub" for our helloAction bean. We can invoke the methods of our bean against this stub, which is exactly what happens with the remainder of the line: sayHello(name, sayHelloCallback);.

What this line of code in its completeness does, is invoke the sayHello method of our bean, passing in name as a parameter. The second parameter, sayHelloCallback isn't a parameter of our bean's sayHello method, instead it tells the Seam Remoting framework that once it receives the response to our request, it should pass it to the sayHelloCallback Javascript method. This callback parameter is entirely optional, so feel free to leave it out if you're calling a method with a void return type or if you don't care about the result.

The sayHelloCallback method, once receiving the response to our remote request then pops up an alert message displaying the result of our method call.

The Seam Remoting Context contains additional information which is sent and received as part of a remoting request/response cycle. It currently contains the conversation ID and Call ID, and may be expanded to include other properties in the future.

When a remote method is executed, the result is serialized into an XML response that is returned to the client. This response is then unmarshaled by the client into a JavaScript object. For complex types (i.e. Javabeans) that include references to other objects, all of these referenced objects are also serialized as part of the response. These objects may reference other objects, which may reference other objects, and so forth. If left unchecked, this object "graph" could potentially be enormous, depending on what relationships exist between your objects. And as a side issue (besides the potential verbosity of the response), you might also wish to prevent sensitive information from being exposed to the client.

Seam Remoting provides a simple means to "constrain" the object graph, by specifying the exclude field of the remote method's @WebRemote annotation. This field accepts a String array containing one or more paths specified using dot notation. When invoking a remote method, the objects in the result's object graph that match these paths are excluded from the serialized result packet.

For all our examples, we'll use the following Widget class:

public class Widget

{
  private String value;
  private String secret;
  private Widget child;
  private Map<String,Widget> widgetMap;
  private List<Widget> widgetList;
  
  // getters and setters for all fields
}

The Model API builds on top of Seam Remoting's object serialization features to provide a component-based approach to working with a server-side object model, as opposed to the RPC-based approach provided by the standard Remoting API. This allows a client-side representation of a server-side object graph to be modified ad hoc by the client, after which the changes made to the objects in the graph can be applied to the corresponding server-side objects. When applying the changes the client determines exactly which objects have been modified by recursively walking the client-side object tree and generating a delta by comparing the original property values of the objects with their new property values.

This approach, when used in conjunction with the extended persistence context provided by Seam elegantly solves a number of problems faced by AJAX developers when working remotely with persistent objects. A persistent, managed object graph can be loaded at the start of a new conversation, and then across multiple requests the client can fetch the objects, make incremental changes to them and apply those changes to the same managed objects after which the transaction can be committed, thereby persisting the changes made.

One other useful feature of the Model API is its ability to expand a model. For example, if you are working with entities with lazy-loaded associations it is usually not a good idea to blindly fetch the associated objects (which may in turn themselves contain associations to other entities, ad nauseum), as you may inadvertently end up fetching the bulk of your database. Seam Remoting already knows how to deal with lazy-loaded associations by automatically excluding them when marshalling instances of entity beans, and assigning them a client-side value of undefined (which is a special JavaScript value, distinct from null). The Model API goes one step further by giving the client the option of manipulating the associated objects also. By providing an expand operation, it allows for the initialization of a previously-uninitialized object property (such as a lazy-loaded collection), by dynamically "grafting" the initialized value onto the object graph. By expanding the model in this way, we have at our disposal a powerful tool for building dynamic client interfaces.

For the methods of the Model API that accept action parameters, an instance of Seam.Action should be used. The constructor for Seam.Action takes no parameters:


  var action = new Seam.Action();

The following table lists the methods used to define the action. Each of the following methods return a reference to the Seam.Action object, so methods can be chained.


The following table describes the methods provided by the Seam.Model object. To work with the Model API in JavaScript you must first create a new Model object:


  var model = new Seam.Model();

Table 25.2. Seam.Model method reference

Method

Description

addBean(alias, bean, qualifiers)

Adds a bean value to the model. When the model is fetched, the value of the specified bean will be read and placed into the model, where it may be accessed by using the getValue() method with the specified alias.

Can only be used before the model is fetched.

  • alias - the local alias for the bean value.
  • bean - the name of the bean, either specified by the @Named annotation or the fully qualified class name.
  • qualifiers (optional) - a list of bean qualifiers.

addBeanProperty(alias, bean, property, qualifiers)

Adds a bean property value to the model. When the model is fetched, the value of the specified property on the specified bean will be read and placed into the model, where it may be accessed by using the getValue() method with the specified alias.

Can only be used before the model is fetched.

Example:


  addBeanProperty("account", "AccountAction", "account", "@Qualifier1", "@Qualifier2");
  • alias - the local alias for the bean value.
  • bean - the name of the bean, either specified by the @Named annotation or the fully qualified class name.
  • property - the name of the bean property.
  • qualifiers (optional) - a list of bean qualifiers. This parameter (and any after it) are treated as bean qualifiers.

fetch(action, callback)

Fetches the model - this operation causes an asynchronous request to be sent to the server. The request contains a list of the beans and bean properties (set by calling the addBean() and addBeanProperty() methods) for which values will be returned. Once the response is received, the callback method (if specified) will be invoked, passing in a reference to the model as a parameter.

A model should only be fetched once.

  • action (optional) - a Seam.Action instance representing the bean action to invoke before the model values are read and stored in the model.
  • callback (optional) - a reference to a JavaScript function that will be invoked after the model has been fetched. A reference to the model instance is passed to the callback method as a parameter.

getValue(alias)

This method returns the value of the object with the specified alias.

  • alias - the alias of the value to return.

expand(value, property, callback)

Expands the model by initializing a property value that was previously uninitialized. This operation causes an asynchronous request to be sent to the server, where the uninitialized property value (such as a lazy-loaded collection within an entity bean association) is initialized and the resulting value is returned to the client. Once the response is received, the callback method (if specified) will be invoked, passing in a reference to the model as a parameter.

  • value - a reference to the value containing the uninitialized property to fetch. This can be any value within the model, and does not need to be a "root" value (i.e. it doesn't need to be a value specified by addBean() or addBeanProperty(), it can exist anywhere within the object graph.
  • property - the name of the uninitialized property to be initialized.
  • callback (optional) - a reference to a JavaScript function that will be invoked after the model has been expanded. A reference to the model instance is passed to the callback method as a parameter.

applyUpdates(action, callback)

Applies the changes made to the objects contained in the model. This method causes an asynchronous request to be sent to the server containing a delta consisting of a list of the changes made to the client-side objects.

  • action (optional) - a Seam.Action instance representing a bean method to be invoked after the client-side model changes have been applied to their corresponding server-side objects.
  • callback (optional) - a reference to a JavaScript function that will be invoked after the updates have been applied. A reference to the model instance is passed to the callback method as a parameter.

To fetch a model, one or more values must first be specified using addBean() or addBeanProperty() before invoking the fetch() operation. Let's work through an example - here we have an entity bean called Customer:

@Entity Customer implements Serializable {

  private Integer customerId;
  private String firstName;
  private String lastName;
  
  @Id @GeneratedValue public Integer getCustomerId() { return customerId; }  
  public void setCustomerId(Integer customerId) { this.customerId = customerId; }
  
  public String getFirstName() { return firstName; }  
  public void setFirstName(String firstName) { this.firstName = firstName; }
  
  public String getLastName() { return lastName; }
  public void setLastName(String lastName) { this.lastName = lastName; }
}

We also have a bean called CustomerAction, which is responsible for creating and editing Customer instances. Since we're only interested in editing a customer right now, the following code only shows the editCustomer() method:

@ConversationScoped @Named

public class CustomerAction {
  @Inject Conversation conversation;
  @PersistenceContext EntityManager entityManager;
  public Customer customer;
  
  public void editCustomer(Integer customerId) {
    conversation.begin();  
    customer = entityManager.find(Customer.class, customerId);
  }
  
  public void saveCustomer() {
    entityManager.merge(customer);
    conversation.end();
  }
}

In the client section of this example, we wish to make changes to an existing Customer instance, so we need to use the editCustomer() method of CustomerAction to first load the customer entity, after which we can access it via the public customer field. Our model object must therefore be configured to fetch the CustomerAction.customer property, and to invoke the editCustomer() method when the model is fetched. We start by using the addBeanProperty() method to add a bean property to the model:


  var model = new Seam.Model();
  model.addBeanProperty("customer", "CustomerAction", "customer");

The first parameter of addBeanProperty() is the alias (in this case customer), which is used to access the value via the getValue() method. The addBeanProperty() and addBean() methods can be called multiple times to bind multiple values to the model. An important thing to note is that the values may come from multiple server-side beans, they aren't all required to come from the same bean.

We also specify the action that we wish to invoke (i.e. the editCustomer() method). In this example we know the value of the customerId that we wish to edit, so we can specify this value as an action method parameter:


  var action = new Seam.Action()
    .setBeanType("CustomerAction")
    .setMethod("editCustomer")
    .addParam(123);

Once we've specified the bean properties we wish to fetch and the action to invoke, we can then fetch the model. We pass in a reference to the action object as the first parameter of the fetch() method. Also, since this is an asynchronous request we need to provide a callback method to deal with the response. The callback method is passed a reference to the model object as a parameter.


  var callback = function(model) { alert("Fetched customer: " model.getValue("customer").firstName + 
    " " + model.getValue("customer").lastName); };
  model.fetch(action, callback);

When the server receives a model fetch request, it first invokes the action (if one is specified) before reading the requested property values and returning them to the client.

We can use the Model API's ability to expand a model to load uninitialized branches of the objects in the model's object graph. To understand how this works exactly, let's flesh out our example a little more by adding an Address entity class, and creating a one-to-many relationship between Customer and Address.

@Entity Address implements Serializable {

  private Integer addressId;
  private Customer customer;
  private String unitNumber;
  private String streetNumber;
  private String streetName;
  private String suburb;
  private String zip;
  private String state;
  private String country;
  
  @Id @GeneratedValue public Integer getAddressId() {  return addressId; }
  public void setAddressId(Integer addressId) { this.addressId = addressId; }
  
  @ManyToOne public Customer getCustomer() { return customer; }
  public void setCustomer(Customer customer) { this.customer = customer; }
  
  /* Snipped other getter/setter methods */
  
}

Here's the new field and methods that we also need to add to the Customer class:

  private Collection<Address> addresses;


  @OneToMany(fetch = FetchType.LAZY, mappedBy = "customer", cascade = CascadeType.ALL)
  public Collection<Address> getAddresses() { return addresses; }   
  public void setAddresses(Collection<Address> addresses) { this.addresses = addresses; }

As we can see, the @OneToMany annotation on the getAddresses() method specifies a fetch attribute of LAZY, meaning that by default the customer's addresses won't be loaded automatically when the customer is. When reading the uninitialized addresses property value from a newly-fetched Customer object in JavaScript, a value of undefined will be returned.


  getValue("customer").addresses == undefined; // returns true

We can expand the model by making a special request to initialize this uninitialized property value. The expand() operation takes three parameters - the value containing the property to be initialized, the name of the property and an optional callback method. The following example shows us how the customer's addresses property can be initialized:


  model.expand(model.getValue("customer"), "addresses");

The expand() operation makes an asynchronous request to the server, where the property value is initialized and the value returned to the client. When the client receives the response, it reads the initialized value and appends it to the model.


  // The addresses property now contains an array of address objects
  alert(model.getValue("customer").addresses.length + " addresses loaded");

Seam Remoting provides integrated support for JSR-303 Bean Validation, which defines a standard approach for validating Java Beans no matter where they are used; web tier or persistence tier, server or client. Bean validation for remoting delivers JSR-303's vision by making all of the validation constraints declared by the server-side beans available on the client side, and allows developers to perform client-side bean validation in an easy to use, consistent fashion.

Client-side validation by its very nature is an asynchronous operation, as it is possible that the client may encounter a custom validation constraint for which it has no knowledge of the corresponding validation logic. Under these circumstances, the client will make a request to the server for the validation to be performed server-side, after which it receives the result will forward it to the client-side callback method. All built-in validation types defined by the JSR-303 specification are executed client-side without requiring a round-trip to the server. It is also possible to provide the client-side validation API with custom JavaScript to allow client-side execution of custom validations.

It is also possible to perform multiple validations for beans and bean properties in one go. This might be useful for example to perform validation of forms that present data from more than one bean. The Seam.validate() method takes the following parameters:

      Seam.validate(validations, callback, groups);
    

The validations parameter should contain a list of the validations to perform. It may either be an associative array (for a single validation), or an array of associative arrays (for multiple validations) which define the validations that should be performed. We'll look at this parameter more closely in just a moment.

The callback parameter should contain a reference to the callback function to invoke once validation is complete. The optional groups parameter should contain the group name/s for which to perform validation.

The groups parameter allows one or more validation groups (specified by providing a String or array of String values) to be validated. The validation groups specified here will be applied to all bean values contained in the validations parameter.

The simplest example, in which we wish to validate a single object would look like this:

  Seam.validate({bean:customer}, callback);

In the above example, validation will be performed for the customer object, after which the function named validationCallback will be invoked.

Validate multiple beans is done by passing in an array of validations:

  Seam.validate([{bean:customer}, {bean:order}], callback);

Single properties can be validated by specifying a property name:

  Seam.validate({bean:customer, property: "firstName"}, callback);

To prevent the entire object graph from being validated, the traverse property may be set to false:

  Seam.validate({bean:customer, traverse: false}, callback);

Validation groups may also be set for each individual validation, by setting the groups property to a String or array of Strings value:

  Seam.validate({bean:customer, groups: "default"}, callback);

The Seam REST module runs only on Java EE 6 compliant servers such as JBoss Application Server or GlassFish.

The JAX-RS specification defines the mechanism for exception mapping providers as the standard mechanism for Java exception handling. The Seam REST module comes with an alternative approach, which is more consistent with the CDI programming model. It is also easier to use and still remains portable.

The Seam REST module allows you to:

  • integrate with Seam Catch and thus handle exceptions that occur in different parts of an application uniformly;

  • define exception handling rules declaratively with annotations or XML.

Seam Catch handles exceptions within the Seam REST module: as result, an exception that occurs during an invocation of a JAX-RS service is routed through the Catch exception handling mechanism similar to the CDI event bus. This allows you to implement the exception handling logic in a loosely-coupled fashion.

The following code sample demonstrates a simple exception handler that converts the NoResultException exception to a 404 HTTP response.


Similarly to the CDI event bus, exceptions handled by a handler method can be filtered by qualifiers. The example above treats only exceptions that occur in a JAX-RS service invocation (as opposed to all exceptions of the given type that occur in the application, for example in the view layer). Thus, the @RestRequest qualifier is used to enable the handler only for exceptions that occur during JAX-RS service invocation.

Catch integration is optional and only enabled when Catch libraries are available on classpath. For more information on Seam Catch, refer to Seam Catch reference documentation .

Exception-mapping rules are often fairly simple. Thus, instead of being implemented programatically, they can be expressed declaratively through metadata such as Java annotations or XML. The Seam REST module supports both ways of declarative configurations.

For each exception type, you can specify a status code and an error message of the HTTP response.

You can configure Seam REST exception mapping directly in your Java code with Java Annotations. An exception mapping rule is defined as a @ExceptionMapping annotation. Use an @ExceptionMapping.List annotation to define multiple exception mappings.


The @ExceptionMapping annotation can be applied on any Java class in the deployment. However, it is recommended to keep all exception mapping declarations in the same place, for example, in the javax.ws.rs.core.Application subclass.


As an alternative to the annotation-based configuration, you can use the Seam Config module to configure the SeamRestConfiguration class in XML.

First, add the Seam Config module to the application. If you are using maven, you can do this by specifying the following dependency:


For more information on the Seam Config module, refer to the Seam Config reference documentation. Once you have added the Seam XML module, specify the configuration in the seam-beans.xml file, located in the WEB-INF or META-INF folder of the web archive.


Furthermore, you can use EL expressions in message templates to provide dynamic and more descriptive error messages.


Bean Validation (JSR-303) is a specification introduced as a part of Java EE 6. It aims to provide a standardized way of validating the domain model across all application layers.

The Seam REST module follows the Bean Validation specification and the incomming HTTP requests can be validated with this standardized mechanism.

Firstly, enable the ValidationInterceptor in the beans.xml configuration file.


<interceptors>
    <class>org.jboss.seam.rest.validation.ValidationInterceptor</class>
</interceptors>

Then, enable validation of a particular method by decorating it with the @ValidateRequest annotation.

@PUT

@ValidateRequest
public void updateTask(Task incommingTask)
{
...
}

Now, the HTTP request's entity body (the incomingTask parameter) will be validated prior to invoking the method.

The JAX-RS specification allows path parameters, query parameters, matrix parameters, cookie parameters and headers to be passed as parameters of a resource method.


In order to prevent an oversized method signature when the number of parameters is too large, JAX-RS implementations provide implementations of the Parameter Object pattern. These objects aggregate multiple parameters into a single object, for example RESTEasy Form Object or Apache CXF Parameter Bean. These parameters can be validated by Seam REST. To trigger the validation, annotate the parameter with a javax.validation.Valid annotation.


In some cases, it is desired to have a specific group of constraints used for validation of web service parameters. These constraints are usually weaker than the default constraints of a domain model. Take partial updates as an example.

Consider the following example:


The Employee resource in the example above is not allowed to have the null value specified in any of its fields. Thus, the entire representation of a resource (including the department and related object graph) must be sent to update the resource.

When using partial updates, only values of modified fields are required to be sent within the update request, while the non-null values of the received object are updated. Therefore, two groups of constraints are needed: group for partial updates (including @Size and @Email, excluding @NotNull) and the default group (@NotNull).

A validation group is a simple Java interface:



Finally, the ValidationInterceptor is configured to validate the PartialUpdateGroup group only.


Seam REST allows to create HTTP responses based on the defined templates. Instead of being bound to a particlar templating engine, Seam REST comes with a support for multiple templating engines and support for others can be plugged in.

REST-based web services are often expected to return multiple representations of a resource. The templating support is useful for producing media formats such as XHTML and it can be also used instead of JAXB to produce domain-specific XML representations of a resource. Besides, almost any other representation of a resource can be described in a template.

To enable templating for a particular method, decorate the method with the @ResponseTemplate annotation. Path to a template file to be used for rendering is required.


The @ResponseTemplate annotation offers several other options. For example, it is possible for a method to offer multiple representations of a resource, each rendered with a different template. In the example below, the produces member of the @ResponseTemplate annotation is used to distinguish between produced media types.



There are several ways of accessing the domain data within a template.

Firstly, the object returned by the JAX-RS method is available under the "response" name by default. The object can be made available under a different name using the responseName member of the @ResponseTemplate annotation.


Secondly, every bean reachable via an EL expression is available within a template.


Note

Note that the syntax of the expression depends on the particular templating engine and mostly differs from the syntax of EL expressions. For example, ${university.students} must be used instead of #{university.students} in a FreeMarker template.

Last but not least, the model can be populated programatically. In order to do that, inject the TemplatingModel bean and put the desired objects into the underlying data map. In the following example, the list of professors is available under the "professors" name.


Seam REST currently comes with built-in templating providers for FreeMarker and Apache Velocity.

The RESTEasy Client Framework is a framework for writing clients for REST-based web services. It reuses JAX-RS metadata for creating HTTP requests. For more information about the framework, refer to the project documentation.

Integration with the RESTEasy Client Framework is optional in Seam REST and only available when RESTEasy is available on classpath.

Seam Catch can be used for handling Java exceptions. For more information on using Seam Catch with Seam REST, refer to Section 28.1, “Seam Catch Integration”


<dependency>
    <groupId>org.jboss.seam.catch</groupId>
    <artifactId>seam-catch-api</artifactId>
    <version>${seam.catch.version}</version>
</dependency>
<dependency>
    <groupId>org.jboss.seam.catch</groupId>
    <artifactId>seam-catch-impl</artifactId>
    <version>${seam.catch.version}</version>
</dependency>

Seam Config can be used to configure Seam REST using XML. For more information on using Seam Config with Seam REST, refer to Section 28.2.2, “XML configuration”


<dependency>
    <groupId>org.jboss.seam.config</groupId>
    <artifactId>seam-config-xml</artifactId>
    <version>${seam.config.version}</version>
</dependency>

FreeMarker can be used for rendering HTTP responses. For more information on using FreeMarker with Seam REST, refer to Section 30.2.1, “FreeMarker”


<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>${freemarker.version}</version>
</dependency>

Apache Velocity can be used for rendering HTTP responses. For more information on using Velocity with Seam REST, refer to Section 30.2.2, “Apache Velocity”


<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>${velocity.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-tools</artifactId>
    <version>${velocity.tools.version}</version>
</dependency>

RESTEasy Client Framework can be used for building clients of RESTful web services. For more information on using RESTEasy Client Framework, refer to Chapter 31, RESTEasy Client Framework Integration


<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxrs</artifactId>
    <version>${resteasy.version}</version>
</dependency>

Note

Note that RESTEasy is provided on JBoss Application Server 6 and thus you do not need to bundle it with the web application.

The seam-wicket-api.jar should be placed in the web application library folder. If you are using Maven as your build tool, you can add the following dependency to your pom.xml file:


<dependency>
   <groupId>org.jboss.seam.wicket</groupId>
   <artifactId>seam-wicket-api</artifactId>
   <version>${seam-wicket-version}</version>
</dependency>

Tip

Replace ${seam-wicket-version} with the most recent or appropriate version of Seam for Apache Wicket.

You must also bootstrap Weld according to your environment. As Wicket is normally used in a servlet (non-JavaEE) environment, this is most easily accomplished using the Weld Servlet integration, described in the Weld Reference Guide.

You must extend org.jboss.seam.wicket.SeamApplication rather than org.apache.wicket.protocol.http.WebApplication. In addition:

  • if you override newRequestCycleProcessor to return your own IRequestCycleProcessor subclass, you must instead override getWebRequestCycleProcessorClass() and return the class of your processor, and your processor must extend SeamWebRequestCycleProcessor
  • if you override newRequestCycle to return your own RequestCycle subclass, you must make that subclass extend SeamRequestCycle.

If you can't extend SeamApplication, for example if you use an alternate Application superclass for which you do not control the source, you can duplicate the three steps SeamApplication takes, i.e. return a SeamWebRequestCycleProcessor NonContextual instance in newRequestCycleProcessor, return a SeamRequestCycle instance in newRequestCycle, and add a SeamComponentInstantiationListener with addComponentInstantiationListener.

Seam's integration with Wicket is focused on two tasks: conversation propagation through wicket page metadata and contextual injection of wicket components.

A transient conversation is created when the first wicket IRequestTarget is set during a request. If the request target is an IPageRequestTarget for a page which has previously marked a conversation as non-transient, or if the "cid" parameter is present in the request, the specified conversation will be activated. If the conversation is missing (i.e. has timed out and been destroyed), SeamRequestCycle.handleMissingConversation() will be invoked. By default this does nothing, and your conversation will be new and transient. You can however override this, for example to throw a PageExpiredException or something similar. Upon the end of a response, SeamRequestCycleProcessor will store the cid of a long running conversation, if one exists, to the current page's metadata map, if there is a current page. The key for the cid in the metadata map is the singleton SeamMetaData.CID. Finally, uppon detach(), the SeamRequestCycle will invalidate and deactive the conversation context.

Note that the above process indicates that after a conversation is marked long-running by a page, requests back to that page (whether ajax or not) will activate that conversation. It also means that new Pages set as RequestTargets, if created directly with setResponsePage(somePageInstance) or with setResponsePage(SomePage.class,pageParameters), will have the conversation propagated to them. This can be avoided by (a) ending the conversation before the call to setResponsePage, (b) using a BookmarkablePageLink rather than directly instantiating the response page, or (c) specifying an empty "cid" parameter in PageParameters when using setResponsePage. (Note that the final case also provides a mechanism for switching conversations: if a cid is specified in PageParameters, it will be used by bookmarkable pages, rather than the current conversation.)

Getting started with Seam Solder is easy. All you need to do is put the API and implementation JARs on the classpath of your CDI application. The features provided by Seam Solder will be enabled automatically.

Some additional configuration, covered at the end of this chapter, is required if you are using a pre-Servlet 3.0 environment.

If you are using Maven as your build tool, first make sure you have configured your build to use the JBoss Community repository, where you can find all the Seam artifacts. Then, add the following single dependency to your pom.xml file to get started using Seam Solder:


<dependency>
   <groupId>org.jboss.seam.solder</groupId>
   <artifactId>seam-solder</artifactId>
   <version>${seam.solder.version}</version>
</dependency>

This artifact includes the combined API and implementation.

Tip

Substitute the expression ${seam.solder.version} with the most recent or appropriate version of Seam Solder. Alternatively, you can create a Maven user-defined property to satisfy this substitution so you can centrally manage the version.

To be more strict, you can use the API at compile time and only include the implementation at runtime. This protects you from inadvertantly depending on an implementation class.


<dependency>
   <groupId>org.jboss.seam.solder</groupId>
   <artifactId>seam-solder-api</artifactId>
   <version>${seam.solder.version}</version>
   <scope>compile</scope>
</dependency>

<dependency>
   <groupId>org.jboss.seam.solder</groupId>
   <artifactId>seam-solder-impl</artifactId>
   <version>${seam.solder.version}</version>
   <scope>runtime</scope>
</dependency>

In a Servlet 3.0 or Java EE 6 environment, your configuration is now complete!

You're all setup. It's time to dive into all the useful stuff that Seam Solder provides!

Seam Solder provides a number enhancements to the CDI programming model which are under trial and may be included in later releases of Contexts and Dependency Injection.

According to the CDI standard, the @Named annotation assigns a name to a bean equal to the value specified in the @Named annotation or, if a value is not provided, the simple name of the bean class. This behavior aligns is with the needs of most application developers. However, framework writers should avoid trampling on the "root" bean namespace. Instead, frameworks should specify qualified names for built-in components. The motivation is the same as qualifying Java types. The @FullyQualified provides this facility without sacrificing type-safety.

Seam Solder allows you to customize the bean name using the complementary @FullyQualified annotation. When the @FullyQualified annotation is added to a @Named bean type, producer method or producer field, the standard bean name is prefixed with the name of the Java package in which the bean resides, the segments separated by a period. The resulting fully-qualified bean name (FQBN) replaces the standard bean name.

package com.acme;

      
@FullyQualified @Named
public class NamedBean {
   public String getAge()
   {
      return 5;
   }
}

The bean in the previous code listing is assigned the name com.acme.namedBean. The value of its property age would be referenced in an EL expression (perhaps in a JSF view template) as follows:

#{com.acme.namedBean.age}

The @FullyQualified annotation is permitted on a bean type, producer method or producer field. It can also be used on a Java package, in which case all @Named beans in that package get a bean name which is fully-qualified.

@FullyQualified

package com.acme;

If you want to use a different Java package as the namespace of the bean, rather than the Java package of the bean, you specify any class in that alternative package in the annotation value.

package com.acme;

      
@FullyQualified(ClassInOtherPackage.class) @Named
public class CustomNamespacedNamedBean {
   ...
}

Seam Solder provides an extensible, injectable resource loader. The resource loader can provide URLs or managed input streams. By default the resource loader will look at the classpath, and the servlet context if available.

If the resource name is known at development time, the resource can be injected, either as a URL or an InputStream:

   @Inject

   @Resource("WEB-INF/beans.xml")
   URL beansXml;
   @Inject
   @Resource("WEB-INF/web.xml")
   InputStream webXml;

If the resource name is not known, the ResourceProvider can be injected, and the resource looked up dynamically:

   @Inject

   void readXml(ResourceProvider provider, String fileName) {
      InputStream is = provider.loadResourceStream(fileName);
   }

If you need access to all resources under a given name known to the resource loader (as opposed to first resource loaded), you can inject a collection of resources:

   @Inject

   @Resource("WEB-INF/beans.xml")
   Collection<URL> beansXmls;
   @Inject
   @Resource("WEB-INF/web.xml")
   Collection<InputStream> webXmls;

Tip

Any input stream injected, or created directly by the ResourceProvider is managed, and will be automatically closed when the bean declaring the injection point of the resource or provider is destroyed.

If the resource is a Properties bundle, you can also inject it as a set of Properties:

   @Inject

   @Resource("META-INF/aws.properties")
   Properties awsProperties;

Seam Solder integrates JBoss Logging 3 as its logging framework of choice. JBoss Logging 3 is a modern logging framework offering:

To use a typed logger, first create the logger definition:

@MessageLogger

interface TrainSpotterLog {
   // Define log call with message, using printf-style interpolation of parameters
   @LogMessage @Message("Spotted %s diesel trains") 
   void dieselTrainsSpotted(int number);
}

You can then inject the typed logger with no further configuration:

   // Use the train spotter log, with the log category "trains"

   @Inject @Category("trains") TrainSpotterLog log;

and use it:

log.dieselTrainsSpotted(7);

JBoss Logging will use the default locale unless overridden:

   // Use the train spotter log, with the log category "trains", and select the UK locale

   @Inject @Category("trains") @Locale("en_GB") TrainSpotterLog log;

You can also log exceptions:

@MessageLogger

interface TrainSpotterLog {
   // Define log call with message, using printf-style interpolation of parameters
   // The exception parameter will be logged as an exception
   @LogMessage @Message("Failed to spot train %s") 
   void missedTrain(String trainNumber,@Cause Exception exception);
}

You can then log a message with an exception:

log.missedTrain("RH1", cause);

You can also inject a "plain old" Logger:

   @Inject Logger log;

Log messages created from this Logger will have a category (logger name) equal to the fully-qualified class name of the bean implementation class. You can specify a category explicitly using an annotation.

   @Inject @Category("billing") Logger log;

You can also specify a category using a reference to a type:

   @Inject @TypedCategory(BillingService.class) Logger log;

Typed loggers also provide internationalization support, simply add the @MessageBundle annotation to the logger interface (not currently supported).

Sometimes you need to access the message directly (for example to localize an exception message). Seam Solder let's you inject a typed message bundle. First, declare the message bundle:

@MessageBundle

interface TrainMessages {
   // Define a message using printf-style interpolation of parameters
   @Message("No trains spotted due to %s") 
   String noTrainsSpotted(String cause);
}

Inject it:

@Inject @MessageBundle TrainMessages messages;

And use it:

   throw new BadDayException(messages.noTrainsSpotted("leaves on the line"));

Seam Solder provides a number of utilility classes to make working with Annotations and AnnotatedTypes easier. This chapter will walk you each utility, and give you an idea of how to use it. For more detail, take a look at the javaodoc on each class.

Seam Solder provides an AnnotatedType implementation that should be suitable for most portable extensions needs. The AnnotatedType is created from AnnotatedTypeBuilder as follows:

AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder()

      .readFromType(baseType,true) /* readFromType can read from an AnnotatedType or a class */
      .addToClass(ModelLiteral.INSTANCE) /* add the @Model annotation */
      .create();

Here we create a new builder, and initialize it using an existing AnnotatedType. We can then add or remove annotations from the class, and its members. When we have finished modifying the type, we call create() to spit out a new, immutable, AnnotatedType.

AnnotatedTypeBuilder also allows you to specify a "redefinition" which can be applied to the type, a type of member, or all members. The redefiner will receive a callback for any annotations present which match the annotation type for which the redefinition is applied. For example, to remove the qualifier @Unique from any class member and the type:

AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder()

      .readFromType(baseType,true)
      .redefine(Unique.class, new AnnotationRedefiner<Unique>() {
      
         public void redefine(RedefinitionContext<A> ctx) {
            ctx.getAnnotationBuilder().remove(Unique.class);
         }
            
      }
      .create();

Sometimes you may need an annotation instance for an annotation whose type is not known at development time. Seam Solder provides a AnnotationInstanceProvider class that can create an AnnotationLiteral instance for any annotation at runtime. Annotation attributes are passed in via a Map<String,Object>. For example given the follow annotation:

@Retention(RetentionPolicy.RUNTIME)

public @interface MultipleMembers {
   int intMember();
   long longMember();
   short shortMember();
   float floatMember();
   double doubleMember();
   byte byteMember();
   char charMember();
   boolean booleanMember();
   int[] intArrayMember();
}

We can create an annotation instance as follows:

/* Create a new provider */

   AnnotationInstanceProvider provider = new AnnotationInstanceProvider();
    /* Set the value for each of attributes */
    Map<String, Object> values = new HashMap<String, Object>();
    values.put("intMember", 1);
    values.put("longMember", 1);
    values.put("shortMember", 1);
    values.put("floatMember", 0);
    values.put("doubleMember", 0);
    values.put("byteMember", ((byte) 1));
    values.put("charMember", 'c');
    values.put("booleanMember", true);
    values.put("intArrayMember", new int[] { 0, 1 });
    
    /* Generate the instance */
    MultipleMembers an = provider.get(MultipleMembers.class, values);

When developing a framework that builds on CDI, you may need to obtain the BeanManager for the application, can't simply inject it as you are not working in an object managed by the container. The CDI specification allows lookup of java:comp/BeanManager in JNDI, however some environments don't support binding to this location (e.g. servlet containers such as Tomcat and Jetty) and some environments don't support JNDI (e.g. the Weld SE container). For this reason, most framework developers will prefer to avoid a direct JNDI lookup.

Often it is possible to pass the correct BeanManager to the object in which you require it, for example via a context object. For example, you might be able to place the BeanManager in the ServletContext, and retrieve it at a later date.

On some occasions however there is no suitable context to use, and in this case, you can take advantage of the abstraction over BeanManager lookup provided by Seam Solder. To lookup up a BeanManager, you can extend the abstract BeanManagerAware class, and call getBeanManager():

public class WicketIntegration extends BeanManagerAware {


   public WicketManager getWicketManager() {
      Bean<?> bean = getBeanManager().getBean(Instance.class);
      ... // and so on to lookup the bean
   }
   
}

The benefit here is that BeanManagerAware class will first look to see if its BeanManager injection point was satisified before consulting the providers. Thus, if injection becomes available to the class in the future, it will automatically start the more efficient approach.

Occasionally you will be working in an existing class hierarchy, in which case you can use the accessor on BeanManagerLocator. For example:

public class ResourceServlet extends HttpServlet {


   protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
         throws ServletException, IOException {
      BeanManager beanManager = new BeanManagerLocator().getBeanManager();
      ...
   }
}

If this lookup fails to resolve a BeanManager, the BeanManagerUnavailableException, a runtime exception, will be thrown. If you want to perform conditional logic based on whether the BeanManager is available, you can use this check:

public class ResourceServlet extends HttpServlet {


   protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
         throws ServletException, IOException {
      BeanManagerLocator locator = new BeanManagerLocator();
      if (locator.isBeanManagerAvailable()) {
         BeanManager beanManager = locator.getBeanManager();
         ... // work with the BeanManager
      }
      else {
         ... // work without the BeanManager
      }
   }
}

However, keep in mind that you can inject into Servlets in Java EE 6!! So it's very likely the lookup isn't necessary, and you can just do this:

public class ResourceServlet extends HttpServlet {


   @Inject
   private BeanManager beanManager;
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
         throws ServletException, IOException {
      ... // work with the BeanManager
   }
}

Seam Solder provides a number of base classes which can be extended to create custom beans. Seam Solder also provides bean builders which can be used to dynamically create beans using a fluent API.

AbstractImmutableBean

An immutable (and hence thread-safe) bean, whose constructor will substitute specification defaults if null is passed for a particular attribute. Subclasses must implement the create() and destroy() methods.

AbstractImmutableProducer

An immutable (and hence thread-safe) abstract class for creating producers. Subclasses must implement produce() and dispose().

BeanBuilder

A builder for creating immutable beans which can read the type and annotations from an AnnotatedType.

Beans

A set of utilities for working with beans.

ForwardingBean

A base class for implementing Bean which forwards all calls to delegate().

ForwardingInjectionTarget

A base class for implementing InjectionTarget which forwards all calls to delegate().

ForwardingObserverMethod

A base class for implementing ObserverMethod which forwards all calls to delegate().

ImmutableBean

An immutable (and hence thread-safe) bean, whose constructor will substitute specification defaults if null is passed for a particular attribute. An implementation of ContextualLifecycle may be registered to receive lifecycle callbacks.

ImmutableInjectionPoint

An immutable (and hence thread-safe) injection point.

ImmutableNarrowingBean

An immutable (and hence thread-safe) narrowing bean. Narrowing beans allow you to build a general purpose bean (likely a producer method), and register it for a narrowed type (or qualifiers).

ImmutablePassivationCapableBean

An immutable (and hence thread-safe) bean, whose constructor will substitute specification defaults if null is passed for a particular attribute. An implementation of ContextualLifecycle may be registered to receive lifecycle callbacks. The bean implements PassivationCapable, and an id must be provided.

ImmutablePassivationCapableNarrowingBean

An immutable (and hence thread-safe) narrowing bean. Narrowing beans allow you to build a general purpose bean (likely a producer method), and register it for a narrowed type (or qualifiers). The bean implements PassivationCapable, and an id must be provided.

NarrowingBeanBuilder

A builder for creating immutable narrowing beans which can read the type and annotations from an AnnotatedType.

The use of these classes is in general trivially understood with an understanding of basic programming patterns and the CDI specification, so no in depth explanation is provided here. The JavaDoc for each class and method provides more detail.

Properties are a convenient way of locating and working with JavaBean properties. They can be used with properties exposed via a getter/setter method, or directly via the field of a bean, providing a uniform interface that allows you all properties in the same way.

Property queries allow you to interrogate a class for properties which match certain criteria.

Once you have created the PropertyQuery instance, you can add search criteria. Seam Solder provides three built-in criteria types, and it is very easy to add your own. A criteria is added to a query via the addCriteria() method. This method returns an instance of the PropertyQuery, so multiple addCriteria() invocations can be stacked.

After creating the PropertyQuery and setting the criteria, the query can be executed by invoking either the getResultList() or getFirstResult() methods. The getResultList() method returns a List of Property objects, one for each matching property found that matches all the specified criteria:

   List<Property<String>> results = PropertyQueries.<String>createQuery(Foo.class)
     .addCriteria(TypedPropertyCriteria(String.class))
     .getResultList();

If no matching properties are found, getResultList() will return an empty List. If you know that the query will return exactly one result, you can use the getFirstResult() method instead:

   Property<String> result = PropertyQueries.<String>createQuery(Foo.class)
      .addCriteria(NamedPropertyCriteria("bar"))
      .getFirstResult();

If no properties are found, then getFirstResult() will return null. Alternatively, if more than one result is found, then getFirstResult() will return the first property found.

Alternatively, if you know that the query will return exactly one result, and you want to assert that assumption is true, you can use the getSingleResult() method instead:

   Property<String> result = PropertyQueries.<String>createQuery(Foo.class)
      .addCriteria(NamedPropertyCriteria("bar"))
      .getSingleResult();

If no properties are found, or more than one property is found, then getSingleResult() will throw an exception. Otherwise, getSingleResult() will return the sole property found.

Sometimes you may not be interested in read only properties, so getResultList(),getFirstResult() and getSingleResult() have corresponding getWritableResultList(),getWritableFirstResult() and getWritableSingleResult() methods, that will only return properties that are not read-only. This means that if there is a field and a getter method that resolve to the same property, instead of getting a read-only MethodProperty you will get a writable FieldProperty.

Unwrapping producer methods allow you to create injectable objects that have "self-managed"" lifecycles, and are particularly useful if you have need a bean whose lifecycle does not exactly match one of the lifecycle of one of the existing scopes. The lifecycle of the bean is are managed by the bean that defines the producer method, and changes to the unwrapped object are immediately visible to all clients.

You can declare a method to be an unwrapping producer method by annotating it @Unwraps. The return type of the managed producer must be proxyable (see Section 5.4.1 of the CDI specification, "Unproxyable bean types"). Every time a method is called on unwrapped object the invocation is forwarded to the result of calling the unwrapping producer method - the unwrapped object.

For example consider a permission manager (that manages the current permission), and a security manager (that checks the current permission level). Any changes to permission in the permission manager are immediately visible to the security manager.

@SessionScoped

class PermissionManager {
   
   Permission permission;
  
   void setPermission(Permission permission) {
      this.permission=permission;
   }
  
   @Unwraps @Current
   Permission getPermission() {
      return this.permission;
   }
}
@SessionScoped

class SecurityManager {
   
   @Inject @Current
   Permission permission;
  
   boolean checkAdminPermission() {
      return permission.getName().equals("admin");
   }
}

When permission.getName() is called, the unwrapped Permission forwards the invocation of getName() to the result of calling PermissionManager.getPermission().

For example you could raise the permission level before performing a sensitive operation, and then lower it again afterwards:

public class SomeSensitiveOperation {

   
   @Inject
   PermissionManager permissionManager;
  
   public void perform() {
      try {
         permissionManager.setPermission(Permissions.ADMIN);
         // Do some sensitive operation
      } finally {
         permissionManager.setPermission(Permissions.USER);
      }
   }
}

Unwrapping producer methods can have parameters injected, including InjectionPoint (which repreents) the calling method.

Suppose you have a situation where you want to provide a default implementation of a particular service and allow the user to override it as needed. Although this may sound like a job for an alternative, they have some restrictions that may make them undesirable in this situation. If you were to use an alternative it would require an entry in every beans.xml file in an application.

Developers consuming the extension will have to open up the any jar file which references the default bean, and edit the beans.xml file within, in order to override the service. This is where default beans come in.

Default beans allow you to create a default bean with a specified type and set of qualifiers. If no other bean is installed that has the same type and qualifiers, then the default bean will be installed.

Let's take a real world example - a module that allows you to evaluate EL (something that Seam Solder provides!). If JSF is available we want to use the FunctionMapper provided by the JSF implementation to resolve functions, otherwise we just want to use a a default FunctionMapper implementation that does nothing. We can achieve this as follows:

@DefaultBean(type = FunctionMapper.class)

@Mapper
class FunctionMapperImpl extends FunctionMapper {
   @Override
   Method resolveFunction(String prefix, String localName) {
      return null;
   }
}

And in the JSF module:

class FunctionMapperProvider {

   
   @Produces
   @Mapper
   FunctionMapper produceFunctionMapper() {
      return FacesContext.getCurrentInstance().getELContext().getFunctionMapper();
   }
}

If FunctionMapperProvider is present then it will be used by default, otherwise the default FunctionMapperImpl is used.

A producer method or producer field may be defined to be a default producer by placing the @DefaultBean annotation on the producer. For example:

class CacheManager {
   
   @DefaultBean(Cache.class)
   Cache getCache() {
      ...
   }
     
}

Any producer methods or producer fields declared on a default managed bean are automatically registered as default producers, with Method.getGenericReturnType() or Field.getGenericType() determining the type of the default producer. The default producer type can be overridden by specifying @DefaultBean on the producer method or field.

Many common services and API's require the use of more than just one class. When exposing these services via CDI, it would be time consuming and error prone to force the end developer to provide producers for all the different classes required. Generic beans provide a solution, allowing a framework author to provide a set of related beans, one for each single configuration point defined by the end developer. The configuration points specifies the qualifiers which are inherited by all beans in the set.

To illustrate the use of generic beans, we'll use the following example. Imagine we are writing an extension to integrate our custom messaging solution "ACME Messaging" with CDI. The ACME Messaging API for sending messages consists of several interfaces:

MessageQueue
The message queue, onto which messages can be placed, and acted upon by ACME Messaging
MessageDispatcher
The dispatcher, responsible for placing messages created by the user onto the queue
DispatcherPolicy
The dispatcher policy, which can be used to tweak the dispatch policy by the client
MessageSystemConfiguration
The messaging system configuration

We want to be able to create as many MessageQueue configurations's as they need, however we do not want to have to declare each producer and the associated plumbing for every queue. Generic beans are an ideal solution to this problem.

Before we take a look at creating generic beans, let's see how we will use them.

Generic beans are configured via producer methods and fields. We want to create two queues to interact with ACME Messaging, a default queue that is installed with qualifier @Default and a durable queue that has qualifier @Durable:

class MyMessageQueues {

   
   @Produces
   @ACMEQueue("defaultQueue")
   MessageSystemConfiguration defaultQueue = new MessageSystemConfiguration();
   
   @Produces @Durable @ConversationScoped
   @ACMEQueue("durableQueue")
   MessageSystemConfiguration producerDefaultQueue() {
      MessageSystemConfiguration config = new MessageSystemConfiguration();
      config.setDurable(true);
      return config;
   }
}

Looking first at the default queue, in addition to the @Produces annotation, the generic configuration annotation ACMEQueue, is used, which defines this to be a generic configuration point for ACME messaging (and cause a whole set of beans to be created, exposing for example the dispatcher). The generic configuration annotation specifies the queue name, and the value of the producer field defines the messaging system's configuration (in this case we use all the defaults). As no qualifier is placed on the definition, @Default qualifier is inherited by all beans in the set.

The durable queue is defined as a producer method (as we want to alter the configuration of the queue before having Seam Solder use it). Additionally, it specifies that the generic beans created (that allow for their scope to be overridden) should be placed in the conversation scope. Finally, it specifies that the generic beans created should inherit the qualifier @Durable.

We can now inject our generic beans as normal, using the qualifiers specified on the configuration point:

class MessageLogger {

  
   @Inject
   MessageDispatcher dispatcher;
  
   void logMessage(Payload payload) {
      /* Add metaddata to the message */
      Collection<Header> headers = new ArrayList<Header>();
      ... 
      Message message = new Message(headers, payload);
      dispatcher.send(message);
   }
  
}
class DurableMessageLogger {

  
   @Inject @Durable
   MessageDispatcher dispatcher;
   
   @Inject @Durable
   DispatcherPolicy policy;
   
         
   /* Tweak the dispatch policy to enable duplicate removal */
   @Inject
   void tweakPolicy(@Durable DispatcherPolicy policy) {
      policy.removeDuplicates();
   }
  
   void logMessage(Payload payload) {
      ...
   }
}

It is also possible to configure generic beans using beans by sub-classing the configuration type, or installing another bean of the configuration type through the SPI (e.g. using Seam XML). For example to configure a durable queue via sub-classing:

@Durable @ConversationScoped

@ACMEQueue("durableQueue")
class DurableQueueConfiguration extends MessageSystemConfiguration {
      
   public DurableQueueConfiguration()
   {
      this.durable = true;
   }
}

And the same thing via Seam XML:


<my:MessageSystemConfiguration>
   <my:Durable/>
   <s:ConversationScoped/>
   <my:ACMEQueue>durableQueue</my:ACMEQueue>
   <my:durable>true</my:durable>
</my:MessageSystemConfiguration>

Having seen how we use the generic beans, let's look at how to define them. We start by creating the generic configuration annotation:

@Retention(RUNTIME)

@GenericType(MessageSystemConfiguration.class)
@interface ACMEQueue {
   String name();
   
}

The generic configuration annotation a defines the generic configuration type (in this case MessageSystemConfiguration); the type produced by the generic configuration point must be of this type. Additionally it defines the member name, used to provide the queue name.

Next, we define the queue manager bean. The manager has one producer method, which creates the queue from the configuration:

@GenericConfiguration(ACMEQueue.class) @ApplyScope

class QueueManager {
   @Inject @Generic
   MessageSystemConfiguration systemConfig;
   
   @Inject
   ACMEQueue config;
   
   MessageQueueFactory factory;
   
   @PostConstruct
   void init() {
      factory = systemConfig.createMessageQueueFactory();
   }
   
   @Produces @ApplyScope
   public MessageQueue messageQueueProducer() {
      return factory.createMessageQueue(config.name());
   }
}

The bean is declared to be a generic bean for the @ACMEQueue generic configuration type annotation by placing the @GenericConfiguration annotation on the class. We can inject the generic configuration type using the @Generic qualifier, as well the annotation used to define the queue.

Placing the @ApplyScope annotation on the bean causes it to inherit the scope from the generic configuration point. As creating the queue factory is a heavy operation we don't want to do it more than necessary.

Having created the MessageQueueFactory, we can then expose the queue, obtaining its name from the generic configuration annotation. Additionally, we define the scope of the producer method to be inherited from the generic configuration point by placing the annotation @ApplyScope on the producer method. The producer method automatically inherits the qualifiers specified by the generic configuration point.

Finally we define the message manager, which exposes the message dispatcher, as well as allowing the client to inject an object which exposes the policy the dispatcher will use when enqueing messages. The client can then tweak the policy should they wish.

@Generic(ACMEQueue.class)

class MessageManager {
   @Inject @Generic
   MessageQueue queue;
   
   @Produces @ApplyScope
   MessageDispatcher messageDispatcherProducer() {
      return queue.createMessageDispatcher();
   }
   
   @Produces
   DispatcherPolicy getPolicy() {
      return queue.getDispatcherPolicy();
   }   
   
}

The service handler facility allow you to declare interfaces and abstract classes as automatically implemented beans. Any call to an abstract method on the interface or abstract class will be forwarded to the invocation handler for processing.

If you wish to convert some non-type-safe lookup to a type-safe lookup, then service handlers may be useful for you, as they allow the end user to map a lookup to a method using domain specific annotations.

We will work through using this facility, taking the example of a service which can execute JPA queries upon abstract method calls. First we define the annotation used to mark interfaces as automatically implemented beans. We meta-annotate it, defining the invocation handler to use:

@ServiceHandlerType(QueryHandler.class)

@Retention(RUNTIME)
@Target({TYPE})
@interface QueryService {}

We now define an annotation which provides the query to execute:

@Retention(RUNTIME)

@Target({METHOD})
@interface Query {
   String value();
   
}

And finally, the invocation handler, which simply takes the query, and executes it using JPA, returning the result:

class QueryHandler {

   
   @Inject EntityManager em;
  
   @AroundInvoke
   Object handle(InvocationContext ctx) {
      return em.createQuery(ctx.getMethod().getAnnotation(Query.class).value()).getResultList();
   }
}

Finally, we can define (any number of) interfaces which define our queries:

@QueryService

interface UserQuery {
   
   @Query("select u from User u");
   public List<User> getAllUsers();
}

Finally, we can inject the query interface, and call methods, automatically executing the JPA query.

class UserListManager {

   @Inject 
   UserQuery userQuery;
  
   List<User> users;
   
   @PostConstruct
   void create() {
      users=userQuery.getAllUsers();
   }
}