SeamFramework.orgCommunity Documentation

Seam 3

Bundled Reference Guide


1. Credits
1.1. List of contributors
1.2. Would you like to contribute?
2. Seam
2.1. Overview
2.2. Seam Bill of Materials
I. Solder
Introduction
3. Getting Started
3.1. Maven dependency configuration
3.2. Transitive dependencies
3.3. Pre-Servlet 3.0 configuration
4. Enhancements to the CDI Programming Model
4.1. Preventing a class from being processed
4.1.1. @Veto
4.1.2. @Requires
4.2. @Exact
4.3. @Client
4.4. Named packages
4.5. @FullyQualified bean names
5. Annotation Literals
6. Evaluating Unified EL
6.1. @Resolver
7. Resource Loading
7.1. Extending the Resource Loader
8. Logging, redesigned
8.1. JBoss Logging: The foundation
8.2. Solder Logging: Feature set
8.3. Typed loggers
8.4. Native logger API
8.5. Typed message bundles
8.6. Implementation classes
8.6.1. Generating the implementation classes
8.6.2. Including the implementation classes in Arquillian tests
9. Annotation and AnnotatedType Utilities
9.1. Annotated Type Builder
9.2. Annotation Instance Provider
9.3. Annotation Inspector
9.4. Synthetic Qualifiers
9.5. Reflection Utilities
10. Obtaining a reference to the BeanManager
11. Bean Utilities
12. Properties
12.1. Working with properties
12.2. Querying for properties
12.3. Property Criteria
12.3.1. AnnotatedPropertyCriteria
12.3.2. NamedPropertyCriteria
12.3.3. TypedPropertyCriteria
12.3.4. Creating a custom property criteria
12.4. Fetching the results
13. Unwrapping Producer Methods
14. Default Beans
15. Generic Beans
15.1. Using generic beans
15.2. Defining Generic Beans
16. Service Handler
17. XML Configuration Introduction
17.1. Getting Started
17.2. The Princess Rescue Example
18. Solder Config XML provider
18.1. XML Namespaces
18.2. Adding, replacing and modifying beans
18.3. Applying annotations using XML
18.4. Configuring Fields
18.4.1. Initial Field Values
18.4.2. Inline Bean Declarations
18.5. Configuring methods
18.6. Configuring the bean constructor
18.7. Overriding the type of an injection point
18.8. Configuring Meta Annotations
18.9. Virtual Producer Fields
18.10. More Information
Introduction
19. Installation
19.1. Pre-Servlet 3.0 configuration
20. Servlet event propagation
20.1. Servlet context lifecycle events
20.2. Application initialization
20.3. Servlet request lifecycle events
20.4. Servlet response lifecycle events
20.5. Servlet request context lifecycle events
20.6. Session lifecycle events
20.7. Session activation events
21. Injectable Servlet objects and request state
21.1. @Inject @RequestParam
21.2. @Inject @HeaderParam
21.3. @Inject ServletContext
21.4. @Inject ServletRequest / HttpServletRequest
21.5. @Inject ServletResponse / HttpServletResponse
21.6. @Inject HttpSession
21.7. @Inject HttpSessionStatus
21.8. @Inject @ContextPath
21.9. @Inject List<Cookie>
21.10. @Inject @CookieParam
21.11. @Inject @ServerInfo
21.12. @Inject @Principal
22. Servlet Exception Handling Integration
22.1. Background
22.2. Defining a exception handler for a web request
23. Retrieving the BeanManager from the servlet context
24. Exception Handling - Introduction
24.1. How Solder's Exception Handling Works
25. Exception Handling - Usage
25.1. Eventing into the exception handling framework
25.1.1. Manual firing of the event
25.1.2. Using the @ExceptionHandled Interceptor
25.2. Exception handlers
25.3. Exception handler annotations
25.3.1. @HandlesExceptions
25.3.2. @Handles
25.4. Exception chain processing
25.5. Exception handler ordering
25.5.1. Traversal of exception type hierarchy
25.5.2. Handler precedence
25.6. APIs for exception information and flow control
25.6.1. CaughtException
25.6.2. ExceptionStack
26. Exception handling - Advanced Features
26.1. Exception Modification
26.1.1. Introduction
26.1.2. Usage
26.2. Filtering Stack Traces
26.2.1. Introduction
26.2.2. ExceptionStackOutput
26.2.3. StackFrameFilter
26.2.4. StackFrameFilterResult
26.2.5. StackFrame
27. Exception Handling - Framework Integration
27.1. Creating and Firing an ExceptionToCatch event
27.2. Default Handlers and Qualifiers
27.2.1. Default Handlers
27.2.2. Qualifiers
27.3. Supporting ServiceHandlers
27.4. Programmatic Handler Registration
Exception Handling - Glossary
II. Seam Persistence
28. Seam Persistence Reference
28.1. Introduction
28.2. Getting Started
28.3. Transaction Management
28.3.1. Configuration
28.3.2. Declarative Transaction Management
28.4. Seam-managed persistence contexts
28.4.1. Using a Seam-managed persistence context with JPA
28.4.2. Seam-managed persistence contexts and atomic conversations
28.4.3. Using EL in EJB-QL/HQL
28.4.4. Setting up the EntityManager
III. Seam Transaction
29. Seam Transaction Reference
29.1. Introduction
IV. Seam Security
30. Security - Introduction
30.1. Overview
30.1.1. Authentication
30.1.2. Identity Management
30.1.3. External Authentication
30.1.4. Authorization
30.2. Configuration
30.2.1. Maven Dependencies
30.2.2. Enabling the Security Interceptor
31. Security - Authentication
31.1. Basic Concepts
31.2. Built-in Authenticators
31.3. Which Authenticator will Seam use?
31.4. Writing a custom Authenticator
32. Security - Identity Management
32.1. Overview
32.2. Configuring Seam to use Identity Management with JPA
32.2.1. Recommended database schema
32.2.2. The @IdentityEntity and @IdentityProperty annotations
32.2.3. Identity Object
32.2.4. Credential
32.2.5. Identity Object Relationship
32.2.6. Attributes
32.3. Managing Users, Groups and Roles
32.3.1. Managing Users and Groups
32.3.2. Managing Relationships
32.3.3. Managing Roles
33. Security - External Authentication
33.1. Introduction
33.1.1. Configuration
33.2. OpenID
33.2.1. Overview
33.2.2. Enabling OpenID for your application
33.2.3. Choosing which OpenID provider to use
33.2.4. Managing the OpenID authentication process
34. Security - Authorization
34.1. Configuration
34.2. Basic Concepts
34.2.1. IdentityType
34.2.2. User
34.2.3. Group
34.2.4. Role
34.2.5. RoleType
34.3. Role and Group-based authorization
34.4. Typesafe authorization
34.4.1. Creating a typesafe security binding
34.4.2. Creating an authorizer method
34.4.3. Applying the binding to your business methods
34.4.4. Built-in security binding annotations
35. Security - Events
35.1. Introduction
35.2. Event list
35.3. Usage Example
V. Seam International
Introduction
36. Installation
37. Locales
37.1. Application Locale
37.2. User Locale
37.3. Available Locales
38. Timezones
38.1. Joda Time
38.2. Application TimeZone
38.3. User TimeZone
38.4. Available TimeZones
39. Messages
39.1. Message Creation
39.2. Properties Files
VI. Seam Faces
Introduction
40. Installation
40.1. Maven dependency configuration
40.2. Pre-Servlet 3.0 configuration
40.3. How to setup JSF in a Java EE 6 webapp
41. Faces Events Propagation
41.1. JSF Phase events
41.1.1. Seam Faces Phase events
41.1.2. Phase events listing
41.2. JSF system events
41.2.1. Seam Faces System events
41.2.2. System events listing
41.2.3. Component system events
42. Faces Scoping Support
42.1. @RenderScoped
42.2. @Inject javax.faces.context.Flash flash
42.3. @ViewScoped
43. Messages API
43.1. Adding Messages
43.2. Displaying pending messages
44. Faces Artifact Injection
44.1. @*Scoped and @Inject in Validators and Converters
44.2. @Inject'able Faces Artifacts
45. Seam Faces Components
45.1. Introduction
45.2. <s:validateForm>
45.3. <s:viewAction>
45.3.1. Motivation
45.3.2. Usage
45.3.3. View actions vs the PreRenderViewEvent
45.4. ObjectConverter
45.5. UI Input Container
VII. Seam Reports
Introduction
46. Installation
46.1. Installation using Seam Forge
46.1.1. Plugin Installation
46.1.2. Plugin Configuration
47. Usage
47.1. Quick Start
47.2. Annotations
47.3. Troubleshooting
VIII. Seam Mail
48. Seam Mail Introduction
48.1. Getting Started
49. Configuration
49.1. Minimal Configuration
50. Core Usage
50.1. Intro
50.2. Contacts
50.2.1. String Based
50.2.2. InternetAddress
50.2.3. EmailContact
50.2.4. Content
50.2.5. Attachments
51. Templating
51.1. Velocity
51.2. Freemarker
52. Advanced Features
52.1. MailTransporter
52.2. MailConfig
IX. Seam Remoting
53. Seam Remoting - Basic Features
53.1. Configuration
53.1.1. Dynamic type loading
53.2. The "Seam" object
53.2.1. A Hello World example
53.2.2. Seam.createBean
53.3. The Context
53.3.1. Setting and reading the Conversation ID
53.3.2. Remote calls within the current conversation scope
53.4. Working with Data types
53.4.1. Primitives / Basic Types
53.4.2. JavaBeans
53.4.3. Dates and Times
53.4.4. Enums
53.4.5. Collections
53.5. Debugging
53.6. Messages
53.7. Handling Exceptions
53.8. The Loading Message
53.8.1. Changing the message
53.8.2. Hiding the loading message
53.8.3. A Custom Loading Indicator
53.9. Controlling what data is returned
53.9.1. Constraining normal fields
53.9.2. Constraining Maps and Collections
53.9.3. Constraining objects of a specific type
53.9.4. Combining Constraints
54. Seam Remoting - Model API
54.1. Introduction
54.2. Model Operations
54.3. Fetching a model
54.3.1. Fetching a bean value
54.4. Modifying model values
54.5. Expanding a model
54.6. Applying Changes
55. Seam Remoting - Bean Validation
55.1. Validating a single object
55.2. Validating a single property
55.3. Validating multiple objects and/or properties
55.4. Validation groups
55.5. Handling validation failures
X. Seam REST
Introduction
56. Installation
56.1. Basics
56.2. Transitive dependencies
56.3. Registering JAX-RS components explicitly
56.4. Servlet container support
57. Exception Handling
57.1. Solder Exception Handling Integration
57.2. Declarative Exception Mapping
57.2.1. Annotation-based configuration
57.2.2. XML configuration
57.2.3. Declarative exception mapping processing
58. Bean Validation Integration
58.1. Validating HTTP requests
58.1.1. Validating entity body
58.1.2. Validating resource fields
58.1.3. Validating other method parameters
58.2. Validation configuration
58.3. Using validation groups
59. Templating support
59.1. Creating JAX-RS responses using templates
59.1.1. Accessing the model
59.2. Built-in support for templating engines
59.2.1. FreeMarker
59.2.2. Apache Velocity
59.2.3. Pluggable support for templating engines
59.2.4. Selecting preferred templating engine
60. RESTEasy Client Framework Integration
60.1. Using RESTEasy Client Framework with Seam REST
60.2. Manual ClientRequest API
60.3. Client Executor Configuration
61. Seam REST Dependencies
61.1. Transitive Dependencies
61.2. Optional dependencies
61.2.1. FreeMarker
61.2.2. Apache Velocity
61.2.3. RESTEasy
XI. Seam JCR
62. Seam JCR - Introduction
62.1. Introduction
62.2. Maven dependency configuration
63. Seam JCR - JBoss ModeShape Integration
63.1. ModeShape Integration Installation
63.2. Usage
64. Seam JCR - JackRabbit Integration
64.1. JackRabbit Integration Installation
64.2. Usage
65. Seam JCR - Event Mapping
65.1.
65.2.
66. Seam JCR - Object Content Mapping
66.1. What is Object Content Mapping?
66.2. Mapping and Conversion Capabilities
66.3. JCR Data Access Objects
XII. Seam JMS
67. Introduction
67.1. Mission statement
67.2. Seam 3 JMS Module Overview
68. Installation
69. Resource Injection
69.1. JMS Resource Injection
69.1.1. Destination Based Injection
69.1.2. Resource Configuration
69.2. Module Extensions
70. Messaging API
70.1. QueueBuilder and TopicBuilder
70.2. Message Manager
70.3. Durable Messaging Capabilities
70.4. MessageListeners versus Message Driven Beans
71. Bridging the Gap
71.1. Event Routing
71.1.1. Routes
71.2. Routing CDI Events to JMS
71.2.1. Usage
71.3. CDI Events from JMS Messages
71.3.1. Usage
72. Annotation Routing APIs
72.1. Observer Method Interfaces
XIII. Seam Validation
73. Introduction
74. Installation
74.1. Prerequisites
74.2. Maven setup
74.3. Manual setup
75. Dependency Injection
75.1. Retrieving of validator factory and validators via dependency injection
75.2. Dependency injection for constraint validators
76. Method Validation
XIV. Seam Social
Introduction
77. Getting Started
77.1. Building
77.2. Usage big picture
77.3. Starting with OAuth configuration
77.3.1. Create an OAutConfigSettings bean thru Seam configuration (in bean.xml)
77.3.2. Adding the @ConfigureOAuth annotation when injecting the OAuth service bean
77.4. Inject an OAuthService bean with one of the following ways :
77.5. Request the Authorization URL for the service and redirect the app to this url
77.6. Store the verifier in OAuthService bean and init access token
77.7. After what we can send calls to the service
77.8. Testing
XV. Seam Spring
78. Seam Spring - Introduction
78.1. Features
79. Seam Spring - Installation
79.1. Maven dependency configuration
80. Seam Spring - Architecture and Usage
80.1. Accessing Spring artifacts from CDI
80.1.1. Accessing Spring application contexts
80.1.2. Exposing Spring beans as CDI beans
80.2. Importing CDI beans into Spring applications
80.2.1. Registering a BeanManager
80.2.2. Importing a CDI bean as a Spring bean
XVI. Seam Wicket
Introduction
81. Installation
82. Seam for Apache Wicket Features
82.1. Injection
82.2. Conversation Control
82.3. Conversation Propagation

Seam's mission is to provide a fully-integrated development platform for building rich, standards-based Internet applications tailored for traditional and cloud deployments.

The Seam 3 project is organized as a collection of modules and developer tooling tailored for Java EE 6 application development, built on top of the component model defined by JSR-299 Context and Dependency Injection (CDI). CDI is a JCP standard, you can find out more about it at http://jcp.org/en/jsr/summary?id=299.

Seam's modules leverage portable CDI extensions to build on the core Java EE functionality and integrate with JBoss and third-party projects. Together, these modules provide many of the popular features and integrations from Seam 2 (security, internationalization, JSF, rules, BPM) while also exploring new integrations and designs.

The developer tooling for Seam is provided by JBoss Tools and Seam Forge. JBoss Tools enhances Eclipse with features designed to help developers write, test and deploy enterprise Java applications. Seam Forge is an incremental project enhancement API and shell.

This guide steps you through the modules and select tooling, covering the purpose, APIs and usage scenarios for each. Collectively, this software should give you everything you need to develop comprehensive, robust and compelling enterprise applications.

The Seam 3 build is based on Maven 3. Each Seam module is a separate project, with its own release cycle. Each Seam module is a multi-module project contains the api, implementation, examples and documentation. Select modules are assembled together to create a Seam distribution, or stack release.

To keep the modules in sync, the Seam project publishes a special Maven POM known as a "Bill of Materials" (BOM), which we'll refer to as the Seam BOM. The Seam BOM defines the versions of all the Seam modules and third-party libraries that are used in the Seam stack using Maven's dependency management facility.

You can import these version definitions into your project by adding the Seam BOM as a dependency with scope import. The benefit of doing so is that it relieves you from having to specify the version of any Seam module explicitly. It also means you can upgrade all your Seam modules at once by just updating the version of the BOM.

Generally, the easiest way to accomplish this import is by first defining a property for the Seam BOM version:


<properties>
        <seam.version>3.0.0.Final</seam.version>
</properties>

Then you add the following dependency declaration to the dependencyManagement section of your project's POM file (or parent POM, if you use one).


<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.seam</groupId>
                <artifactId>seam-bom</artifactId>
                <version>${seam.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

Then, it's a simple matter to declare which Seam module dependencies your project requires by adding them inside the dependencies section. There's no need to specify a version of the module as it gets inherited from the Seam BOM.


<dependency>
    <groupId>org.jboss.seam.solder</groupId>
    <artifactId>seam-solder</artifactId>
</dependency>

To see which version is going to get selected, use the dependency analysis tools in Maven:

mvn dependency:tree

You may upgrade an individual module by specifying the version explicitly. There's no crime in doing so. The Seam BOM is there as a convenience and a reference point for the recommended module version matrix. It's up to you how closely to follow it.

Each of the Seam modules also use the Seam BOM to keep the versions of related modules in sync. Once in a while, a module may specify a version of another module that's different from the Seam BOM. We usually try to get this worked out by the time we make a Seam stack release to fix the version matrix.

Refer to the Build System Architecture page on the Seam website for more detail about how the Seam 3 project is structured. Though, for the purpose of using Seam, how to import the module artifacts is likely all you need to know about the project's build.

Table of Contents

Introduction
3. Getting Started
3.1. Maven dependency configuration
3.2. Transitive dependencies
3.3. Pre-Servlet 3.0 configuration
4. Enhancements to the CDI Programming Model
4.1. Preventing a class from being processed
4.1.1. @Veto
4.1.2. @Requires
4.2. @Exact
4.3. @Client
4.4. Named packages
4.5. @FullyQualified bean names
5. Annotation Literals
6. Evaluating Unified EL
6.1. @Resolver
7. Resource Loading
7.1. Extending the Resource Loader
8. Logging, redesigned
8.1. JBoss Logging: The foundation
8.2. Solder Logging: Feature set
8.3. Typed loggers
8.4. Native logger API
8.5. Typed message bundles
8.6. Implementation classes
8.6.1. Generating the implementation classes
8.6.2. Including the implementation classes in Arquillian tests
9. Annotation and AnnotatedType Utilities
9.1. Annotated Type Builder
9.2. Annotation Instance Provider
9.3. Annotation Inspector
9.4. Synthetic Qualifiers
9.5. Reflection Utilities
10. Obtaining a reference to the BeanManager
11. Bean Utilities
12. Properties
12.1. Working with properties
12.2. Querying for properties
12.3. Property Criteria
12.3.1. AnnotatedPropertyCriteria
12.3.2. NamedPropertyCriteria
12.3.3. TypedPropertyCriteria
12.3.4. Creating a custom property criteria
12.4. Fetching the results
13. Unwrapping Producer Methods
14. Default Beans
15. Generic Beans
15.1. Using generic beans
15.2. Defining Generic Beans
16. Service Handler
17. XML Configuration Introduction
17.1. Getting Started
17.2. The Princess Rescue Example
18. Solder Config XML provider
18.1. XML Namespaces
18.2. Adding, replacing and modifying beans
18.3. Applying annotations using XML
18.4. Configuring Fields
18.4.1. Initial Field Values
18.4.2. Inline Bean Declarations
18.5. Configuring methods
18.6. Configuring the bean constructor
18.7. Overriding the type of an injection point
18.8. Configuring Meta Annotations
18.9. Virtual Producer Fields
18.10. More Information
Introduction
19. Installation
19.1. Pre-Servlet 3.0 configuration
20. Servlet event propagation
20.1. Servlet context lifecycle events
20.2. Application initialization
20.3. Servlet request lifecycle events
20.4. Servlet response lifecycle events
20.5. Servlet request context lifecycle events
20.6. Session lifecycle events
20.7. Session activation events
21. Injectable Servlet objects and request state
21.1. @Inject @RequestParam
21.2. @Inject @HeaderParam
21.3. @Inject ServletContext
21.4. @Inject ServletRequest / HttpServletRequest
21.5. @Inject ServletResponse / HttpServletResponse
21.6. @Inject HttpSession
21.7. @Inject HttpSessionStatus
21.8. @Inject @ContextPath
21.9. @Inject List<Cookie>
21.10. @Inject @CookieParam
21.11. @Inject @ServerInfo
21.12. @Inject @Principal
22. Servlet Exception Handling Integration
22.1. Background
22.2. Defining a exception handler for a web request
23. Retrieving the BeanManager from the servlet context
24. Exception Handling - Introduction
24.1. How Solder's Exception Handling Works
25. Exception Handling - Usage
25.1. Eventing into the exception handling framework
25.1.1. Manual firing of the event
25.1.2. Using the @ExceptionHandled Interceptor
25.2. Exception handlers
25.3. Exception handler annotations
25.3.1. @HandlesExceptions
25.3.2. @Handles
25.4. Exception chain processing
25.5. Exception handler ordering
25.5.1. Traversal of exception type hierarchy
25.5.2. Handler precedence
25.6. APIs for exception information and flow control
25.6.1. CaughtException
25.6.2. ExceptionStack
26. Exception handling - Advanced Features
26.1. Exception Modification
26.1.1. Introduction
26.1.2. Usage
26.2. Filtering Stack Traces
26.2.1. Introduction
26.2.2. ExceptionStackOutput
26.2.3. StackFrameFilter
26.2.4. StackFrameFilterResult
26.2.5. StackFrame
27. Exception Handling - Framework Integration
27.1. Creating and Firing an ExceptionToCatch event
27.2. Default Handlers and Qualifiers
27.2.1. Default Handlers
27.2.2. Qualifiers
27.3. Supporting ServiceHandlers
27.4. Programmatic Handler Registration
Exception Handling - Glossary

Solder is a library of Generally Useful Stuff (TM), particularly if you are developing an application based on CDI (JSR-299 Java Contexts and Dependency Injection), or a CDI based library or framework.

This guide is split into three parts. ??? details extensions and utilities which are likely to be of use to any developer using CDI; ??? describes utilities which are likely to be of use to developers writing libraries and frameworks that work with CDI; ??? discusses extensions which can be used to implement configuration for a framework

Getting started with 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 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 dependencies to your pom.xml file to get started using Solder:


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

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

Tip

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

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

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 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.

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 int 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 {
   ...
}

Solder provides a method to evaluate EL that is not dependent on JSF or JSP, a facility sadly missing in Java EE. To use it inject Expressions into your bean. You can evaluate value expressions, or method expressions. The Solder API provides type inference for you. For example:

class FruitBowl {

   
   @Inject Expressions expressions;
  
   public void run() {
      String fruitName = expressions.evaluateValueExpression("#{fruitBowl.fruitName}");
      Apple fruit = expressions.evaluateMethodExpression("#{fruitBown.getFruit}");
   }
}

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;

Solder brings a fresh perspective to the ancient art of logging. Rather than just giving you an injectable version of the same old logging APIs, Solder goes the extra mile by embracing the type-safety of CDI and eliminating brittle, boilerplate logging statements. The best part is, no matter how you decide to roll it out, you still get to keep your logging engine of choice (for the logging wars will never end!).

Before talking about Solder Logging, you need to first be introduced to JBoss Logging 3. The reason is, JBoss Logging provides the foundation on which Solder's declarative programming model for logging is built. Plus, we have to convince you that you aren't tied to JBoss AS by using it.

JBoss Logging acts as a logging bridge. If you don't add any other logging libraries to your project, it will delegate all logging calls it handles to the logging facility built into the Java platform (commonly referred to as JDK logging). That's nice, because it means your deployment headaches caused by missing logging jars are gone. And you accomplish it all through the use of the Logger type. It has the usual level-based log methods and complimentary ones that provide formatting.

Here's an example of how you obtain a logger and log a basic message:

Logger log = Logger.getLogger(Bean.class);

// log a plain text method
log.debug("I'm using JBoss Logging.");

If you want to use another logging engine, such as SLF4J or Log4J, you just have to add the native library to the deployment. Keep in mind, though, if your application server provides one of these frameworks, it will get chosen instead. On JBoss AS, JBoss Logging will prefer the JBoss LogManager because it's the built-in logging engine. (We are looking into more sophisticated runtime selection of the logging engine).

Here are the providers JBoss Logging supports (and the order in which it looks for them):

  • JBoss LogManager

  • Log4J

  • SLF4J

  • JDK logging

So you get that JBoss Logging is an abstraction. What else is it good for?

JBoss Logging has a facility for formatting log messages, using either the printf syntax or MessageFormat. This makes it possible to use positional parameters to build dynamic log messages based on contextual information.

Logger log = Logger.getLogger(Bean.class);

// log a message formatted using printf-style substitutions
log.infof("My name is %s.", "David");
// log a message formatted using MessageFormat-style substitutions
log.errorv("The license for Solder is the {0}", "APL");

The most significant and distinguishing feature of JBoss Logging is support for typed loggers. A typed logger is an interface that defines methods which serve as logging operations. When a method is invoked on one of these interfaces, the message defined in an annotation on the method is interpolated and written to the underlying logging engine.

Here's an example of a typed logger:

import org.jboss.logging.Message;

import org.jboss.logging.LogMessage;
import org.jboss.logging.MessageLogger;
@MessageLogger
public interface CelebritySightingLog {
    @LogMessage @Message("Spotted celebrity %s!")
    void spottedCelebrity(String name);
}

JBoss Logging has parallel support for typed message bundles, whose methods return a formatted message rather than log it. Combined, these features form the centerpiece of Solder's logging and message bundle programming model (and a foundation for additional support provided by the Seam international module). After looking at the samples provided so far, don't pull out your IDE just yet. We'll get into the details of typed loggers and how to use them in Solder in a later section.

There you have it! JBoss Logging is a low-level API that provides logging abstraction, message formatting and internationalization, and typed loggers. But it doesn't tie you to JBoss AS!

With that understanding, we'll now move on to what Solder does to turn this foundation into a programming model and how to use it in your CDI-based application.

To define a typed logger, first create an interface, annotate it, then add methods that will act as log operations and configure the message it will print using another annotation:

import org.jboss.solder.messages.Message;

import org.jboss.solder.logging.Log;
import org.jboss.solder.logging.MessageLogger;
@MessageLogger
public interface TrainSpotterLog {
    @Log @Message("Spotted %s diesel trains")
    void dieselTrainsSpotted(int number);
}

We have configured the log messages to use printf-style interpolations of parameters (%s).

You can then inject the typed logger with no further configuration necessary. We use another optional annotation to set the category of the logger to "trains" at the injection point, overriding the default category of the fully-qualified class name of the component receiving the injection:

    @Inject @Category("trains")

    private TrainSpotterLog log;

We log a message by simply invoking a method of the typed logger interface:

   log.dieselTrainsSpotted(7);

The default locale will be used unless overridden. Here we configure the logger to use the UK locale:

    @Inject @Category("trains") @Locale("en_GB")

    private TrainSpotterLog log;

You can also log exceptions.

import org.jboss.solder.messages.Message;

import org.jboss.solder.messages.Cause;
import org.jboss.solder.logging.Log;
import org.jboss.solder.logging.MessageLogger;
@MessageLogger
public interface TrainSpotterLog {
    @Log @Message("Failed to spot train %s")
    void missedTrain(String trainNumber, @Cause Exception exception);
}

You can then log a message with an exception as follows:

try {

    ...
} catch (Exception e) {
    log.missedTrain("RH1", e);
}

The stacktrace of the exception parameter will be written to the log along with the message.

Typed loggers also provide internationalization support. Simply add the @MessageBundle annotation to the logger interface.

If injecting a typed logger seems too "enterprisy" to you, or you need to get a reference to it from outside of CDI, you can use a static accessor method on Logger:

TrainSpotterLog log = Logger.getMessageLogger(TrainSpotterLog.class, "trains");

log.dieselTrainsSpotted(7);

The injected version is a convenience for those who prefer the declarative style of programming. If you are looking for a simpler starting point, you can simply use the Logger directly.

You may have noticed that throughout this chapter, we've only defined interfaces. Yet, we are injecting and invoking them as though they are concrete classes. So where's the implementation?

Good news. The typed logger and message bundle implementations are generated automatically! You'll see this strategy used often in Seam 3. It's declarative programming at its finest (or to an extreme, depending on how you look at it). Either way, it saves you from a whole bunch of typing.

So how are they generated? Let's find out!

The first time you need logging in your application, you'll likely start with the more casual approach of using the Logger API directly. There's no harm in that, but it's certainly cleaner to use the typed loggers, and at the same time leverage the parallel benefits of the typed bundles. So we recommend that as your long term strategy.

Once you are ready to move to the the typed loggers and message bundles, you'll need to generate the concrete implementation classes as part of the build. These classes are generated by using an annotation processor that is provided by Solder and based on the JBoss Logging tools project. Don't worry, setting it up is a lot simpler than it sounds. You just need to do these two simple steps:

  • Set the Java compliance to 1.6 (or better)

  • Add the Solder tooling library to the build classpath

Warning

If you forget to add the annotation processor to your build, you'll get an error when you deploy the application that reports: "Invalid bundle interface (implementation not found)". This error occurs because the concrete implementation classes are missing.

Setting the Java compliance to 1.6 enables any annotation processors on the classpath to be activated during compilation.

If you're using Maven, here's how the configuration in your POM file looks:


<dependencies>
    <!-- Annotation processor for generating typed logger and message bundle classes -->
    <dependency>
        <groupId>org.jboss.solder</groupId>
        <artifactId>solder-tooling</artifactId>
        <scope>provided</scope>
        <optional>true</optional>
    </dependency>
    ...
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Note

In the future, you can expect IDE plugins like JBoss Tools to setup this configuration automatically.

Here are the classes that will be generated for the examples above:

TrainSpotterLog_$logger.java
TrainSpotterLog_$logger_en_GB.java
TrainMessages_$bundle.java

Classes are generated for each language referenced by an annotation or if there is a .i18n.properties language file in the same package as the interface and has the same root name. For instance, if we wanted to generate a French version of TrainMessages, we would have to create the following properties file in the same package as the interface:

TrainMessages.i18n_fr.properties

Then populate it with the translations (Note the property key is the method name):

noTrainsSpotted=pas de trains repéré en raison de %s

Now the annotation processor will generate the following class:

TrainMessages_$bundle_fr.java

Now you can add typed loggers and message bundles at will (and you won't have to worry about unsatisfied dependencies).

Solder provides a number of utility classes that make working with annotations and AnnotatedTypes easier. This chapter walks you through each utility, and gives you some ideas about how to use it. For more detail, take a look at the JavaDoc on each class.

Solder provides an AnnotatedType implementation that should be suitable for the needs of most portable extensions. The AnnotatedType is created from AnnotatedTypeBuilder, typically in an extension's observer method, as follows:

AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder()

        .readFromType(type, 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.

AnnotatedType redefinedType = builder.create();

One place this is immensely useful is for replacing the AnnotatedType in an extension that observes the ProcessAnnotatedType event:

public <X> void processAnnotatedType(@Observes ProcessAnnotatedType<X> evt) {

    AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder()
            .readFromType(evt.getAnnotatedType(), true)
            .addToClass(ModelLiteral.INSTANCE);
    evt.setAnnotatedType(builder.create());
}

This type is now effectively annotated with @Model, even if the annotation is not present on the class definition in the Java source file.

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 the type and any of its members, use this:

AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder()

        .readFromType(type, true)
        .redefine(Unique.class, new AnnotationRedefiner<Unique>() {
            public void redefine(RedefinitionContext<Unqiue> ctx) {
                ctx.getAnnotationBuilder().remove(Unique.class);
            } 
        });
AnnotatedType redefinedType = builder.create();

No doubt, this is a key blade in Solder's army knife arsenal of tools. You can quite effectively change the picture of the type metadata CDI discovers when it scans and processes the classpath of a bean archive.

The Annotation Inspector allows you to easily discover annotations which are meta-annotated. For example:

/* Discover all annotations on type which are meta-annotated @Constraint */

Set<Annotation> constraints = AnnotationInspector.getAnnotations(type, Constraint.class);
/* Load the annotation instance for @FacesValidator the annotation may declared on the type, */
/* or, if the type has any stereotypes, on the stereotypes */
FacesValidator validator = AnnotationInspector.getAnnotation(
        type, FacesValidator.class, true, beanManager);

The utility methods work correctly on Stereotypes as well. Let's say you're working with a bean that was decorated @Model, running the following example will still show you the underlying @Named

// assuming you have a class..

@Model
public class User {
    ...
}
// Assume type represents the User class
assert AnnotationInspector.isAnnotationPresent(type, Named.class, beanManager);
// Retrieves the underlying @Named instance on the stereotype
Named name = AnnotationInspector.getAnnotation(type, Named.class, true, beanManager);

The search algorithm will first check to see if the annotation is present directly on the annotated element first, then searches within the stereotype annotations on the element. If you only want to search for Annotations on Stereotypes, then you can use either of the methods AnnotationInspector.getAnnotationFromStereotype.

There is an overloaded form of isAnnotationPresent and getAnnotation to control whether it will search on Stereotypes or not. For both of these methods, a search is performed first directly on the element before searching in stereotypes.

When developing a framework that builds on CDI, you may need to obtain the BeanManager for the application, you 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 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().getBeans(IRequestListener.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 satisfied 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
   }
}

Solder provides a number of base classes which can be extended to create custom beans. 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.

The Property<V> interface declares a number of methods for interacting with bean properties. You can use these methods to read or set the property value, and read the property type information. Properties may be readonly.


Given a class with two properties, personName and postcode:'

class Person {

   
   PersonName personName;
   
   Address address;
   
   void setPostcode(String postcode) {
      address.setPostcode(postcode);
   }
   
   String getPostcode() {
      return address.getPostcode();
   }
   
}

You can create two properties:

   Property<PersonName> personNameProperty = Properties.createProperty(Person.class.getField("personName"));

   Property<String> postcodeProperty = Properties.createProperty(Person.class.getMethod("getPostcode"));

Once you have created the PropertyQuery instance, you can add search criteria. 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(new 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(new 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(new 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. An unwrapped injectable object is useful if you need a bean whose lifecycle does not exactly match one of the lifecycles of the existing scopes. The lifecycle of the bean is 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.

Important

Solder implements this by injecting a proxy rather than the original object. Every invocation on the injected proxy will cause the unwrapping producer method to be invoked to obtain the instance on which to invoke the method called. Solder will then invoke the method on unwrapped instance.

Because of this, it is very important the producer method is lightweight.

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 represents) 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 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(FunctionMapper.class)

@Mapper
class FunctionMapperImpl extends FunctionMapper {
   @Override
   public 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 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 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 Solder Config). 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 Solder Config:


<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 value();
   
}

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 queuing messages. The client can then tweak the policy should they wish.

@Generic

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();
   }
}

Solder provides a method for configuring CDI beans using alternate metadata sources, such as XML configuration. Currently, the XML provider is the only alternative available. Using a "type-safe" XML syntax, it is possible to add new beans, override existing beans, and add extra configuration to existing beans.

To take advantage of XML Configuration, you need 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 some CDI implementations will not allow this, so seam-beans.xml is provided as an alternative.

Here is a simple example. The following class 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
  }
}

The 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.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
(1)ml_plain">       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
(2)ml_plain">       xmlns:s="urn:java:ee" 
       xmlns:r="urn:java:org.example.reports">
(3)ml_plain">
(4)ml_plain">  <r:Report>
(5)ml_plain">   <s:modifies/>
   <r:filename>sales.jrxml<r:filename>
(6)ml_plain">   <r:datasource>
    <r:SalesQualifier/>
   </r:datasource>
  </r:Report>
(7)ml_plain">   
(8)ml_plain">  <r:Report filename="billing.jrxml">
   <s:replaces/>
(9)ml_plain">   <r:datasource>
(10)ml_plain">    <s:Inject/>
    <s:Exact>org.example.reports.BillingDatasource</s:Exact>
   </r:datasource>
   </r:Report>   
</beans>

1

The namespace urn:java:ee is the XML 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 the reporting classes live. Multiple java packages can be aggregated into a single namespace declaration by separating 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 the 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 as 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 available 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/>

Initial 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.solder.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 example, MethodBean has three methods. They are all 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 ofMethodValueBeans as a parameter. For both of 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>
      

If you are using Java EE 5 or some other Servlet 2.5 container, then you need to manually register several Servlet components in your application's web.xml to activate the features provided by this module:


<listener>
    <listener-class>org.jboss.solder.servlet.event.ServletEventBridgeListener</listener-class>
</listener>

<servlet>
    <servlet-name>Servlet Event Bridge Servlet</servlet-name>
    <servlet-class>org.jboss.solder.servlet.event.ServletEventBridgeServlet</servlet-class>
    <!-- Make load-on-startup large enough to be initialized last (thus destroyed first) -->
    <load-on-startup>99999</load-on-startup>
</servlet>

<servlet-mapping>
   <servlet-name>Servlet Event Bridge Servlet</servlet-name>
   <url-pattern>/*</url-pattern>
</servlet-mapping>

<filter>
   <filter-name>Exception Filter</filter-name>
   <filter-class>org.jboss.solder.servlet.exception.CatchExceptionFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Exception Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>Servlet Event Bridge Filter</filter-name>
    <filter-class>org.jboss.solder.servlet.event.ServletEventBridgeFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>Servlet Event Bridge Filter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

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

By including the Solder 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. Solder 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.solder.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 qualifiers:

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 alternative 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.solder.servlet.WebApplication rather than the ServletContext. WebApplication is a informational object provided by Solder 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 99999.

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.solder.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 qualifier:

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, Solder 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.solder.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 qualifier

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 Solder 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.solder.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!

Solder 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 Solder 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.

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

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, Solder 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

Solder also includes a provider that retrieves the BeanManager from this location. Anytime the Solder 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, among other available strategies. Refer to Chapter 10, Obtaining a reference to the BeanManager for information on how to leverage the servlet context attribute provider to access the BeanManager from outside the CDI environment.

Exceptions are a fact of life. As developers, we need to be prepared to deal with them in the most graceful manner possible. Solder's exception handling framework provides a simple, yet robust foundation for modules and/or applications to establish a customized exception handling process. By employing a delegation model, Solder allows exceptions to be addressed in a centralized, extensible and uniform manner.

In this guide, we'll explore the various options you have for handling exceptions using Solder, as well as how framework authors can offer Solder exception handling integration.

The entire exception handling process starts with an event. This helps keep your application minimally coupled to Solder, but also allows for further extension. Exception handling in Solder is all about letting you take care of exceptions the way that makes the most sense for your application. Events provide this delicate balance.

There are three means of firing the event to start the exception handling process:

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. Solder will discover all such methods at deployment time.

Let's look at an example. The following method is invoked for every exception that Solder processes and prints the exception message to stdout. (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.markHandled();
   }
}
            

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 type CaughtException<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 chain, as returned by getException().

4

This handler does not modify the invocation of subsequent handlers, as designated by invoking markHandled() 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 type CaughtException<T extends Throwable>. Handler methods are similar to CDI observers and, as such, follow the same principles 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 section Section 25.5.1, “Traversal of exception type hierarchy”.

3

This handler is qualified with @WebRequest. When Solder calculates the handler chain, it filters handlers based on the exception type and qualifiers. This handler will only be invoked for exceptions passed to Solder 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 Solder. 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 re-enables 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 propagate up the stack and all handling done via Solder 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 chain.

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

The first exception handlers to be invoked by Solder are those that match the type of root cause. Thus, instead of seeing a vague EJBException, your handlers will instead see an meaningful exception such as ConstraintViolationException. This feature, alone, makes Solder's exception handling a worthwhile tool.

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

Consider a exception chain containing the following nested causes (from outer cause to root cause):

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

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

While processing one of the causes in the exception chain, Solder 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.

Solder 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 hierarchy toward 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 Solder 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, Solder starts with handlers of the actual exception type and works up toward 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, Solder will notify that exception handler before the exception handler for the actual type is notified.

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

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

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).

When Solder finds more than one handler for the same exception type, it orders the handlers by precedence. Handlers with higher precedence are executed before handlers with a lower precedence. If Solder detects two handlers for the same type with the same precedence, it detects it as an error and throws an exception at deployment time.

Let's define two handlers with different precedence:



void handleIOExceptionFirst(@Handles(precedence = 100) CaughtException<IOException> evt)
{
   System.out.println("Invoked first");
}
void handleIOExceptionSecond(@Handles CaughtException<IOException> evt)
{
   System.out.println("Invoked second");
}
         

The first method is invoked first since it has a higher precedence (100) than the second method, which has the default precedence (0).

To make specifying precedence values more convenient, Solder provides several built-in constants, available on the Precedence class:

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

There are two APIs provided by Solder 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 such as EJBException, changing the exception type to something more meaningful such as cases like SQLException, or wrapping exceptions as custom application exception types.

This contains methods to help aid in determining what to do in the filter, it also allows you to completely replace the StackTraceElement if desired. The four "mark" methods deal with marking a stack trace and are used if "folding" a stack trace is desired, instead of dropping the frame. The StackFrame will allow for multiple marks to be set. The last method,getIndex(), will return the index of the StackTraceElement from the exception.





Integration of Solder's exception handling 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. The following example is a possible usage of ServiceHandlers within a JAX-RS application:

@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 Solder integration, however, there may be situations 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 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 withoptimistic 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 loosely-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.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 an 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.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>

Let's 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() andafterCompletion(), 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.

If your entity manager is installed with a different qualifier, then you need to use the following configuration (this assumes that my has been bound to the namespace that contains the appropriate qualifier, see the Seam Config XML documentation for more details):


<t:EntityTransaction>
   <s:modifies />
   <t:entityManager>
      <my:SomeQualifier/>
   </tentityManager>
</t:EntityTransaction>

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 an 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 API's 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.

Unlike in Seam 2, transactions will not roll back whenever a non-application exception propagates out of a bean, unless the bean has the transaction interceptor enabled.

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 TransactionalBean
                {
                /* 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.

@ExtensionManaged
                @Produces
                @PersistenceUnit
                @ConversationScoped
                EntityManagerFactory producerField;
            

This is just an ordinary resource producer field as defined by the CDI specification, however the presence of the @ExtensionManaged annotation tells seam to create a seam managed persistence context from thisEntityManagerFactory. 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;

Table of Contents

30. Security - Introduction
30.1. Overview
30.1.1. Authentication
30.1.2. Identity Management
30.1.3. External Authentication
30.1.4. Authorization
30.2. Configuration
30.2.1. Maven Dependencies
30.2.2. Enabling the Security Interceptor
31. Security - Authentication
31.1. Basic Concepts
31.2. Built-in Authenticators
31.3. Which Authenticator will Seam use?
31.4. Writing a custom Authenticator
32. Security - Identity Management
32.1. Overview
32.2. Configuring Seam to use Identity Management with JPA
32.2.1. Recommended database schema
32.2.2. The @IdentityEntity and @IdentityProperty annotations
32.2.3. Identity Object
32.2.4. Credential
32.2.5. Identity Object Relationship
32.2.6. Attributes
32.3. Managing Users, Groups and Roles
32.3.1. Managing Users and Groups
32.3.2. Managing Relationships
32.3.3. Managing Roles
33. Security - External Authentication
33.1. Introduction
33.1.1. Configuration
33.2. OpenID
33.2.1. Overview
33.2.2. Enabling OpenID for your application
33.2.3. Choosing which OpenID provider to use
33.2.4. Managing the OpenID authentication process
34. Security - Authorization
34.1. Configuration
34.2. Basic Concepts
34.2.1. IdentityType
34.2.2. User
34.2.3. Group
34.2.4. Role
34.2.5. RoleType
34.3. Role and Group-based authorization
34.4. Typesafe authorization
34.4.1. Creating a typesafe security binding
34.4.2. Creating an authorizer method
34.4.3. Applying the binding to your business methods
34.4.4. Built-in security binding annotations
35. Security - Events
35.1. Introduction
35.2. Event list
35.3. Usage Example

The Seam Security module provides a number of useful features for securing your Java EE application, which are briefly summarised in the following sections. The rest of the chapters contained in this documentation each focus on one major aspect of each of the following features.

The Maven artifacts for all Seam modules are hosted within the JBoss Maven repository. Please refer to the Maven Getting Started Guide for information about configuring your Maven installation to use the JBoss repository.

To use Seam Security within your Maven-based project, it is advised that you import the Seam BOM (Bill of Materials) which declares the versions for all Seam modules. First declare a property value for ${seam.version} as follows:


<properties>
  <seam.version>3.1.0.Final</seam.version>
</properties>

You can check the JBoss Maven Repository directly to determine the latest version of the Seam BOM to use.

Now add the following lines to the list of dependencies within the dependencyManagement section of your project's pom.xml file:


<dependency>
  <groupId>org.jboss.seam</groupId>
  <artifactId>seam-bom</artifactId>
  <version>${seam.version}</version>
  <type>pom</type>
  <scope>import</scope>
</dependency>

Once that is done, add the following dependency (no version is required as it comes from seam-bom):


<dependency>
  <groupId>org.jboss.seam.security</groupId>
  <artifactId>seam-security</artifactId>
</dependency>

If you wish to use the external authentication module in your application to allow authentication using OpenID or SAML, then add the following dependency also:


<dependency>
  <groupId>org.jboss.seam.security</groupId>
  <artifactId>seam-security-external</artifactId>
</dependency>

The majority of the Security API is centered around the Identity bean. This bean represents the identity of the current user, the default implementation of which is a session-scoped, named bean. This means that once logged in, a user's identity is scoped to the lifecycle of their current session. The two most important methods that you need to know about at this stage in regard to authentication are login() and logout(), which as the names suggest are used to log the user in and out, respectively.

As the default implementation of the Identity bean is named, it may be referenced via an EL expression, or be used as the target of an EL action. Take the following JSF code snippet for example:

  <h:commandButton action="#{identity.login}" value="Log in"/>    

This JSF command button would typically be used in a login form (which would also contain inputs for the user's username and password) that allows the user to log into the application.

The other important bean to know about right now is the Credentials bean. Its' purpose is to hold the user's credentials (such as their username and password) before the user logs in. The default implementation of the Credentials bean is also a session-scoped, named bean (just like the Identity bean).

The Credentials bean has two properties, username and credential that are used to hold the current user's username and credential (e.g. a password) values. The default implementation of the Credentials bean provides an additional convenience property called password, which may be used in lieu of the credential property when a simple password is required.

The Identity bean has an authenticatorClass property, which if set will be used to determine which Authenticator bean implementation to invoke during the authentication process. This property may be set by configuring it with a predefined authenticator type, for example by using Solder XML Config. The following XML configuration example shows how you would configure the Identity bean to use the com.acme.MyCustomerAuthenticator bean for authentication:


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:ee" 
   xmlns:security="urn:java:org.jboss.seam.security"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
       
   <security:IdentityImpl>
      <s:modifies/>      
      <security:authenticatorClass>com.acme.MyCustomAuthenticator</security:authenticatorClass>
   </security:IdentityImpl>      
</beans>

Alternatively, if you wish to be able to select the Authenticator to authenticate with by specifying the name of the Authenticator implementation (i.e. for those annotated with the @Named annotation), the authenticatorName property may be set instead. This might be useful if you wish to offer your users the choice of how they would like to authenticate, whether it be through a local user database, an external OpenID provider, or some other method.

The following example shows how you might configure the authenticatorName property with the Seam Config module:


<beans xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:s="urn:java:ee" 
   xmlns:security="urn:java:org.jboss.seam.security"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
   <security:IdentityImpl>
      <s:modifies/>
      <security:authenticatorName>openIdAuthenticator</security:authenticatorName>
   </security:IdentityImpl>      
</beans>

If neither the authenticatorClass or authenticatorName properties are set, then the authentication process with automatically use a custom Authenticator implementation, if the developer has provided one (and only one) within their application.

If neither property is set, and the user has not provided a custom Authenticator, then the authentication process will fall back to the Identity Management API to attempt to authenticate the user.

All Authenticator implementations must implement the org.jboss.seam.security.Authenticator interface. This interface defines the following methods:

public interface Authenticator {

  void authenticate();   
  void postAuthenticate();   
  User getUser();   
  AuthenticationStatus getStatus();
}

The authenticate() method is invoked during the authentication process and is responsible for performing the work necessary to validate whether the current user is who they claim to be.

The postAuthenticate() method is invoked after the authentication process has already completed, and may be used to perform any post-authentication business logic, such as setting session variables, logging, auditing, etc.

The getUser() method should return an instance of org.picketlink.idm.api.User, which is generally determined during the authentication process.

The getStatus() method must return the current status of authentication, represented by the AuthenticationStatus enum. Possible values are SUCCESS, FAILURE and DEFERRED. The DEFERRED value should be used for special circumstances, such as asynchronous authentication as a result of authenticating against a third party as is the case with OpenID, etc.

The easiest way to get started writing your own custom authenticator is to extend the org.jboss.seam.security.BaseAuthenticator abstract class. This class implements the getUser() and getStatus() methods for you, and provides setUser() and setStatus() methods for setting both the user and status values.

To access the user's credentials from within the authenticate() method, you can inject the Credentials bean like so:

@Inject Credentials credentials;

Once the credentials are injected, the authenticate() method is responsible for checking that the provided credentials are valid. Here is a complete example:

public class SimpleAuthenticator extends BaseAuthenticator implements Authenticator {

   @Inject Credentials credentials;
   
   @Override
   public void authenticate() {
      if ("demo".equals(credentials.getUsername()) && 
            credentials.getCredential() instanceof PasswordCredential &&
            "demo".equals(((PasswordCredential) credentials.getCredential()).getValue()))  {
         setStatus(AuthenticationStatus.SUCCESS);
         setUser(new SimpleUser("demo"));
      }
   }
}

In the above code, the authenticate() method checks that the user has provided a username of demo and a password of demo. If so, the authentication is deemed as successful and the status is set to AuthenticationStatus.SUCCESS, and a new SimpleUser instance is created to represent the authenticated user.

Identity Management is a feature that allows you to manage the users, groups and roles in your application. The Identity Management features in Seam Security are provided by PicketLink IDM. The best place to find more information about PicketLink IDM is the reference documentation, available here.

PicketLink provides two identity store implementations to allow you to use Hibernate or LDAP to store identity-related data (please refer to the PicketLink IDM documentation for details on configuring these). Seam Security provides an additional implementation called JpaIdentityStore, which allows you to store your identity data using JPA.

In a Seam-based application it probably makes more sense to use the standards-based JpaIdentityStore rather than HibernateIdentityStore, as you will most likely be running in an Java EE container that supports JPA. JpaIdentityStore is an implementation of the PicketLink IdentityStore interface, provided by Seam Security. This identity store allows you to store your identity model inside a relational database, accessible via JPA. It provides an immense amount of flexibility in the way you define your identity model, and in most cases should be compatible with existing database schemas.

Note

See the idmconsole example application (included in the Seam distribution) for a demonstration of Seam's Identity Management features.

Like all authentication providers in Seam, Identity Management is supported via a concrete Authenticator implementation called IdmAuthenticator. To use Identity Management in your own application, you don't need to do anything! Simply don't configure any authenticator, and as long as you have an identity store configured (see the next section), the Identity Management API will be used to authenticate automatically.

package org.jboss.seam.security.annotations.management;


public @interface IdentityProperty {
   PropertyType value();
   String attributeName() default "";
}

The value() member is of type PropertyType, which is an enum that defines the following values:

public enum PropertyType {

  NAME, TYPE, VALUE, RELATIONSHIP_FROM, RELATIONSHIP_TO, CREDENTIAL, 
  CREDENTIAL_TYPE, ATTRIBUTE }

By placing the IdentityProperty annotation on various fields of your entity beans, JpaIdentityStore can determine how identity-related data must be stored within your database tables.

In the following sections we'll look at how each of the main entities are configured.

Let's start by looking at identity object. In the recommended database schema, the IDENTITY_OBJECT table is responsible for storing objects such as users and groups. This table may be represented by the following entity bean:

@Entity

@IdentityEntity(IDENTITY_OBJECT)
public class IdentityObject implements Serializable {  
    @Id @GeneratedValue private Long id;
     
    @IdentityProperty(PropertyType.NAME)
    private String name;
     
    @ManyToOne @IdentityProperty(PropertyType.TYPE)
    @JoinColumn(name = "IDENTITY_OBJECT_TYPE_ID")
    private IdentityObjectType type;
    // snip getter and setter methods
}

In the above code both the name and type fields are annotated with @IdentityProperty. This tells JpaIdentityStore that these two fields are significant in terms of identity management-related state. By annotating the name field with @IdentityProperty(PropertyType.NAME), JpaIdentityStore knows that this field is used to store the name of the identity object. Likewise, the @IdentityProperty(PropertyType.TYPE) annotation on the type field indicates that the value of this field is used to represent the type of identity object.

The IdentityObjectType entity is simply a lookup table containing the names of the valid identity types. The field representing the actual name of the type itself should be annotated with @IdentityProperty(PropertyType.NAME):

@Entity

public class IdentityObjectType implements Serializable {   
   @Id @GeneratedValue private Long id;
   @IdentityProperty(PropertyType.NAME) private String name;        
   
   // snip getter and setter methods
}

The relationship table stores associations between identity objects. Here's an example of an entity bean that has been configured to store identity object relationships:

@Entity

@IdentityEntity(IDENTITY_RELATIONSHIP)
public class IdentityObjectRelationship implements Serializable
{   
   @Id @GeneratedValue private Long id;
   
   @IdentityProperty(PropertyType.NAME)
   private String name;
   
   @ManyToOne @IdentityProperty(PropertyType.TYPE) @JoinColumn(name = "RELATIONSHIP_TYPE_ID")
   private IdentityObjectRelationshipType relationshipType;
   
   @ManyToOne @IdentityProperty(PropertyType.RELATIONSHIP_FROM) @JoinColumn(name = "FROM_IDENTITY_ID")
   private IdentityObject from;
   
   @ManyToOne @IdentityProperty(PropertyType.RELATIONSHIP_TO) @JoinColumn(name = "TO_IDENTITY_ID")
   private IdentityObject to;        
   
   // snip getter and setter methods
}

The name property is annotated with @IdentityProperty(PropertyType.NAME) to indicate that this field contains the name value for named relationships. An example of a named relationship is a role, which uses the name property to store the role type name.

The relationshipType property is annotated with @IdentityProperty(PropertyType.TYPE) to indicate that this field represents the type of relationship. This is typically a value in a lookup table.

The from property is annotated with @IdentityProperty(PropertyType.RELATIONSHIP_FROM) to indicate that this field represents the IdentityObject on the from side of the relationship.

The to property is annotated with @IdentityProperty(PropertyType.RELATIONSHIP_TO) to indicate that this field represents the IdentityObject on the to side of the relationship.

The IdentityObjectRelationshipType entity is a lookup table containing the valid relationship types. The @IdentityProperty(PropertyType.NAME) annotation is used to indicate the field containing the relationship type names:

@Entity

public class IdentityObjectRelationshipType implements Serializable {   
   @Id @GeneratedValue private Long id;
   
   @IdentityProperty(PropertyType.NAME)
   private String name;
   
   // snip getter and setter methods
}

The Identity Management features are provided by a number of manager objects, which can be access from an IdentitySession. The IdentitySession may be injected directly into your beans like so:

import org.picketlink.idm.api.IdentitySession;


  public @Model class IdentityAction {
    @Inject IdentitySession identitySession;
    
    // code goes here...
  }

Once you have the IdentitySession object, you can use it to perform various identity management operations. You should refer to the PicketLink documentation for a complete description of the available features, however the following sections contain a brief overview.

OpenID allows the users of your application to authenticate without requiring them to create an account. When using OpenID, your user is temporarily redirected to the web site of their OpenID provider so that they can enter their password, after which they are redirected back to your application. The OpenID authentication process is safe - at no time is the user's password seen by any site besides their OpenID provider.

The external authentication module provides support for OpenID based on OpenID4Java, an open source OpenID library (licensed under the Apache v2 license) with both Relying Party and Identity Provider capabilities. This feature allows your application to authenticate its users against an external OpenID provider, such as Google or Yahoo, or to turn your application into an OpenID provider itself.

Note

To see the OpenID features in action, take a look at the openid-rp example included in the Seam Security distribution.

To use OpenID in your own application, you must configure Seam Security to use OpenIdAuthenticator, an Authenticator implementation that performs authentication against an OpenID provider. This authenticator is a named, session-scoped bean, with the following declaration:

public @Named("openIdAuthenticator") @SessionScoped class OpenIdAuthenticator

Seam provides built-in support for a number of well-known OpenID providers. The OpenIdAuthenticator bean may be configured to select which OpenID provider will be used to process an authentication request. Each concrete provider implements the following interface:

public interface OpenIdProvider {

   String getCode();
   String getName();
   String getUrl();
}

The following table lists the providers that come pre-packaged in Seam:

ProviderCodeNameURL
CustomOpenIdProvidercustomGoogle 
GoogleOpenIdProvidergoogleGooglehttps://www.google.com/accounts/o8/id
MyOpenIdProvidermyopenidMyOpenIDhttps://myopenid.com
YahooOpenIdProvideryahooYahoohttps://me.yahoo.com

To select one of the built-in providers to use for an authentication request, the providerCode property of the OpenIdAuthenticator bean should be set to one of the Code values from the above table. The OpenIdAuthenticator bean provides a convenience method called getProviders() that returns a list of all known providers. This may be used in conjunction with a radio group to allow the user to select which OpenID provider they wish to authenticate with - see the following JSF snippet for an example:


<h:selectOneRadio value="#{openIdAuthenticator.providerCode}">
  <f:selectItems value="#{openIdAuthenticator.providers}" var="p" itemValue="#{p.code}" itemLabel="#{p.name}"/>
</h:selectOneRadio>

Your application must provide an implementation of the OpenIdRelyingPartySpi interface to process OpenID callback events. This interface declares the following methods:

public interface OpenIdRelyingPartySpi {

   void loginSucceeded(OpenIdPrincipal principal, ResponseHolder responseHolder);
   void loginFailed(String message, ResponseHolder responseHolder);      
      

The implementation is responsible for processing the response of the OpenID authentication, and is typically used to redirect the user to an appropriate page depending on whether authentication was successful or not.

There are two API calls that must be made in the case of a successful authentication. The first one should notify the OpenIdAuthenticator that the authentication attempt was successful, and pass it the OpenIdPrincipal object:

openIdAuthenticator.success(principal);

Secondly, a DeferredAuthenticationEvent must be fired to signify that a deferred authentication attempt has been completed:

deferredAuthentication.fire(new DeferredAuthenticationEvent());

After making these two API calls, the implementation may perform whatever additional logic is required. The following code shows a complete example:

import java.io.IOException;


import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import org.jboss.seam.security.events.DeferredAuthenticationEvent;
import org.jboss.seam.security.external.api.ResponseHolder;
import org.jboss.seam.security.external.openid.OpenIdAuthenticator;
import org.jboss.seam.security.external.openid.api.OpenIdPrincipal;
import org.jboss.seam.security.external.spi.OpenIdRelyingPartySpi;
public class OpenIdRelyingPartySpiImpl implements OpenIdRelyingPartySpi {
   @Inject private ServletContext servletContext;
   @Inject OpenIdAuthenticator openIdAuthenticator;   
   @Inject Event<DeferredAuthenticationEvent> deferredAuthentication;
   public void loginSucceeded(OpenIdPrincipal principal, ResponseHolder responseHolder) {
      try {
         openIdAuthenticator.success(principal);
         deferredAuthentication.fire(new DeferredAuthenticationEvent());
         
         responseHolder.getResponse().sendRedirect(servletContext.getContextPath() + "/UserInfo.jsf");
      } catch (IOException e) {
         throw new RuntimeException(e);
      }
   }
   public void loginFailed(String message, ResponseHolder responseHolder) {
      try {
         responseHolder.getResponse().sendRedirect(servletContext.getContextPath() + "/AuthenticationFailed.jsf");
      } catch (IOException e) {
         throw new RuntimeException(e);
      }
   }
}

Seam Security provides a number of facilities for restricting access to certain parts of your application. As mentioned previously, the security API is centered around the Identity bean, which is a session-scoped bean used to represent the identity of the current user.

To be able to restrict the sensitive parts of your code, you may inject the Identity bean into your class:

@Inject Identity identity;

Once you have injected the Identity bean, you may invoke its methods to perform various types of authorization. The following sections will examine each of these in more detail.

The security model in Seam Security is based upon the PicketLink API. Let's briefly examine a few of the core interfaces provided by PicketLink that are used in Seam.

This is the simplest type of authorization, used to define coarse-grained privileges for users assigned to a certain role or belonging to a certain group. Users may belong to zero or more roles and groups, and inversely, roles and groups may contain zero or more members.

The Identity bean provides the following two methods for checking role membership:

boolean hasRole(String role, String group, String groupType);
void checkRole(String role, String group, String groupType);

These two methods are similar in function, and both accept the same parameter values. Their behaviour differs when an authorization check fails. The hasRole() returns a value of false when the current user is not a member of the specified role. The checkRole() method on the other hand, will throw an AuthorizationException. Which of the two methods you use will depend on your requirements.

The following code listing contains a usage example for the hasRole() method:

   if (identity.hasRole("manager", "Head Office", "OFFICE")) {
      report.addManagementSummary();
   }

Groups can be used to define a collection of users that meet some common criteria. For example, an application might use groups to define users in different geographical locations, their role in the company, their department or division or some other criteria which may be significant from a security point of view. As can be seen in the above class diagram, groups consist of a unique combination of group name and group type. Some examples of group types may be "OFFICE", "DEPARTMENT", "SECURITY_LEVEL", etc. An individual user may belong to many different groups.

The Identity bean provides the following methods for checking group membership:

boolean inGroup(String name, String groupType);
void checkGroup(String group, String groupType);

These methods are similar in behaviour to the role-specific methods above. The inGroup() method returns a value of false when the current user isn't in the specified group, and the checkGroup() method will throw an exception.

Seam Security provides a way to secure your bean classes and methods by annotating them with a typesafe security binding. Each security binding must have a matching authorizer method, which is responsible for performing the business logic required to determine whether a user has the necessary privileges to invoke a bean method. Creating and applying a security binding is quite simple, and is described in the following steps.

The following table contains the list of event classes that may be fired by Seam Security, along with a description of when the event is fired. All event classes are contained in the org.jboss.seam.security.events package.

EventDescription
AlreadyLoggedInEventFired when a user who is already logged in attempts to log in again
AuthorizationCheckEventFired when an authorization check is performed, such as Identity.hasPermission().
CredentialsUpdatedEventFired whenever a user's credentials (such as their username or password) are updated.
DeferredAuthenticationEventFired when a deferred authentication occurs. For example, at the end of the OpenID authentication process when the OpenID provider redirects the user back to the application.
LoggedInEventFired when the user is successfully logged in.
LoginFailedEventFired when an authentication attempt by the user fails.
NotAuthorizedEventFired when the user is not authorized to invoke a particular operation.
NotLoggedInEventFired when the user attempts to invoke a privileged operation before they have authenticated.
PreAuthenticateEventFired just before a user is authenticated
PostAuthenticateEventFired after a user has authenticated successfully.
PreLoggedOutEventFired just before a user is logged out.
PostLoggedOutEventFired after a user has logged out.
PrePersistUserEventFired just before a new user is persisted (when using Identity Management).
PrePersistUserRoleEventFired just before a new user role is persisted (when using Identity Management).
QuietLoginEventFired when a user is quietly authenticated.
SessionInvalidatedEventFired when a user's session is invalidated.
UserAuthenticatedEventFired when a user is authenticated.
UserCreatedEvent 

The following code listing shows the SecurityEventMessages class, from the Seam Security implementation library. This class (which is disabled by default due to the @Veto annotation) uses the Messages API from Seam International to generate user-facing messages in response to certain security events.

package org.jboss.seam.security;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.security.events.AlreadyLoggedInEvent;
import org.jboss.seam.security.events.LoggedInEvent;
import org.jboss.seam.security.events.LoginFailedEvent;
import org.jboss.seam.security.events.NotLoggedInEvent;
import org.jboss.seam.security.events.PostAuthenticateEvent;
import org.jboss.solder.core.Requires;
import org.jboss.solder.core.Veto;

public @ApplicationScoped @Veto @Requires("org.jboss.seam.international.status.Messages")
class SecurityEventMessages {
    private static final String DEFAULT_LOGIN_FAILED_MESSAGE = "Login failed - please check your username and password before trying again.";
    private static final String DEFAULT_LOGIN_SUCCESSFUL_MESSAGE = "Welcome, {0}.";
    private static final String DEFAULT_ALREADY_LOGGED_IN_MESSAGE = "You're already logged in. Please log out first if you wish to log in again.";
    private static final String DEFAULT_NOT_LOGGED_IN_MESSAGE = "Please log in first.";

    public void postAuthenticate(@Observes PostAuthenticateEvent event, Messages messages, Identity identity) {
        messages.info(DEFAULT_LOGIN_SUCCESSFUL_MESSAGE, identity.getUser().getId());
    }

    public void addLoginFailedMessage(@Observes LoginFailedEvent event, Messages messages) {
        messages.error(DEFAULT_LOGIN_FAILED_MESSAGE);
    }

    public void addLoginSuccessMessage(@Observes LoggedInEvent event, Messages messages, Credentials credentials) {
        messages.info(DEFAULT_LOGIN_SUCCESSFUL_MESSAGE, credentials.getUsername());
    }

    public void addAlreadyLoggedInMessage(@Observes AlreadyLoggedInEvent event, Messages messages) {
        messages.error(DEFAULT_ALREADY_LOGGED_IN_MESSAGE);
    }

    public void addNotLoggedInMessage(@Observes NotLoggedInEvent event, Messages messages) {
        messages.error(DEFAULT_NOT_LOGGED_IN_MESSAGE);
    }
}

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.international</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.

To support a more developer friendly way of handling TimeZones, in addition to supporting JDK TimeZone, we have added support for using Joda-Time through their DateTimeZone class. Don't worry, it provides convenience methods for converting to JDK TimeZone.

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 inadvertently 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!

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 @org.jboss.seam.faces.context.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.

An alternate way of accessing those fields on the validator by injecting an InputElement. It works similarly to @InputField, but stores the clientId and a JSF UIComponent, along with the field value.

@FacesValidator("fooValidator")

public class FooValidator implements Validator {
    @Inject
    private InputElement<String> firstNameElement;
    @Inject
    private InputElement<String> lastNameElement;
    
    @Inject
    private InputElement<Date> startDateElement;
    @Inject
    private InputElement<Date> endDateElement;
    ...
    
    }

Use get methods to access those information

public void validate(final FacesContext ctx, final UIComponent form, final Object value) throws ValidatorException {

        Date startDate = startDateElement.getValue();
        
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        
        if (startDate.before(calendar.getTime())) {
            String message = messageBuilder.get().key(new DefaultBundleKey("booking_checkInNotFutureDate"))
                    .targets(  startDateElement.getClientId()  ).build().getText();
            throw new ValidatorException(new FacesMessage(message));
        } 
        ...
    }

The view action component (UIViewAction) is an ActionSource2 UIComponent that specifies an application-specific command (or action), 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 blog 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.

There's a composite componente that ships with seam-faces under the url:

http://java.sun.com/jsf/composite/components/seamfaces.


xmlns:sc="http://java.sun.com/jsf/composite/components/seamfaces"
    <sc:inputContainer label="name" id="name">
        <h:inputText id="input" value="#{person.name}"/>
    </sc:inputContainer>

If you want to define your own composite component, follow this 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>
   <h:panelGroup>
     <cc:insertChildren/>
   </h:panelGroup>
   <h:message id="message" errorClass="invalid message" rendered="#{cc.attrs.invalid}"/>
 </cc:implementation>

Most features of Seam Reports are installed automatically by including the seam-reports-api.jar and the respective provider implementation (along with its dependencies) 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.reports</groupId>
    <artifactId>seam-reports-api</artifactId>
    <version>${seam-reports-version}</version>
</dependency>

<!-- If you are using Jasper Reports, add the following dependency --> 
<dependency>
    <groupId>org.jboss.seam.reports</groupId>
    <artifactId>seam-reports-jasper</artifactId>
    <version>${seam-reports-version}</version>
</dependency>

<!-- If you are using Pentaho, add the following dependency --> 
<dependency>
    <groupId>org.jboss.seam.reports</groupId>
    <artifactId>seam-reports-pentaho</artifactId>
    <version>${seam-reports-version}</version>
</dependency>

Tip

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

Using Seam Reports is a simple four step process. These steps are the same regardless of the reporting engine being used.

Of course some of these steps will have different ways of accomplishing the task, but at a high level they are all the same. For simplicity this quick start will use JasperReports and the first step will be assumed to have already taken place and the report is available in the deployed archive. The location of the report isn't important, the ability to pull it into an InputStream is all that really matters.

The following code demonstrates a basic way of fulfilling the last three steps in using Seam Reports using JasperReports as the reporting engine. The report has already been created and is bundled inside the deployable archive. There are no paramaters for the report. The report is a simple listing of people's names and contact information.

@Model

public class PersonContactReport {
(1)  @Inject @Resource("WEB-INF/jasperreports/personContact.jrxml")
  private InputStream reportTemplate;
(2)  @Inject @Jasper
  private ReportCompiler reportCompiler;
(3)  @Inject @Jasper @PDF
  private ReportRenderer pdfRenderer;
  @Inject
  private EntityManager em; (4)
  public OutputStream render() {
    final Report filledReport = this.fillReport();
    final OutputStream os = new ByteArrayOutputStream();
    this.pdfRenderer.render(filledReport, os);
    return os;
  } (5)
  private Report fillReport() {
    final ReportDefinition rd = this.reportCompiler.compile(reportTemplate);
    return rd.fill(this.createDatasource(), Collections.EMPTY_MAP);
  } (6)
  private JRDataSource createDatasource() {
    final List<Person> personList = this.em.createQuery("select p from Person", Person.class).getResultList();
    return new JRBeanCollectionDataSource(personList);
  }
}

1

Solder allows easy resource injection for files available in the archive. This injects the report template which has been created previously (perhaps by someone else in the business) and added to the deployable archive.

2

A ReportCompiler is an interface from Seam Reports which abstracts compiling the report template into ReportDefinition. Seam Reports makes use of CDI's type safety features by using qualifiers to further narrow the intended type. This allows programs to remain implementation agnostic. The Jasper qualifier annotation instructs CDI to inject an implementation of the ReportCompiler which contains the same qualifer.

3

This is an instance of using both a qualifer (@Jasper) and also a metadata annotation, which happens to be a stereotype. The @PDF annotation is a CDI stereotype, which essentially means it's a group of other annotations. It carries metadata about the type it is decorating. More about this later.

4

The render method is the only entry point into the class, it also returns the final output of generating a report. It makes use of other methods in the class to finish the steps outlined above to generate a report using Seam Reports.

5

At this stage data to populate the report is retrieved and added to the compiled ReportDefinition. This particular report doesn't make use of any parameters, hence the empty map instance being passed.

6

This last stage of using Seam Reports is the only place that may require the application to use the report engine API. In this example a list of JPA entities is retrieved and added to a JasperReports datasource, which is then used by the calling method to populate the report template as mentioned above.

By default the configuration parameters for Seam Mail are handled via configuration read from your application's seam-beans.xml. This file is then parsed by Seam Solder to configure the MailConfig class. You can override this and provide your own configuration outside of Seam Mail but we will get into that later.

First lets add the relevant maven configuration to your pom.xml



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

Now now that is out of the way lets provide JavaMail with the details of your SMTP server so that it can connect and send your mail on it's way.

This configuration is handled via Seam Solder which reads in the configuration from your application's seam-beans.xml and configures the MailConfig class prior to injection.



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

    <mail:MailConfig
            serverHost="my-server.test.com"
            serverPort="25">
        <s:modifies/>
    </mail:MailConfig>
    
</beans>

That is all the configuration necessary to send a simple email message. Next we will take a look at how to configure and use the supported templating engines.

Important

JBoss AS 7.0.x does not correctly load all the modules to support sending mail AS7-1375. This is easily fixed By replacing the module definition at $JBOSS_HOME/modules/javax/activation/api/main/module.xml with the following



<module xmlns="urn:jboss:module:1.0" name="javax.activation.api">
    <dependencies>
        <module name="javax.api" />
        <module name="javax.mail.api" >
            <imports><include path="META-INF"/></imports>
        </module>   
    </dependencies>        
        
     <resources>
        <resource-root path="activation-1.1.1.jar"/>
            
        <!-- Insert resources here -->
    </resources>
</module>

This will be fixed in AS 7.1.x

At it's base an email consists of various destinations and content. Seam Mail provides a wide varerity of methods of ways to configure the following address fields

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.

The Seam International module provides a Messages API that allows generation of view-independent messages. This is useful if you want to convey additional information to a user that is not returned directly from the result of a method invocation.

Using the Messages API is extremely easy. Simply add the Seam International libraries to your application (see the Seam International configuration chapter to learn how to do this), then inject the Messages object into your bean. The Messages object provides several methods for adding messages, see the Seam International documentation for more information. Here's a simple example showing how to create an info message (messages generally follow the same DEBUG, INFO, WARN, ERROR levels that a typical logging framework would provide):

import javax.inject.Inject;

import org.jboss.seam.international.status.Messages;
import org.jboss.seam.remoting.annotations.WebRemote;
public class HelloAction {    
    @Inject Messages messages;
    
    @WebRemote
    public String sayHello(String name) {
        messages.info("Invoked HelloAction.sayHello()");        
        return "Hello, " + name;
    }
}

After creating the message in your server-side code, you still need to write some client-side code to handle any messages that are returned by your remote invocations. Thankfully this is also simple, you just need to write a JavaScript handler function and assign it to Seam.messageHandler.

If any messages are returned from a remote method invocation, the message handler function will be invoked and passed a list of Message objects. These objects declare three methods for retrieving various properties of the message - getLevel() returns the message level (such as DEBUG, INFO, etc). The getTargets() method returns the targets of the message - these may be the ID's for specific user interface controls, which is helpful for conveying validation failures for certain field values. The getTargets() method may return null, if the message is not specific to any field value. Lastly, the getText() method returns the actual text of the message.

Here's a really simple example showing how you would display an alert box for any messages returned:

    function handleMessages(msgs) {      
      for (var i = 0; i < msgs.length; i++) {
        alert("Received message - Level: " + msgs[i].getLevel() + " Text: " + msgs[i].getText();
      }
    }
    
    Seam.messageHandler = handleMessages;

You can see the Messages API in action in the HelloWorld example. Simply choose the "Formal" option for the Formality, and "Localized (English)" for the Localization. Invoking this combination will cause a server-side message to be created, which you will then see in the Messages list at the top of the screen.

When invoking a remote bean method, it is possible to specify an exception handler which will process the response in the event of an exception during bean invocation. To specify an exception handler function, include a reference to it after the callback parameter in your JavaScript:

var callback = function(result) { alert(result); };
var exceptionHandler = function(ex) { alert("An exception occurred: " + ex.getMessage()); };
Seam.createBean("helloAction").sayHello(name, callback, exceptionHandler);

If you do not have a callback handler defined, you must specify null in its place:

var exceptionHandler = function(ex) { alert("An exception occurred: " + ex.getMessage()); };
Seam.createBean("helloAction").sayHello(name, null, exceptionHandler);

The exception object that is passed to the exception handler exposes two methods, getExceptionClass() which returns the name of the exception class that was thrown, and getMessage(), which returns the exception message which is produced by the exception thrown by the @WebRemote method.

It is also possible to register a global exception handler, which will be invoked if there is no exception handler defined for an individual invocation. By default, the global exception handler will display an alert message notifying the user that there was an exception - here's what the default exception handler looks like:

Seam.defaultExceptionHandler = function(exception) {
  alert("An exception has occurred while executing a remote request: " + exception.getExceptionClass() + ":" + exception.getMessage());
};

If you would like to provide your own global exception handler, then simply override the value of Seam.exceptionHandler with your own custom exception handler, as in the following example:

  function customExceptionHandler(exception) {
    alert("Uh oh, something bad has happened! [" + exception.getExceptionClass() + ":" + exception.getMessage() + "]");
  }    
  
  Seam.exceptionHandler = customExceptionHandler;
    

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
}