SeamFramework.orgCommunity Documentation

Web Beans: Java Contexts and Dependency Injection

The new standard for dependency injection and contextual state management


Note
I. Using contextual objects
1. Getting started with Web Beans
1.1. Your first Web Bean
1.2. What is a Web Bean?
1.2.1. API types, binding types and dependency injection
1.2.2. Deployment types
1.2.3. Scope
1.2.4. Web Bean names and Unified EL
1.2.5. Interceptor binding types
1.3. What kinds of objects can be Web Beans?
1.3.1. Simple Web Beans
1.3.2. Enterprise Web Beans
1.3.3. Producer methods
1.3.4. JMS endpoints
2. JSF web application example
3. Getting started with Web Beans, the Reference Implementation of JSR-299
3.1. Using JBoss AS 5
3.2. Using Apache Tomcat 6.0
3.3. Using GlassFish
3.4. The numberguess example
3.4.1. The numberguess example in Tomcat
3.4.2. The numberguess example for Apache Wicket
3.4.3. The numberguess example for Java SE with Swing
3.5. The translator example
4. Dependency injection
4.1. Binding annotations
4.1.1. Binding annotations with members
4.1.2. Combinations of binding annnotations
4.1.3. Binding annotations and producer methods
4.1.4. The default binding type
4.2. Deployment types
4.2.1. Enabling deployment types
4.2.2. Deployment type precedence
4.2.3. Example deployment types
4.3. Fixing unsatisfied dependencies
4.4. Client proxies
4.5. Obtaining a Web Bean by programatic lookup
4.6. Lifecycle callbacks, @Resource, @EJB and @PersistenceContext
4.7. The InjectionPoint object
5. Scopes and contexts
5.1. Scope types
5.2. Built-in scopes
5.3. The conversation scope
5.3.1. Conversation demarcation
5.3.2. Conversation propagation
5.3.3. Conversation timeout
5.4. The dependent pseudo-scope
5.4.1. The @New annotation
6. Producer methods
6.1. Scope of a producer method
6.2. Injection into producer methods
6.3. Use of @New with producer methods
II. Developing loosely-coupled code
7. Interceptors
7.1. Interceptor bindings
7.2. Implementing interceptors
7.3. Enabling interceptors
7.4. Interceptor bindings with members
7.5. Multiple interceptor binding annotations
7.6. Interceptor binding type inheritance
7.7. Use of @Interceptors
8. Decorators
8.1. Delegate attributes
8.2. Enabling decorators
9. Events
9.1. Event observers
9.2. Event producers
9.3. Registering observers dynamically
9.4. Event bindings with members
9.5. Multiple event bindings
9.6. Transactional observers
III. Making the most of strong typing
10. Stereotypes
10.1. Default scope and deployment type for a stereotype
10.2. Restricting scope and type with a stereotype
10.3. Interceptor bindings for stereotypes
10.4. Name defaulting with stereotypes
10.5. Standard stereotypes
11. Specialization
11.1. Using specialization
11.2. Advantages of specialization
12. Defining Web Beans using XML
12.1. Declaring Web Bean classes
12.2. Declaring Web Bean metadata
12.3. Declaring Web Bean members
12.4. Declaring inline Web Beans
12.5. Using a schema
IV. Web Beans and the Java EE ecosystem
13. Java EE integration
13.1. Injecting Java EE resources into a Web Bean
13.2. Calling a Web Bean from a Servlet
13.3. Calling a Web Bean from a Message-Driven Bean
13.4. JMS endpoints
13.5. Packaging and deployment
14. Extending Web Beans
14.1. The Manager object
14.2. The Bean class
14.3. The Context interface
15. Next steps
V. Web Beans Reference
16. Application Servers and environments supported by Web Beans
16.1. Using Web Beans with JBoss AS
16.2. Glassfish
16.3. Servlet Containers (such as Tomcat or Jetty)
16.3.1. Tomcat
16.4. Java SE
16.4.1. Web Beans SE Module
17. JSR-299 extensions available as part of Web Beans
17.1. Web Beans Logger
18. Alternative view layers
18.1. Using Web Beans with Wicket
18.1.1. The WebApplication class
18.1.2. Conversations with Wicket
A. Integrating Web Beans into other environments
A.1. The Web Beans SPI
A.1.1. Web Bean Discovery
A.1.2. EJB services
A.1.3. JPA services
A.1.4. Transaction Services
A.1.5. JMS services
A.1.6. Resource Services
A.1.7. Web Services
A.1.8. The bean store
A.1.9. The application context
A.1.10. Bootstrap and shutdown
A.1.11. JNDI
A.1.12. Resource loading
A.1.13. Servlet injection
A.2. The contract with the container

JSR-299 has recently changed its name from "Web Beans" to "Java Contexts and Dependency Injection". The reference guide still refers to JSR-299 as "Web Beans" and the JSR-299 Reference Implementation as the "Web Beans RI". Other documentation, blogs, forum posts etc. may use the new nomenclature, including the new name for the JSR-299 Reference Implementation - "Web Beans".

You'll also find that some of the more recent functionality to be specified is missing (such as producer fields, realization, asynchronous events, XML mapping of EE resources).

The Web Beans (JSR-299) specification defines a set of services for the Java EE environment that makes applications much easier to develop. Web Beans layers an enhanced lifecycle and interaction model over existing Java component types including JavaBeans and Enterprise Java Beans. As a complement to the traditional Java EE programming model, the Web Beans services provide:

Dependency injection, together with contextual lifecycle management, saves the user of an unfamiliar API from having to ask and answer the following questions:

A Web Bean specifies only the type and semantics of other Web Beans it depends upon. It need not be aware of the actual lifecycle, concrete implementation, threading model or other clients of any Web Bean it depends upon. Even better, the concrete implementation, lifecycle and threading model of a Web Bean it depends upon may vary according to the deployment scenario, without affecting any client.

Events, interceptors and decorators enhance the loose-coupling that is inherent in this model:

Most importantly, Web Beans provides all these facilities in a typesafe way. Web Beans never uses string-based identifiers to determine how collaborating objects fit together. And XML, though it remains an option, is rarely used. Instead, Web Beans uses the typing information that is already available in the Java object model, together with a new pattern, called binding annotations, to wire together Web Beans, their dependencies, their interceptors and decorators and their event consumers.

The Web Beans services are general and apply to the following types of components that exist in the Java EE environment:

Web Beans even provides the necessary integration points so that other kinds of components defined by future Java EE specifications or by non-standard frameworks may be cleanly integrated with Web Beans, take advantage of the Web Beans services, and interact with any other kind of Web Bean.

Web Beans was influenced by a number of existing Java frameworks, including Seam, Guice and Spring. However, Web Beans has its own very distinct character: more typesafe than Seam, more stateful and less XML-centric than Spring, more web and enterprise-application capable than Guice.

Most importantly, Web Beans is a JCP standard that integrates cleanly with Java EE, and with any Java SE environment where embeddable EJB Lite is available.

Table of Contents

1. Getting started with Web Beans
1.1. Your first Web Bean
1.2. What is a Web Bean?
1.2.1. API types, binding types and dependency injection
1.2.2. Deployment types
1.2.3. Scope
1.2.4. Web Bean names and Unified EL
1.2.5. Interceptor binding types
1.3. What kinds of objects can be Web Beans?
1.3.1. Simple Web Beans
1.3.2. Enterprise Web Beans
1.3.3. Producer methods
1.3.4. JMS endpoints
2. JSF web application example
3. Getting started with Web Beans, the Reference Implementation of JSR-299
3.1. Using JBoss AS 5
3.2. Using Apache Tomcat 6.0
3.3. Using GlassFish
3.4. The numberguess example
3.4.1. The numberguess example in Tomcat
3.4.2. The numberguess example for Apache Wicket
3.4.3. The numberguess example for Java SE with Swing
3.5. The translator example
4. Dependency injection
4.1. Binding annotations
4.1.1. Binding annotations with members
4.1.2. Combinations of binding annnotations
4.1.3. Binding annotations and producer methods
4.1.4. The default binding type
4.2. Deployment types
4.2.1. Enabling deployment types
4.2.2. Deployment type precedence
4.2.3. Example deployment types
4.3. Fixing unsatisfied dependencies
4.4. Client proxies
4.5. Obtaining a Web Bean by programatic lookup
4.6. Lifecycle callbacks, @Resource, @EJB and @PersistenceContext
4.7. The InjectionPoint object
5. Scopes and contexts
5.1. Scope types
5.2. Built-in scopes
5.3. The conversation scope
5.3.1. Conversation demarcation
5.3.2. Conversation propagation
5.3.3. Conversation timeout
5.4. The dependent pseudo-scope
5.4.1. The @New annotation
6. Producer methods
6.1. Scope of a producer method
6.2. Injection into producer methods
6.3. Use of @New with producer methods

So you're already keen to get started writing your first Web Bean? Or perhaps you're skeptical, wondering what kinds of hoops the Web Beans specification will make you jump through! The good news is that you've probably already written and used hundreds, perhaps thousands of Web Beans. You might not even remember the first Web Bean you wrote.

With certain, very special exceptions, every Java class with a constructor that accepts no parameters is a Web Bean. That includes every JavaBean. Furthermore, every EJB 3-style session bean is a Web Bean. Sure, the JavaBeans and EJBs you've been writing every day have not been able to take advantage of the new services defined by the Web Beans specification, but you'll be able to use every one of them as Web Beans — injecting them into other Web Beans, configuring them via the Web Beans XML configuration facility, even adding interceptors and decorators to them — without touching your existing code.

Suppose that we have two existing Java classes, that we've been using for years in various applications. The first class parses a string into a list of sentences:

public class SentenceParser {

    public List<String> parse(String text) { ... }
}

The second existing class is a stateless session bean front-end for an external system that is able to translate sentences from one language to another:

@Stateless

public class SentenceTranslator implements Translator {
    public String translate(String sentence) { ... }
}

Where Translator is the local interface:

@Local

public interface Translator {
    public String translate(String sentence);
}

Unfortunately, we don't have a preexisting class that translates whole text documents. So let's write a Web Bean that does this job:

public class TextTranslator {

    
    private SentenceParser sentenceParser;
    private Translator sentenceTranslator;
    
    @Initializer
    TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
        this.sentenceParser = sentenceParser;
        this.sentenceTranslator = sentenceTranslator;
    }
    
    public String translate(String text) {
        StringBuilder sb = new StringBuilder();
        for (String sentence: sentenceParser.parse(text)) {
            sb.append(sentenceTranslator.translate(sentence));
        }
        return sb.toString();
    }
    
}

We may obtain an instance of TextTranslator by injecting it into a Web Bean, Servlet or EJB:

@Initializer

public setTextTranslator(TextTranslator textTranslator) {
    this.textTranslator = textTranslator;
}

Alternatively, we may obtain an instance by directly calling a method of the Web Bean manager:

TextTranslator tt = manager.getInstanceByType(TextTranslator.class);

But wait: TextTranslator does not have a constructor with no parameters! Is it still a Web Bean? Well, a class that does not have a constructor with no parameters can still be a Web Bean if it has a constructor annotated @Initializer.

As you've guessed, the @Initializer annotation has something to do with dependency injection! @Initializer may be applied to a constructor or method of a Web Bean, and tells the Web Bean manager to call that constructor or method when instantiating the Web Bean. The Web Bean manager will inject other Web Beans to the parameters of the constructor or method.

At system initialization time, the Web Bean manager must validate that exactly one Web Bean exists which satisfies each injection point. In our example, if no implementation of Translator available — if the SentenceTranslator EJB was not deployed — the Web Bean manager would throw an UnsatisfiedDependencyException. If more than one implementation of Translator was available, the Web Bean manager would throw an AmbiguousDependencyException.

So what, exactly, is a Web Bean?

A Web Bean is an application class that contains business logic. A Web Bean may be called directly from Java code, or it may be invoked via Unified EL. A Web Bean may access transactional resources. Dependencies between Web Beans are managed automatically by the Web Bean manager. Most Web Beans are stateful and contextual. The lifecycle of a Web Bean is always managed by the Web Bean manager.

Let's back up a second. What does it really mean to be "contextual"? Since Web Beans may be stateful, it matters which bean instance I have. Unlike a stateless component model (for example, stateless session beans) or a singleton component model (such as servlets, or singleton beans), different clients of a Web Bean see the Web Bean in different states. The client-visible state depends upon which instance of the Web Bean the client has a reference to.

However, like a stateless or singleton model, but unlike stateful session beans, the client does not control the lifecycle of the instance by explicitly creating and destroying it. Instead, the scope of the Web Bean determines:

For a given thread in a Web Beans application, there may be an active context associated with the scope of the Web Bean. This context may be unique to the thread (for example, if the Web Bean is request scoped), or it may be shared with certain other threads (for example, if the Web Bean is session scoped) or even all other threads (if it is application scoped).

Clients (for example, other Web Beans) executing in the same context will see the same instance of the Web Bean. But clients in a different context will see a different instance.

One great advantage of the contextual model is that it allows stateful Web Beans to be treated like services! The client need not concern itself with managing the lifecycle of the Web Bean it is using, nor does it even need to know what that lifecyle is. Web Beans interact by passing messages, and the Web Bean implementations define the lifecycle of their own state. The Web Beans are loosely coupled because:

We can replace one Web Bean with a different Web Bean that implements the same API and has a different lifecycle (a different scope) without affecting the other Web Bean implementation. In fact, Web Beans defines a sophisticated facility for overriding Web Bean implementations at deployment time, as we will see in Section 4.2, “Deployment types”.

Note that not all clients of a Web Bean are Web Beans. Other objects such as Servlets or Message-Driven Beans — which are by nature not injectable, contextual objects — may also obtain references to Web Beans by injection.

Enough hand-waving. More formally, according to the spec:

A Web Bean comprises:

  • A (nonempty) set of API types

  • A (nonempty) set of binding annotation types

  • A scope

  • A deployment type

  • Optionally, a Web Bean name

  • A set of interceptor binding types

  • A Web Bean implementation

Let's see what some of these terms mean, to the Web Bean developer.

Web Beans usually acquire references to other Web Beans via dependency injection. Any injected attribute specifies a "contract" that must be satisfied by the Web Bean to be injected. The contract is:

An API is a user-defined class or interface. (If the Web Bean is an EJB session bean, the API type is the @Local interface or bean-class local view). A binding type represents some client-visible semantic that is satisfied by some implementations of the API and not by others.

Binding types are represented by user-defined annotations that are themselves annotated @BindingType. For example, the following injection point has API type PaymentProcessor and binding type @CreditCard:

@CreditCard PaymentProcessor paymentProcessor

If no binding type is explicitly specified at an injection point, the default binding type @Current is assumed.

For each injection point, the Web Bean manager searches for a Web Bean which satisfies the contract (implements the API, and has all the binding types), and injects that Web Bean.

The following Web Bean has the binding type @CreditCard and implements the API type PaymentProcessor. It could therefore be injected to the example injection point:

@CreditCard

public class CreditCardPaymentProcessor 
    implements PaymentProcessor { ... }

If a Web Bean does not explicitly specify a set of binding types, it has exactly one binding type: the default binding type @Current.

Web Beans defines a sophisticated but intuitive resolution algorithm that helps the container decide what to do if there is more than one Web Bean that satisfies a particular contract. We'll get into the details in Chapter 4, Dependency injection.

We've already seen that JavaBeans, EJBs and some other Java classes can be Web Beans. But exactly what kinds of objects are Web Beans?

The specification says that all EJB 3-style session and singleton beans are enterprise Web Beans. Message driven beans are not Web Beans — since they are not intended to be injected into other objects — but they can take advantage of most of the functionality of Web Beans, including dependency injection and interceptors.

Every local interface of an enterprise Web Bean that does not have a wildcard type parameter or type variable, and every one of its superinterfaces, is an API type of the enterprise Web Bean. If the EJB bean has a bean class local view, the bean class, and every one of its superclasses, is also an API type.

Stateful session beans should declare a remove method with no parameters or a remove method annotated @Destructor. The Web Bean manager calls this method to destroy the stateful session bean instance at the end of its lifecycle. This method is called the destructor method of the enterprise Web Bean.

@Stateful @SessionScoped

public class ShoppingCart {
    ...
    
    @Remove
    public void destroy() {}
}

So when should we use an enterprise Web Bean instead of a simple Web Bean? Well, whenever we need the advanced enterprise services offered by EJB, such as:

we should use an enterprise Web Bean. When we don't need any of these things, a simple Web Bean will serve just fine.

Many Web Beans (including any session or application scoped Web Bean) are available for concurrent access. Therefore, the concurrency management provided by EJB 3.1 is especially useful. Most session and application scoped Web Beans should be EJBs.

Web Beans which hold references to heavy-weight resources, or hold a lot of internal state benefit from the advanced container-managed lifecycle defined by the EJB @Stateless/@Stateful/@Singleton model, with its support for passivation and instance pooling.

Finally, it's usually obvious when method-level transaction management, method-level security, timers, remote methods or asynchronous methods are needed.

It's usually easy to start with simple Web Bean, and then turn it into an EJB, just by adding an annotation: @Stateless, @Stateful or @Singleton.

Let's illustrate these ideas with a full example. We're going to implement user login/logout for an application that uses JSF. First, we'll define a Web Bean to hold the username and password entered during login:

@Named @RequestScoped

public class Credentials {
    
    private String username;
    private String password;
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
}

This Web Bean is bound to the login prompt in the following JSF form:

<h:form>

    <h:panelGrid columns="2" rendered="#{!login.loggedIn}">
        <h:outputLabel for="username">Username:</h:outputLabel>
        <h:inputText id="username" value="#{credentials.username}"/>
        <h:outputLabel for="password">Password:</h:outputLabel>
        <h:inputText id="password" value="#{credentials.password}"/>
    </h:panelGrid>
    <h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
    <h:commandButton value="Logout" acion="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>

The actual work is done by a session scoped Web Bean that maintains information about the currently logged-in user and exposes the User entity to other Web Beans:

@SessionScoped @Named

public class Login {
    @Current Credentials credentials;
    @PersistenceContext EntityManager userDatabase;
    private User user;
    
    public void login() {
        
        List<User> results = userDatabase.createQuery(
           "select u from User u where u.username=:username and u.password=:password")
           .setParameter("username", credentials.getUsername())
           .setParameter("password", credentials.getPassword())
           .getResultList();
        
        if ( !results.isEmpty() ) {
           user = results.get(0);
        }
        
    }
    
    public void logout() {
        user = null;
    }
    
    public boolean isLoggedIn() {
       return user!=null;
    }
    
    @Produces @LoggedIn User getCurrentUser() {
        return user;
    }
}

Of course, @LoggedIn is a binding annotation:

@Retention(RUNTIME)

@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface LoggedIn {}

Now, any other Web Bean can easily inject the current user:

public class DocumentEditor {


    @Current Document document;
    @LoggedIn User currentUser;
    @PersistenceContext EntityManager docDatabase;
    
    public void save() {
        document.setCreatedBy(currentUser);
        docDatabase.persist(document);
    }
    
}

Hopefully, this example gives a flavor of the Web Bean programming model. In the next chapter, we'll explore Web Beans dependency injection in greater depth.

The Web Beans is being developed at the Seam project. You can download the latest developer release of Web Beans from the the downloads page.

Web Beans comes with a two deployable example applications: webbeans-numberguess, a war example, containing only simple beans, and webbeans-translator an ear example, containing enterprise beans. There are also two variations on the numberguess example, the tomcat example (suitable for deployment to Tomcat) and the jsf2 example, which you can use if you are running JSF2. To run the examples you'll need the following:

  • the latest release of Web Beans,

  • JBoss AS 5.0.1.GA, or

  • Apache Tomcat 6.0.x, and

  • Ant 1.7.0.

You'll need to download JBoss AS 5.0.1.GA from jboss.org, and unzip it. For example:

$ cd /Applications
$ unzip ~/jboss-5.0.1.GA.zip

Next, download Web Beans from seamframework.org, and unzip it. For example

$ cd ~/
$ unzip ~/webbeans-$VERSION.zip

Next, we need to tell Web Beans where JBoss is located. Edit jboss-as/build.properties and set the jboss.home property. For example:

jboss.home=/Applications/jboss-5.0.1.GA

To install Web Beans, you'll need Ant 1.7.0 installed, and the ANT_HOME environment variable set. For example:

Note

JBoss 5.1.0 comes with Web Beans built in, so there is no need to update the server.

$ unzip apache-ant-1.7.0.zip
$ export ANT_HOME=~/apache-ant-1.7.0

Then, you can install the update. The update script will use Maven to download Web Beans automatically.

$ cd webbeans-$VERSION/jboss-as
$ ant update

Now, you're ready to deploy your first example!

Tip

The build scripts for the examples offer a number of targets for JBoss AS, these are:

  • ant restart - deploy the example in exploded format

  • ant explode - update an exploded example, without restarting the deployment

  • ant deploy - deploy the example in compressed jar format

  • ant undeploy - remove the example from the server

  • ant clean - clean the example

To deploy the numberguess example:

$ cd examples/numberguess
ant deploy

Start JBoss AS:

$ /Application/jboss-5.0.0.GA/bin/run.sh

Tip

If you use Windows, use the run.batscript.

Wait for the application to deploy, and enjoy hours of fun at http://localhost:8080/webbeans-numberguess!

Web Beans includes a second simple example that will translate your text into Latin. The numberguess example is a war example, and uses only simple beans; the translator example is an ear example, and includes enterprise beans, packaged in an EJB module. To try it out:

$ cd examples/translator
ant deploy

Wait for the application to deploy, and visit http://localhost:8080/webbeans-translator!

You'll need to download Tomcat 6.0.18 or later from tomcat.apache.org, and unzip it. For example:

$ cd /Applications
$ unzip ~/apache-tomcat-6.0.18.zip

Next, download Web Beans from seamframework.org, and unzip it. For example

$ cd ~/
$ unzip ~/webbeans-$VERSION.zip

Next, we need to tell Web Beans where Tomcat is located. Edit jboss-as/build.properties and set the tomcat.home property. For example:

tomcat.home=/Applications/apache-tomcat-6.0.18

Tip

The build scripts for the examples offer a number of targets for Tomcat, these are:

  • ant tomcat.restart - deploy the example in exploded format

  • ant tomcat.explode - update an exploded example, without restarting the deployment

  • ant tomcat.deploy - deploy the example in compressed jar format

  • ant tomcat.undeploy - remove the example from the server

  • ant tomcat.clean - clean the example

To deploy the numberguess example for tomcat:

$ cd examples/tomcat
ant tomcat.deploy

Start Tomcat:

$ /Applications/apache-tomcat-6.0.18/bin/startup.sh

Tip

If you use Windows, use the startup.batscript.

Wait for the application to deploy, and enjoy hours of fun at http://localhost:8080/webbeans-numberguess!

In the numberguess application you get given 10 attempts to guess a number between 1 and 100. After each attempt, you will be told whether you are too high, or too low.

The numberguess example is comprised of a number of Web Beans, configuration files, and Facelet JSF pages, packaged as a war. Let's start with the configuration files.

All the configuration files for this example are located in WEB-INF/, which is stored in WebContent in the source tree. First, we have faces-config.xml, in which we tell JSF to use Facelets:


<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
              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://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
    
    <application>
        <view-handler>com.sun.facelets.FaceletViewHandler</view-handler>
    </application>

</faces-config>

There is an empty web-beans.xml file, which marks this application as a Web Beans application.

Finally there is web.xml:

Let's take a look at the Facelet view:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:s="http://jboss.com/products/seam/taglib">

  <ui:composit(1)ion template="template.xhtml">
    <ui:define name="content">
       <h1>Guess a number...</h1>
       <h:form id="NumberGuessMain">
          <div(2) style="color: red">
             <h:messages id="messages" globalOnly="false"/>
             <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}"/>
             <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}"/>
          </div>
   
          <div>
             I(3)'m thinking of a number between #{game.smallest} and #{game.biggest}.
             You have #{game.remainingGuesses} guesses.
          </div>
     
          <div>
             Your guess: 
             <(4)h:inputText id="inputGuess" 
                          value="#{game.guess}" 
                          required="true" 
                          size="3" 
                          disabled="#{game.number eq game.guess}">
              (5)  <f:validateLongRange maximum="#{game.biggest}" 
                                     minimum="#{game.smallest}"/>
             </h:inputText>
            <h(6):commandButton id="GuessButton"  
                             value="Guess" 
                             action="#{game.check}" 
                             disabled="#{game.number eq game.guess}"/>
          </div>
          <div>
            <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" />
          </div>
       </h:form>
    </ui:define>
  </ui:composition>
</html>
1

Facelets is a templating language for JSF, here we are wrapping our page in a template which defines the header.

2

There are a number of messages which can be sent to the user, "Higher!", "Lower!" and "Correct!"

3

As the user guesses, the range of numbers they can guess gets smaller - this sentance changes to make sure they know what range to guess in.

4

This input field is bound to a Web Bean, using the value expression.

5

A range validator is used to make sure the user doesn't accidentally input a number outside of the range in which they can guess - if the validator wasn't here, the user might use up a guess on an out of range number.

6

And, of course, there must be a way for the user to send their guess to the server. Here we bind to an action method on the Web Bean.

The example exists of 4 classes, the first two of which are binding types. First, there is the @Random binding type, used for injecting a random number:

@Target( { TYPE, METHOD, PARAMETER, FIELD })

@Retention(RUNTIME)
@Documented
@BindingType
public @interface Random {}

There is also the @MaxNumber binding type, used for injecting the maximum number that can be injected:

@Target( { TYPE, METHOD, PARAMETER, FIELD })

@Retention(RUNTIME)
@Documented
@BindingType
public @interface MaxNumber {}

The Generator class is responsible for creating the random number, via a producer method. It also exposes the maximum possible number via a producer method:

@ApplicationScoped

public class Generator {
   
   private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
   
   private int maxNumber = 100;
   
   java.util.Random getRandom()
   {
      return random;
   }
   
   @Produces @Random int next() { 
      return getRandom().nextInt(maxNumber); 
   }
   
   @Produces @MaxNumber int getMaxNumber()
   {
      return maxNumber;
   }
}

You'll notice that the Generator is application scoped; therefore we don't get a different random each time.

The final Web Bean in the application is the session scoped Game.

You'll note that we've used the @Named annotation, so that we can use the bean through EL in the JSF page. Finally, we've used constructor injection to initialize the game with a random number. And of course, we need to tell the player when they've won, so we give feedback with a FacesMessage.

package org.jboss.webbeans.examples.numberguess;



import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.webbeans.AnnotationLiteral;
import javax.webbeans.Current;
import javax.webbeans.Initializer;
import javax.webbeans.Named;
import javax.webbeans.SessionScoped;
import javax.webbeans.manager.Manager;
@Named
@SessionScoped
public class Game
{
   private int number;
   
   private int guess;
   private int smallest;
   private int biggest;
   private int remainingGuesses;
   
   @Current Manager manager;
   
   public Game()
   {
   }
   
   @Initializer
   Game(@MaxNumber int maxNumber)
   {      
      this.biggest = maxNumber;
   }
   public int getNumber()
   {
      return number;
   }
   
   public int getGuess()
   {
      return guess;
   }
   
   public void setGuess(int guess)
   {
      this.guess = guess;
   }
   
   public int getSmallest()
   {
      return smallest;
   }
   
   public int getBiggest()
   {
      return biggest;
   }
   
   public int getRemainingGuesses()
   {
      return remainingGuesses;
   }
   
   public String check()
   {
      if (guess>number)
      {
         biggest = guess - 1;
      }
      if (guess<number)
      {
         smallest = guess + 1;
      }
      if (guess == number)
      {
         FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
      }
      remainingGuesses--;
      return null;
   }
   
   @PostConstruct
   public void reset()
   {
      this.smallest = 0;
      this.guess = 0;
      this.remainingGuesses = 10;
      this.number = manager.getInstanceByType(Integer.class, new AnnotationLiteral<Random>(){});
   }
   
}

Whilst JSR-299 specifies integration with Java ServerFaces, Web Beans allows you to inject into Wicket components, and also allows you to use a conversation context with Wicket. In this section, we'll walk you through the Wicket version of the numberguess example.

Like the previous example, the Wicket WebBeans examples make use of the webbeans-servlet module. The use of the Jetty servlet container is common in the Wicket community, and is chosen here as the runtime container in order to facilitate comparison between the standard Wicket examples and these examples, and also to show how the webbeans-servlet integration is not dependent upon Tomcat as the servlet container.

These examples make use of the Eclipse IDE; instructions are also given to deploy the application from the command line.

JSF uses Unified EL expressions to bind view layer components in JSP or Facelet views to beans, Wicket defines it's components in Java. The markup is plain html with a one-to-one mapping between html elements and the view components. All view logic, including binding of components to models and controlling the response of view actions, is handled in Java. The integration of Web Beans with Wicket takes advantage of the same binding annotations used in your business layer to provide injection into your WebPage subclass (or into other custom wicket component subclasses).

The code in the wicket numberguess example is very similar to the JSF-based numberguess example. The business layer is identical!

Differences are:

This example can be found in the examples/se/numberguess folder of the Web Beans distribution.

To run this example:

There is an empty beans.xml file in the root package (src/main/resources/beans.xml), which marks this application as a Web Beans application.

The game's main logic is located in Game.java. Here is the code for that class, highlighting the changes made from the web application version:

(1)(2)@ApplicationScoped

public class Game implements Serializable
{
    private int number;
    private int guess;
    private int smallest;
    @MaxNumber
    private int maxNumber;
    private int biggest;
    private int remainingGuesses;
    private boolean validNumberRange = true;
    @Current Generator rndGenerator;
    ...
    public boolean isValidNumberRange()
    {
        return validNumberRange;
    }
    public boolean isGameWon()
(3)    {
        return guess == number;
    }
    public boolean isGameLost()
    {
        return guess != number && remainingGuesses <= 0;
    }
    public boolean check()
    {
        boolean result = false;
(4)        if ( checkNewNumberRangeIsValid() )
        {
            if ( guess > number )
            {
                biggest = guess - 1;
            }
            if ( guess < number )
            {
                smallest = guess + 1;
            }
            if ( guess == number )
            {
                result = true;
            }
            remainingGuesses--;
        }
        return result;
    }
    private boolean checkNewNumberRangeIsValid()
    {
        return validNumberRange = ( ( guess >= smallest ) && ( guess <= biggest ) );
    }
    @PostConstruct
(5)    public void reset()
    {
        this.smallest = 0;
        ...
        this.number = rndGenerator.next();
    }
}
1

The bean is application scoped instead of session scoped, since an instance of the application represents a single 'session'.

2

The bean is not named, since it doesn't need to be accessed via EL

3

There is no JSF FacesContext to add messages to. Instead the Game class provides additional information about the state of the current game including:

  • If the game has been won or lost

  • If the most recent guess was invalid

This allows the Swing UI to query the state of the game, which it does indirectly via a class called MessageGenerator, in order to determine the appropriate messages to display to the user during the game.

4

Validation of user input is performed during the check() method, since there is no dedicated validation phase

5

The reset() method makes a call to the injected rndGenerator in order to get the random number at the start of each game. It cannot use manager.getInstanceByType(Integer.class, new AnnotationLiteral<Random>(){}) as the JSF example does because there will not be any active contexts like there is during a JSF request.

The MessageGenerator class depends on the current instance of Game, and queries its state in order to determine the appropriate messages to provide as the prompt for the user's next guess and the response to the previous guess. The code for MessageGenerator is as follows:

public class MessageGenerator

{
(1)    @Current Game game;
(2)    public String getChallengeMessage()
    {
        StringBuilder challengeMsg = new StringBuilder( "I'm thinking of a number between " );
        challengeMsg.append( game.getSmallest() );
        challengeMsg.append( " and " );
        challengeMsg.append( game.getBiggest() );
        challengeMsg.append( ". Can you guess what it is?" );
        return challengeMsg.toString();
    }
(3)    public String getResultMessage()
    {
        if ( game.isGameWon() )
        {
            return "You guess it! The number was " + game.getNumber();
        } else if ( game.isGameLost() )
        {
            return "You are fail! The number was " + game.getNumber();
        } else if ( ! game.isValidNumberRange() )
        {
            return "Invalid number range!";
        } else if ( game.getRemainingGuesses() == Game.MAX_NUM_GUESSES )
        {
            return "What is your first guess?";
        } else
        {
            String direction = null;
            if ( game.getGuess() < game.getNumber() )
            {
                direction = "Higher";
            } else
            {
                direction = "Lower";
            }
            return direction + "! You have " + game.getRemainingGuesses() + " guesses left.";
        }
    }
}
1

The instance of Game for the application is injected here.

2

The Game's state is interrogated to determine the appropriate challenge message.

3

And again to determine whether to congratulate, console or encourage the user to continue.

Finally we come to the NumberGuessFrame class which provides the Swing front end to our guessing game.

public class NumberGuessFrame  extends javax.swing.JFrame

{
(1)    private @Current Game game;
(2)    private @Current MessageGenerator msgGenerator;
(3)    public void start( @Observes @Deployed Manager manager )
    {
        java.awt.EventQueue.invokeLater( new Runnable()
            {
                public void run()
                {
                    initComponents();
                    setVisible( true );
                }
            } );
    }
(4)    private void initComponents() {
        buttonPanel = new javax.swing.JPanel();
        mainMsgPanel = new javax.swing.JPanel();
        mainLabel = new javax.swing.JLabel();
        messageLabel = new javax.swing.JLabel();
        guessText = new javax.swing.JTextField();
        ...
        mainLabel.setText(msgGenerator.getChallengeMessage());
        mainMsgPanel.add(mainLabel);
        messageLabel.setText(msgGenerator.getResultMessage());
        mainMsgPanel.add(messageLabel);
        ...
    }
(5)    private void guessButtonActionPerformed( java.awt.event.ActionEvent evt )
    {
        int guess =  Integer.parseInt(guessText.getText());
        game.setGuess( guess );
        game.check();
        refreshUI();
    }
(6)    private void replayBtnActionPerformed( java.awt.event.ActionEvent evt )
    {
       game.reset();
       refreshUI();
    }
(7)    private void refreshUI()
    {
        mainLabel.setText( msgGenerator.getChallengeMessage() );
        messageLabel.setText( msgGenerator.getResultMessage() );
        guessText.setText( "" );
        guessesLeftBar.setValue( game.getRemainingGuesses() );
        guessText.requestFocus();
    }
    // swing components
    private javax.swing.JPanel borderPanel;
    ...
    private javax.swing.JButton replayBtn;
}
1

The injected instance of the game (logic and state).

2

The injected message generator for UI messages.

3

This application is started in the usual Web Beans SE way, by observing the @Deployed Manager event.

4

This method initialises all of the Swing components. Note the use of the msgGenerator.

5

guessButtonActionPerformed is called when the 'Guess' button is clicked, and it does the following:

  • Gets the guess entered by the user and sets it as the current guess in the Game

  • Calls game.check() to validate and perform one 'turn' of the game

  • Calls refreshUI. If there were validation errors with the input, this will have been captured during game.check() and as such will be reflected in the messeges returned by MessageGenerator and subsequently presented to the user. If there are no validation errors then the user will be told to guess again (higher or lower) or that the game has ended either in a win (correct guess) or a loss (ran out of guesses).

6

replayBtnActionPerformed simply calls game.reset() to start a new game and refreshes the messages in the UI.

7

refreshUI uses the MessageGenerator to update the messages to the user based on the current state of the Game.

The translator example will take any sentences you enter, and translate them to Latin.

The translator example is built as an ear, and contains EJBs. As a result, it's structure is more complex than the numberguess example.

First, let's take a look at the ear aggregator, which is located in webbeans-translator-ear module. Maven automatically generates the application.xml for us:


<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-ear-plugin</artifactId>
   <configuration>
      <modules>
         <webModule>
            <groupId>org.jboss.webbeans.examples.translator</groupId>
            <artifactId>webbeans-translator-war</artifactId>
            <contextRoot>/webbeans-translator</contextRoot>
         </webModule>
      </modules>
   </configuration>
</plugin>

Here we set the context path, which gives us a nice url (http://localhost:8080/webbeans-translator).

Tip

If you aren't using Maven to generate these files, you would need META-INF/application.xml:


<?xml version="1.0" encoding="UTF-8"?>
<application 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://java.sun.com/xml/ns/javaee/application_5.xsd"
             version="5">
  <display-name>webbeans-translator-ear</display-name>
  <description>Ear Example for the reference implementation of JSR 299: Web Beans</description>
  
  <module>
    <web>
      <web-uri>webbeans-translator.war</web-uri>
      <context-root>/webbeans-translator</context-root>
    </web>
  </module>
  <module>
    <ejb>webbeans-translator.jar</ejb>
  </module>
</application>

Next, lets look at the war. Just as in the numberguess example, we have a faces-config.xml (to enable Facelets) and a web.xml (to enable JSF) in WebContent/WEB-INF.

More intersting is the facelet used to translate text. Just as in the numberguess example we have a template, which surrounds the form (ommitted here for brevity):


<h:form id="NumberGuessMain">
            
   <table>
      <tr align="center" style="font-weight: bold" >
         <td>
            Your text
         </td>
         <td>
            Translation
         </td>
      </tr>
      <tr>
         <td>
            <h:inputTextarea id="text" value="#{translator.text}" required="true" rows="5" cols="80" />
         </td>
         <td>
            <h:outputText value="#{translator.translatedText}" />
         </td>
      </tr>
   </table>
   <div>
      <h:commandButton id="button" value="Translate" action="#{translator.translate}"/>
   </div>
   
</h:form>

The user can enter some text in the lefthand textarea, and hit the translate button to see the result to the right.

Finally, let's look at the ejb module, webbeans-translator-ejb. In src/main/resources/META-INF there is just an empty web-beans.xml, used to mark the archive as containing Web Beans.

We've saved the most interesting bit to last, the code! The project has two simple beans, SentenceParser and TextTranslator and two enterprise beans, TranslatorControllerBean and SentenceTranslator. You should be getting quite familiar with what a Web Bean looks like by now, so we'll just highlight the most interesting bits here.

Both SentenceParser and TextTranslator are dependent beans, and TextTranslator uses constructor initialization:

public class TextTranslator { 

   private SentenceParser sentenceParser; 
   private Translator sentenceTranslator; 
   
   @Initializer
   TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) 
   { 
      this.sentenceParser = sentenceParser; 
      this.sentenceTranslator = sentenceTranslator;

TextTranslator is a stateless bean (with a local business interface), where the magic happens - of course, we couldn't develop a full translator, but we gave it a good go!

Finally, there is UI orientated controller, that collects the text from the user, and dispatches it to the translator. This is a request scoped, named, stateful session bean, which injects the translator.

@Stateful

@RequestScoped
@Named("translator")
public class TranslatorControllerBean implements TranslatorController
{
   
   @Current TextTranslator translator;

The bean also has getters and setters for all the fields on the page.

As this is a stateful session bean, we have to have a remove method:

   @Remove

   public void remove()
   {
      
   }

The Web Beans manager will call the remove method for you when the bean is destroyed; in this case at the end of the request.

That concludes our short tour of the Web Beans examples. For more on Web Beans , or to help out, please visit http://www.seamframework.org/WebBeans/Development.

We need help in all areas - bug fixing, writing new features, writing examples and translating this reference guide.

Web Beans supports three primary mechanisms for dependency injection:

Constructor parameter injection:

public class Checkout {

        
    private final ShoppingCart cart;
    
    @Initializer
    public Checkout(ShoppingCart cart) {
        this.cart = cart;
    }
}

Initializer method parameter injection:

public class Checkout {

        
    private ShoppingCart cart;
    @Initializer 
    void setShoppingCart(ShoppingCart cart) {
        this.cart = cart;
    }
    
}

And direct field injection:

public class Checkout {


    private @Current ShoppingCart cart;
    
}

Dependency injection always occurs when the Web Bean instance is first instantiated.

  • First, the Web Bean manager calls the Web Bean constructor, to obtain an instance of the Web Bean.

  • Next, the Web Bean manager initializes the values of all injected fields of the Web Bean.

  • Next, the Web Bean manager calls all initializer methods of Web Bean.

  • Finally, the @PostConstruct method of the Web Bean, if any, is called.

Constructor parameter injection is not supported for EJB beans, since the EJB is instantiated by the EJB container, not the Web Bean manager.

Parameters of constructors and initializer methods need not be explicitly annotated when the default binding type @Current applies. Injected fields, however, must specify a binding type, even when the default binding type applies. If the field does not specify a binding type, it will not be injected.

Producer methods also support parameter injection:

@Produces Checkout createCheckout(ShoppingCart cart) {

    return new Checkout(cart);
}

Finally, observer methods (which we'll meet in Chapter 9, Events), disposal methods and destructor methods all support parameter injection.

The Web Beans specification defines a procedure, called the typesafe resolution algorithm, that the Web Bean manager follows when identifying the Web Bean to inject to an injection point. This algorithm looks complex at first, but once you understand it, it's really quite intuitive. Typesafe resolution is performed at system initialization time, which means that the manager will inform the user immediately if a Web Bean's dependencies cannot be satisfied, by throwing a UnsatisfiedDependencyException or AmbiguousDependencyException.

The purpose of this algorithm is to allow multiple Web Beans to implement the same API type and either:

  • allow the client to select which implementation it requires using binding annotations,

  • allow the application deployer to select which implementation is appropriate for a particular deployment, without changes to the client, by enabling or disabling deployment types, or

  • allow one implementation of an API to override another implementation of the same API at deployment time, without changes to the client, using deployment type precedence.

Let's explore how the Web Beans manager determines a Web Bean to be injected.

If we have more than one Web Bean that implements a particular API type, the injection point can specify exactly which Web Bean should be injected using a binding annotation. For example, there might be two implementations of PaymentProcessor:

@PayByCheque

public class ChequePaymentProcessor implements PaymentProcessor {
    public void process(Payment payment) { ... }
}
@PayByCreditCard

public class CreditCardPaymentProcessor implements PaymentProcessor {
    public void process(Payment payment) { ... }
}

Where @PayByCheque and @PayByCreditCard are binding annotations:

@Retention(RUNTIME)

@Target({TYPE, METHOD, FIELD, PARAMETER})
@BindingType
public @interface PayByCheque {}
@Retention(RUNTIME)

@Target({TYPE, METHOD, FIELD, PARAMETER})
@BindingType
public @interface PayByCreditCard {}

A client Web Bean developer uses the binding annotation to specify exactly which Web Bean should be injected.

Using field injection:

@PayByCheque PaymentProcessor chequePaymentProcessor;

@PayByCreditCard PaymentProcessor creditCardPaymentProcessor;

Using initializer method injection:

@Initializer

public void setPaymentProcessors(@PayByCheque PaymentProcessor chequePaymentProcessor, 
                                 @PayByCreditCard PaymentProcessor creditCardPaymentProcessor) {
   this.chequePaymentProcessor = chequePaymentProcessor;
   this.creditCardPaymentProcessor = creditCardPaymentProcessor;
}

Or using constructor injection:

@Initializer

public Checkout(@PayByCheque PaymentProcessor chequePaymentProcessor, 
                @PayByCreditCard PaymentProcessor creditCardPaymentProcessor) {
   this.chequePaymentProcessor = chequePaymentProcessor;
   this.creditCardPaymentProcessor = creditCardPaymentProcessor;
}

All Web Beans have a deployment type. Each deployment type identifies a set of Web Beans that should be conditionally installed in some deployments of the system.

For example, we could define a deployment type named @Mock, which would identify Web Beans that should only be installed when the system executes inside an integration testing environment:

@Retention(RUNTIME)

  @Target({TYPE, METHOD})
  @DeploymentType
  public @interface Mock {}

Suppose we had some Web Bean that interacted with an external system to process payments:

public class ExternalPaymentProcessor {

        
    public void process(Payment p) {
        ...
    }
    
}

Since this Web Bean does not explicitly specify a deployment type, it has the default deployment type @Production.

For integration or unit testing, the external system is slow or unavailable. So we would create a mock object:

@Mock 

public class MockPaymentProcessor implements PaymentProcessor {
    @Override
    public void process(Payment p) {
        p.setSuccessful(true);
    }
}

But how does the Web Bean manager determine which implementation to use in a particular deployment?

If you've been paying attention, you're probably wondering how the Web Bean manager decides which implementation — ExternalPaymentProcessor or MockPaymentProcessor — to choose. Consider what happens when the manager encounters this injection point:

@Current PaymentProcessor paymentProcessor

There are now two Web Beans which satisfy the PaymentProcessor contract. Of course, we can't use a binding annotation to disambiguate, since binding annotations are hard-coded into the source at the injection point, and we want the manager to be able to decide at deployment time!

The solution to this problem is that each deployment type has a different precedence. The precedence of the deployment types is determined by the order in which they appear in web-beans.xml. In our example, @Mock appears later than @Production so it has a higher precedence.

Whenever the manager discovers that more than one Web Bean could satisfy the contract (API type plus binding annotations) specified by an injection point, it considers the relative precedence of the Web Beans. If one has a higher precedence than the others, it chooses the higher precedence Web Bean to inject. So, in our example, the Web Bean manager will inject MockPaymentProcessor when executing in our integration testing environment (which is exactly what we want).

It's interesting to compare this facility to today's popular manager architectures. Various "lightweight" containers also allow conditional deployment of classes that exist in the classpath, but the classes that are to be deployed must be explicity, individually, listed in configuration code or in some XML configuration file. Web Beans does support Web Bean definition and configuration via XML, but in the common case where no complex configuration is required, deployment types allow a whole set of Web Beans to be enabled with a single line of XML. Meanwhile, a developer browsing the code can easily identify what deployment scenarios the Web Bean will be used in.

Clients of an injected Web Bean do not usually hold a direct reference to a Web Bean instance.

Imagine that a Web Bean bound to the application scope held a direct reference to a Web Bean bound to the request scope. The application scoped Web Bean is shared between many different requests. However, each request should see a different instance of the request scoped Web bean!

Now imagine that a Web Bean bound to the session scope held a direct reference to a Web Bean bound to the application scope. From time to time, the session context is serialized to disk in order to use memory more efficiently. However, the application scoped Web Bean instance should not be serialized along with the session scoped Web Bean!

Therefore, unless a Web Bean has the default scope @Dependent, the Web Bean manager must indirect all injected references to the Web Bean through a proxy object. This client proxy is responsible for ensuring that the Web Bean instance that receives a method invocation is the instance that is associated with the current context. The client proxy also allows Web Beans bound to contexts such as the session context to be serialized to disk without recursively serializing other injected Web Beans.

Unfortunately, due to limitations of the Java language, some Java types cannot be proxied by the Web Bean manager. Therefore, the Web Bean manager throws an UnproxyableDependencyException if the type of an injection point cannot be proxied.

The following Java types cannot be proxied by the Web Bean manager:

It's usually very easy to fix an UnproxyableDependencyException. Simply add a constructor with no parameters to the injected class, introduce an interface, or change the scope of the injected Web Bean to @Dependent.

There are certain kinds of dependent objects — Web Beans with scope @Dependent — that need to know something about the object or injection point into which they are injected in order to be able to do what they do. For example:

A Web Bean with scope @Dependent may inject an instance of InjectionPoint and access metadata relating to the injection point to which it belongs.

Let's look at an example. The following code is verbose, and vulnerable to refactoring problems:

Logger log = Logger.getLogger(MyClass.class.getName());

This clever little producer method lets you inject a JDK Logger without explicitly specifying the log category:

class LogFactory {


   @Produces Logger createLogger(InjectionPoint injectionPoint) { 
      return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); 
   }
}

We can now write:

@Current Logger log;

Not convinced? Then here's a second example. To inject HTTP parameters, we need to define a binding type:

@BindingType

@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface HttpParam {
   @NonBinding public String value();
}

We would use this binding type at injection points as follows:

@HttpParam("username") String username;

@HttpParam("password") String password;

The following producer method does the work:

class HttpParams


   @Produces @HttpParam("")
   String getParamValue(ServletRequest request, InjectionPoint ip) {
      return request.getParameter(ip.getAnnotation(HttpParam.class).value());
   }
}

(Note that the value() member of the HttpParam annotation is ignored by the Web Bean manager since it is annotated @NonBinding.)

The Web Bean manager provides a built-in Web Bean that implements the InjectionPoint interface:

public interface InjectionPoint { 

   public Object getInstance(); 
   public Bean<?> getBean(); 
   public Member getMember(): 
   public <extends Annotation> T getAnnotation(Class<T> annotation); 
   public Set<extends Annotation> getAnnotations(); 
}

So far, we've seen a few examples of scope type annotations. The scope of a Web Bean determines the lifecycle of instances of the Web Bean. The scope also determines which clients refer to which instances of the Web Bean. According to the Web Beans specification, a scope determines:

  • When a new instance of any Web Bean with that scope is created

  • When an existing instance of any Web Bean with that scope is destroyed

  • Which injected references refer to any instance of a Web Bean with that scope

For example, if we have a session scoped Web Bean, CurrentUser, all Web Beans that are called in the context of the same HttpSession will see the same instance of CurrentUser. This instance will be automatically created the first time a CurrentUser is needed in that session, and automatically destroyed when the session ends.

The Web Beans conversation scope is a bit like the traditional session scope in that it holds state associated with a user of the system, and spans multiple requests to the server. However, unlike the session scope, the conversation scope:

A conversation represents a task, a unit of work from the point of view of the user. The conversation context holds state associated with what the user is currently working on. If the user is doing multiple things at the same time, there are multiple conversations.

The conversation context is active during any JSF request. However, most conversations are destroyed at the end of the request. If a conversation should hold state across multiple requests, it must be explicitly promoted to a long-running conversation.

Web Beans provides a built-in Web Bean for controlling the lifecyle of conversations in a JSF application. This Web Bean may be obtained by injection:

@Current Conversation conversation;

To promote the conversation associated with the current request to a long-running conversation, call the begin() method from application code. To schedule the current long-running conversation context for destruction at the end of the current request, call end().

In the following example, a conversation-scoped Web Bean controls the conversation with which it is associated:

@ConversationScoped @Stateful

public class OrderBuilder {
    private Order order;
    private @Current Conversation conversation;
    private @PersistenceContext(type=EXTENDED) EntityManager em;
    
    @Produces public Order getOrder() {
        return order;
    }
    public Order createOrder() {
        order = new Order();
        conversation.begin();
        return order;
    }
    
    public void addLineItem(Product product, int quantity) {
        order.add( new LineItem(product, quantity) );
    }
    public void saveOrder(Order order) {
        em.persist(order);
        conversation.end();
    }
    
    @Remove
    public void destroy() {}
    
}

This Web Bean is able to control its own lifecycle through use of the Conversation API. But some other Web Beans have a lifecycle which depends completely upon another object.

In addition to the four built-in scopes, Web Beans features the so-called dependent pseudo-scope. This is the default scope for a Web Bean which does not explicitly declare a scope type.

For example, this Web Bean has the scope type @Dependent:

public class Calculator { ... }

When an injection point of a Web Bean resolves to a dependent Web Bean, a new instance of the dependent Web Bean is created every time the first Web Bean is instantiated. Instances of dependent Web Beans are never shared between different Web Beans or different injection points. They are dependent objects of some other Web Bean instance.

Dependent Web Bean instances are destroyed when the instance they depend upon is destroyed.

Web Beans makes it easy to obtain a dependent instance of a Java class or EJB bean, even if the class or EJB bean is already declared as a Web Bean with some other scope type.

Producer methods let us overcome certain limitations that arise when the Web Bean manager, instead of the application, is responsible for instantiating objects. They're also the easiest way to integrate objects which are not Web Beans into the Web Beans environment. (We'll meet a second approach in Chapter 12, Defining Web Beans using XML.)

According to the spec:

A Web Beans producer method acts as a source of objects to be injected, where:

  • the objects to be injected are not required to be instances of Web Beans,

  • the concrete type of the objects to be injected may vary at runtime or

  • the objects require some custom initialization that is not performed by the Web Bean constructor

For example, producer methods let us:

  • expose a JPA entity as a Web Bean,

  • expose any JDK class as a Web Bean,

  • define multiple Web Beans, with different scopes or initialization, for the same implementation class, or

  • vary the implementation of an API type at runtime.

In particular, producer methods let us use runtime polymorphism with Web Beans. As we've seen, deployment types are a powerful solution to the problem of deployment-time polymorphism. But once the system is deployed, the Web Bean implementation is fixed. A producer method has no such limitation:

@SessionScoped

public class Preferences {
    
    private PaymentStrategyType paymentStrategy;
    
    ...
    
    @Produces @Preferred 
    public PaymentStrategy getPaymentStrategy() {
        switch (paymentStrategy) {
            case CREDIT_CARD: return new CreditCardPaymentStrategy();
            case CHEQUE: return new ChequePaymentStrategy();
            case PAYPAL: return new PayPalPaymentStrategy();
            default: return null;
        } 
    }
    
}

Consider an injection point:

@Preferred PaymentStrategy paymentStrat;

This injection point has the same type and binding annotations as the producer method, so it resolves to the producer method using the usual Web Beans injection rules. The producer method will be called by the Web Bean manager to obtain an instance to service this injection point.

.

There's one potential problem with the code above. The implementations of CreditCardPaymentStrategy are instantiated using the Java new operator. Objects instantiated directly by the application can't take advantage of dependency injection and don't have interceptors.

If this isn't what we want we can use dependency injection into the producer method to obtain Web Bean instances:

@Produces @Preferred @SessionScoped

public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,
                                          ChequePaymentStrategy cps,
                                          PayPalPaymentStrategy ppps) {
    switch (paymentStrategy) {
        case CREDIT_CARD: return ccps;
        case CHEQUE: return cps;
        case PAYPAL: return ppps;
        default: return null;
    } 
}

Wait, what if CreditCardPaymentStrategy is a request scoped Web Bean? Then the producer method has the effect of "promoting" the current request scoped instance into session scope. This is almost certainly a bug! The request scoped object will be destroyed by the Web Bean manager before the session ends, but the reference to the object will be left "hanging" in the session scope. This error will not be detected by the Web Bean manager, so please take extra care when returning Web Bean instances from producer methods!

There's at least three ways we could go about fixing this bug. We could change the scope of the CreditCardPaymentStrategy implementation, but this would affect other clients of that Web Bean. A better option would be to change the scope of the producer method to @Dependent or @RequestScoped.

But a more common solution is to use the special @New binding annotation.

The first major theme of Web Beans is loose coupling. We've already seen three means of achieving loose coupling:

These techniques serve to enable loose coupling of client and server. The client is no longer tightly bound to an implementation of an API, nor is it required to manage the lifecycle of the server object. This approach lets stateful objects interact as if they were services.

Loose coupling makes a system more dynamic. The system can respond to change in a well-defined manner. In the past, frameworks that attempted to provide the facilities listed above invariably did it by sacrificing type safety. Web Beans is the first technology that achieves this level of loose coupling in a typesafe way.

Web Beans provides three extra important facilities that further the goal of loose coupling:

Let's explore interceptors first.

Web Beans re-uses the basic interceptor architecture of EJB 3.0, extending the functionality in two directions:

  • Any Web Bean may have interceptors, not just session beans.

  • Web Beans features a more sophisticated annotation-based approach to binding interceptors to Web Beans.

The EJB specification defines two kinds of interception points:

  • business method interception, and

  • lifecycle callback interception.

A business method interceptor applies to invocations of methods of the Web Bean by clients of the Web Bean:

public class TransactionInterceptor {

    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

A lifecycle callback interceptor applies to invocations of lifecycle callbacks by the container:

public class DependencyInjectionInterceptor {

    @PostConstruct public void injectDependencies(InvocationContext ctx) { ... }
}

An interceptor class may intercept both lifecycle callbacks and business methods.

Interceptors are a powerful way to capture and separate concerns which are orthogonal to the type system. Any interceptor is able to intercept invocations of any Java type. This makes them perfect for solving technical concerns such as transaction management and security. However, by nature, interceptors are unaware of the actual semantics of the events they intercept. Thus, interceptors aren't an appropriate tool for separating business-related concerns.

The reverse is true of decorators. A decorator intercepts invocations only for a certain Java interface, and is therefore aware of all the semantics attached to that interface. This makes decorators a perfect tool for modeling some kinds of business concerns. It also means that a decorator doesn't have the generality of an interceptor. Decorators aren't able to solve technical concerns that cut across many disparate types.

Suppose we have an interface that represents accounts:

public interface Account {

    public BigDecimal getBalance();
    public User getOwner();
    public void withdraw(BigDecimal amount);
    public void deposit(BigDecimal amount);
}

Several different Web Beans in our system implement the Account interface. However, we have a common legal requirement that, for any kind of account, large transactions must be recorded by the system in a special log. This is a perfect job for a decorator.

A decorator is a simple Web Bean that implements the type it decorates and is annotated @Decorator.

@Decorator

public abstract class LargeTransactionDecorator 
        implements Account {
    
    @Decorates Account account;
    
    @PersistenceContext EntityManager em;
    
    public void withdraw(BigDecimal amount) {
        account.withdraw(amount);
        if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
            em.persist( new LoggedWithdrawl(amount) );
        }
    }
    
    public void deposit(BigDecimal amount);
        account.deposit(amount);
        if ( amount.compareTo(LARGE_AMOUNT)>0 ) {
            em.persist( new LoggedDeposit(amount) );
        }
    }
    
}

Unlike other simple Web Beans, a decorator may be an abstract class. If there's nothing special the decorator needs to do for a particular method of the decorated interface, you don't need to implement that method.

The Web Beans event notification facility allows Web Beans to interact in a totally decoupled manner. Event producers raise events that are then delivered to event observers by the Web Bean manager. This basic schema might sound like the familiar observer/observable pattern, but there are a couple of twists:

  • not only are event producers decoupled from observers; observers are completely decoupled from producers,

  • observers can specify a combination of "selectors" to narrow the set of event notifications they will receive, and

  • observers can be notified immediately, or can specify that delivery of the event should be delayed until the end of the current transaction

The event producer may obtain an event notifier object by injection:

@Observable Event<Document> documentEvent

The @Observable annotation implicitly defines a Web Bean with scope @Dependent and deployment type @Standard, with an implementation provided by the Web Bean manager.

A producer raises events by calling the fire() method of the Event interface, passing an event object:

documentEvent.fire(document);

An event object may be an instance of any Java class that has no type variables or wildcard type parameters. The event will be delivered to every observer method that:

The Web Bean manager simply calls all the observer methods, passing the event object as the value of the event parameter. If any observer method throws an exception, the Web Bean manager stops calling observer methods, and the exception is rethrown by the fire() method.

To specify a "selector", the event producer may pass an instance of the event binding type to the fire() method:

documentEvent.fire( document, new AnnotationLiteral<Updated>(){} );

The helper class AnnotationLiteral makes it possible to instantiate binding types inline, since this is otherwise difficult to do in Java.

The event will be delivered to every observer method that:

Alternatively, event bindings may be specified by annotating the event notifier injection point:

@Observable @Updated Event<Document> documentUpdatedEvent

Then every event fired via this instance of Event has the annotated event binding. The event will be delivered to every observer method that:

Transactional observers receive their event notifications during the before or after completion phase of the transaction in which the event was raised. For example, the following observer method needs to refresh a query result set that is cached in the application context, but only when transactions that update the Category tree succeed:

public void refreshCategoryTree(@AfterTransactionSuccess @Observes CategoryUpdateEvent event) { ... }

There are three kinds of transactional observers:

Transactional observers are very important in a stateful object model like Web Beans, because state is often held for longer than a single atomic transaction.

Imagine that we have cached a JPA query result set in the application scope:

@ApplicationScoped @Singleton

public class Catalog {
    @PersistenceContext EntityManager em;
    
    List<Product> products;
    @Produces @Catalog 
    List<Product> getCatalog() {
        if (products==null) {
            products = em.createQuery("select p from Product p where p.deleted = false")
                .getResultList();
        }
        return products;
    }
    
}

From time to time, a Product is created or deleted. When this occurs, we need to refresh the Product catalog. But we should wait until after the transaction completes successfully before performing this refresh!

The Web Bean that creates and deletes Products could raise events, for example:

@Stateless

public class ProductManager {
    @PersistenceContext EntityManager em;
    @Observable Event<Product> productEvent;
    public void delete(Product product) {
        em.delete(product);
        productEvent.fire(product, new AnnotationLiteral<Deleted>(){});
    }
    
    public void persist(Product product) {
        em.persist(product);
        productEvent.fire(product, new AnnotationLiteral<Created>(){});
    }
    
    ...
    
}

And now Catalog can observe the events after successful completion of the transaction:

@ApplicationScoped @Singleton

public class Catalog {
    ...
    
    void addProduct(@AfterTransactionSuccess @Observes @Created Product product) {
        products.add(product);
    }
    
    void addProduct(@AfterTransactionSuccess @Observes @Deleted Product product) {
        products.remove(product);
    }
    
}

The second major theme of Web Beans is strong typing. The information about the dependencies, interceptors and decorators of a Web Bean, and the information about event consumers for an event producer, is contained in typesafe Java constructs that may be validated by the compiler.

You don't see string-based identifiers in Web Beans code, not because the framework is hiding them from you using clever defaulting rules — so-called "configuration by convention" — but because there are simply no strings there to begin with!

The obvious benefit of this approach is that any IDE can provide autocompletion, validation and refactoring without the need for special tooling. But there is a second, less-immediately-obvious, benefit. It turns out that when you start thinking of identifying objects, events or interceptors via annotations instead of names, you have an opportunity to lift the semantic level of your code.

Web Beans encourages you develop annotations that model concepts, for example,

instead of using compound names like

The annotations are reusable. They help describe common qualities of disparate parts of the system. They help us categorize and understand our code. They help us deal with common concerns in a common way. They make our code more literate and more understandable.

Web Beans stereotypes take this idea a step further. A stereotype models a common role in your application architecture. It encapsulates various properties of the role, including scope, interceptor bindings, deployment type, etc, into a single reusable package.

Even Web Beans XML metadata is strongly typed! There's no compiler for XML, so Web Beans takes advantage of XML schemas to validate the Java types and attributes that appear in XML. This approach turns out to make the XML more literate, just like annotations made our Java code more literate.

We're now ready to meet some more advanced features of Web Beans. Bear in mind that these features exist to make our code both easier to validate and more understandable. Most of the time you don't ever really need to use these features, but if you use them wisely, you'll come to appreciate their power.

According to the Web Beans specification:

In many systems, use of architectural patterns produces a set of recurring Web Bean roles. A stereotype allows a framework developer to identify such a role and declare some common metadata for Web Beans with that role in a central place.

A stereotype encapsulates any combination of:

  • a default deployment type,

  • a default scope type,

  • a restriction upon the Web Bean scope,

  • a requirement that the Web Bean implement or extend a certain type, and

  • a set of interceptor binding annotations.

A stereotype may also specify that all Web Beans with the stereotype have defaulted Web Bean names.

A Web Bean may declare zero, one or multiple stereotypes.

A stereotype is a Java annotation type. This stereotype identifies action classes in some MVC framework:

@Retention(RUNTIME)

@Target(TYPE)
@Stereotype
public @interface Action {}

We use the stereotype by applying the annotation to a Web Bean.

@Action 

public class LoginAction { ... }

We've already seen how the Web Beans dependency injection model lets us override the implementation of an API at deployment time. For example, the following enterprise Web Bean provides an implementation of the API PaymentProcessor in production:

@CreditCard @Stateless

public class CreditCardPaymentProcessor 
        implements PaymentProcessor {
    ...
}

But in our staging environment, we override that implementation of PaymentProcessor with a different Web Bean:

@CreditCard @Stateless @Staging

public class StagingCreditCardPaymentProcessor 
        implements PaymentProcessor {
    ...
}

What we've tried to do with StagingCreditCardPaymentProcessor is to completely replace AsyncPaymentProcessor in a particular deployment of the system. In that deployment, the deployment type @Staging would have a higher priority than the default deployment type @Production, and therefore clients with the following injection point:

@CreditCard PaymentProcessor ccpp

Would receive an instance of StagingCreditCardPaymentProcessor.

Unfortunately, there are several traps we can easily fall into:

  • the higher-priority Web Bean may not implement all the API types of the Web Bean that it attempts to override,

  • the higher-priority Web Bean may not declare all the binding types of the Web Bean that it attempts to override,

  • the higher-priority Web Bean might not have the same name as the Web Bean that it attempts to override, or

  • the Web Bean that it attempts to override might declare a producer method, disposal method or observer method.

In each of these cases, the Web Bean that we tried to override could still be called at runtime. Therefore, overriding is somewhat prone to developer error.

Web Beans provides a special feature, called specialization, that helps the developer avoid these traps. Specialization looks a little esoteric at first, but it's easy to use in practice, and you'll really appreciate the extra security it provides.

So far, we've seen plenty of examples of Web Beans declared using annotations. However, there are a couple of occasions when we can't use annotations to define the Web Bean:

  • when the implementation class comes from some preexisting library, or

  • when there should be multiple Web Beans with the same implementation class.

In either of these cases, Web Beans gives us two options:

  • write a producer method, or

  • declare the Web Bean using XML.

Many frameworks use XML to provide metadata relating to Java classes. However, Web Beans uses a very different approach to specifying the names of Java classes, fields or methods to most other frameworks. Instead of writing class and member names as the string values of XML elements and attributes, Web Beans lets you use the class or member name as the name of the XML element.

The advantage of this approach is that you can write an XML schema that prevents spelling errors in your XML document. It's even possible for a tool to generate the XML schema automatically from the compiled Java code. Or, an integrated development environment could perform the same validation without the need for the explicit intermediate generation step.

The third theme of Web Beans is integration. Web Beans was designed to work in concert with other technologies, helping the application developer fit the other technologies together. Web Beans is an open technology. It forms a part of the Java EE ecosystem, and is itself the foundation for a new ecosystem of portable extensions and integration with existing frameworks and technologies.

We've already seen how Web Beans helps integrate EJB and JSF, allowing EJBs to be bound directly to JSF pages. That's just the beginning. Web Beans offers the same potential to diverse other technologies, such as Business Process Management engines, other Web Frameworks, and third-party component models. The Java EE platform will never be able to standardize all the interesting technologies that are used in the world of Java application development, but Web Beans makes it easier to use the technologies which are not yet part of the platform seamlessly within the Java EE environment.

We're about to see how to take full advantage of the Java EE platform in an application that uses Web Beans. We'll also briefly meet a set of SPIs that are provided to support portable extensions to Web Beans. You might not ever need to use these SPIs directly, but it's nice to know they are there if you need them. Most importantly, you'll take advantage of them indirectly, every time you use a third-party extension.

Web Beans is fully integrated into the Java EE environment. Web Beans have access to Java EE resources and JPA persistence contexts. They may be used in Unified EL expressions in JSF and JSP pages. They may even be injected into some objects, such as Servlets and Message-Driven Beans, which are not Web Beans.

Sending messages using JMS can be quite complex, because of the number of different objects you need to deal with. For queues we have Queue, QueueConnectionFactory, QueueConnection, QueueSession and QueueSender. For topics we have Topic, TopicConnectionFactory, TopicConnection, TopicSession and TopicPublisher. Each of these objects has its own lifecycle and threading model that we need to worry about.

Web Beans takes care of all this for us. All we need to do is declare the queue or topic in web-beans.xml, specifying an associated binding type and connection factory.


<Queue>
    <destination>java:comp/env/jms/OrderQueue</destination>
    <connectionFactory>java:comp/env/jms/QueueConnectionFactory</connectionFactory>
    <myapp:OrderProcessor/>    
</Queue>

<Topic>
    <destination>java:comp/env/jms/StockPrices</destination>
    <connectionFactory>java:comp/env/jms/TopicConnectionFactory</connectionFactory>
    <myapp:StockPrices/>    
</Topic>

Now we can just inject the Queue, QueueConnection, QueueSession or QueueSender for a queue, or the Topic, TopicConnection, TopicSession or TopicPublisher for a topic.

@OrderProcessor QueueSender orderSender;

@OrderProcessor QueueSession orderSession;
public void sendMessage() {
    MapMessage msg = orderSession.createMapMessage();
    ...
    orderSender.send(msg);
}
@StockPrices TopicPublisher pricePublisher;

@StockPrices TopicSession priceSession;
public void sendMessage(String price) {
    pricePublisher.send( priceSession.createTextMessage(price) );
}

The lifecycle of the injected JMS objects is completely controlled by the Web Bean manager.

Web Beans is intended to be a platform for frameworks, extensions and integration with other technologies. Therefore, Web Beans exposes a set of SPIs for the use of developers of portable extensions to Web Beans. For example, the following kinds of extensions were envisaged by the designers of Web Beans:

  • integration with Business Process Management engines,

  • integration with third-party frameworks such as Spring, Seam, GWT or Wicket, and

  • new technology based upon the Web Beans programming model.

The nerve center for extending Web Beans is the Manager object.

The Manager interface lets us register and obtain Web Beans, interceptors, decorators, observers and contexts programatically.

public interface Manager

{
   public <T> Set<Bean<T>> resolveByType(Class<T> type, Annotation... bindings);
   public <T> Set<Bean<T>> resolveByType(TypeLiteral<T> apiType,
         Annotation... bindings);
   public <T> T getInstanceByType(Class<T> type, Annotation... bindings);
   public <T> T getInstanceByType(TypeLiteral<T> type,
         Annotation... bindings);
   public Set<Bean<?>> resolveByName(String name);
   public Object getInstanceByName(String name);
   public <T> T getInstance(Bean<T> bean);
   public void fireEvent(Object event, Annotation... bindings);
   public Context getContext(Class<? extends Annotation> scopeType);
   public Manager addContext(Context context);
   public Manager addBean(Bean<?> bean);
   public Manager addInterceptor(Interceptor interceptor);
   public Manager addDecorator(Decorator decorator);
   public <T> Manager addObserver(Observer<T> observer, Class<T> eventType,
         Annotation... bindings);
   public <T> Manager addObserver(Observer<T> observer, TypeLiteral<T> eventType,
         Annotation... bindings);
   public <T> Manager removeObserver(Observer<T> observer, Class<T> eventType,
         Annotation... bindings);
   public <T> Manager removeObserver(Observer<T> observer,
         TypeLiteral<T> eventType, Annotation... bindings);
   public <T> Set<Observer<T>> resolveObservers(T event, Annotation... bindings);
   public List<Interceptor> resolveInterceptors(InterceptionType type,
         Annotation... interceptorBindings);
   public List<Decorator> resolveDecorators(Set<Class<?>> types,
         Annotation... bindings);
}

We can obtain an instance of Manager via injection:

@Current Manager manager

Web Beans is the reference implementation of JSR-299, and is used by JBoss AS and Glassfish to provide JSR-299 services for Java Enterprise Edition applications. Web Beans also goes beyond the environments and APIs defined by the JSR-299 specification and provides support for a number of other environments (such as a servlet container such as Tomcat, or Java SE) and additional APIs and modules (such as logging, XSD generation for the JSR-299 XML deployment descriptors).

If you want to get started quickly using Web Beans with JBoss AS or Tomcat and experiment with one of the examples, take a look at Chapter 3, Getting started with Web Beans, the Reference Implementation of JSR-299. Otherwise read on for a exhaustive discussion of using Web Beans in all the environments and application servers it supports, as well the Web Beans extensions.

Web Beans can be used in any Servlet container such as Tomcat 6.0 or Jetty 6.1.

Web Beans should be used as a web application library in a servlet container. You should place webbeans-servlet.jar in WEB-INF/lib. webbeans-serv;et.jar is an "uber-jar" provided for your convenience. Instead, you could use its component jars:

You also need to explicitly specify the servlet listener (used to boot Web Beans, and control its interaction with requests) in web.xml:

<listener>
   <listener-class>org.jboss.webbeans.environment.servlet.Listener</listener-class>
</listener>

Apart from improved integration of the Enterprise Java stack, Web Beans also provides a state of the art typesafe, stateful dependency injection framework. This is useful in a wide range of application types, enterprise or otherwise. To facilitate this, Web Beans provides a simple means for executing in the Java Standard Edition environment independently of any Enterprise Edition features.

When executing in the SE environment the following features of Web Beans are available:

To make life easy for developers Web Beans provides a special module with a main method which will boot the Web Beans manager, automatically registering all simple Web Beans found on the classpath. This eliminates the need for application developers to write any bootstrapping code. The entry point for a Web Beans SE applications is a simple Web Bean which observes the standard @Deployed Manager event. The command line paramters can be injected using either of the following:

@Parameters List<String> params;

@Parameters String[] paramsArray; // useful for compatability with existing classes

Here's an example of a simple Web Beans SE application:

@ApplicationScoped

public class HelloWorld
{
    @Parameters List<String> parameters;
    public void printHello( @Observes @Deployed Manager manager )
    {
        System.out.println( "Hello " + parameters.get(0) );
    }
}

Web Beans SE applications are started by running the following main method.

java org.jboss.webbeans.environments.se.StartMain <args>

If you need to do any custom initialization of the Web Beans manager, for example registering custom contexts or initializing resources for your beans you can do so in response to the @Initialized Manager event. The following example registers a custom context:

public class PerformSetup

{
    public void setup( @Observes @Initialized Manager manager )
    {
        manager.addContext( ThreadContext.INSTANCE );
    }
}

Important

These modules are usable on any JSR-299 implementation, not just Web Beans!

Adding logging to your application is now even easier with simple injection of a logger object into any JSR-299 bean. Simply annotate a org.jboss.webbeans.log.Log type member with @Logger and an appropriate logger object will be injected into any instance of the bean.

public class Checkout {

    import org.jboss.webbeans.annotation.Logger;
    import org.jboss.webbeans.log.Log;
    
    @Logger
    private Log log;
    void invoiceItems() {
        ShoppingCart cart;
        . . .
        log.debug("Items invoiced for {0}", cart);
    }
    
}

The example shows how objects can be interpolated into a message. This interpolation is done using java.text.MessageFormat, so see the JavaDoc for that class for more details. In this case, the ShoppingCart should have implemented the toString() method to produce a human readable value that is meaningful in messages. Normally, this call would have involved evaluating cart.toString() with String concatenation to produce a single String argument. Thus it was necessary to surround the call with an if-statement using the condition log.isDebugEnabled() to avoid the expensive String concatenation if the message was not actually going to be used. However, when using @Logger injected logging, the conditional test can be left out since the object arguments are not evaluated unless the message is going to be logged.

The conversation scope can be used in Web Beans with the Apache Wicket web framework, through the webbeans-wicket module. This module takes care of:

Currently Web Beans only runs in JBoss AS 5; integrating the RI into other EE environments (for example another application server like Glassfish), into a servlet container (like Tomcat), or with an Embedded EJB3.1 implementation is fairly easy. In this Appendix we will briefly discuss the steps needed.

The Web Beans SPI is located in the webbeans-spi module, and packaged as webbeans-spi.jar. Some SPIs are optional, if you need to override the default behavior, others are required.

All interfaces in the SPI support the decorator pattern and provide a Forwarding class located in the helpers sub package. Additional, commonly used, utility classes, and standard implementations are also located in the helpers sub package.

Web Beans also delegates EJB3 bean discovery to the container so that it doesn't have to scan for EJB3 annotations or parse ejb-jar.xml. For each EJB in the application an EJBDescriptor should be discovered:

public interface EjbDescriptor<T>

{
   
   /**
    * Gets the EJB type
    * 
    * @return The EJB Bean class
    */
   public Class<T> getType();
   /**
    * Gets the local business interfaces of the EJB
    * 
    * @return An iterator over the local business interfaces
    */
   public Iterable<BusinessInterfaceDescriptor<?>> getLocalBusinessInterfaces();
   
   /**
    * Gets the remote business interfaces of the EJB
    * 
    * @return An iterator over the remote business interfaces
    */
   public Iterable<BusinessInterfaceDescriptor<?>> getRemoteBusinessInterfaces();
   
   /**
    * Get the remove methods of the EJB
    * 
    * @return An iterator over the remove methods
    */
   public Iterable<Method> getRemoveMethods();
   /**
    * Indicates if the bean is stateless
    * 
    * @return True if stateless, false otherwise
    */
   public boolean isStateless();
   /**
    * Indicates if the bean is a EJB 3.1 Singleton
    * 
    * @return True if the bean is a singleton, false otherwise
    */
   public boolean isSingleton();
   /**
    * Indicates if the EJB is stateful
    * 
    * @return True if the bean is stateful, false otherwise
    */
   public boolean isStateful();
   /**
    * Indicates if the EJB is and MDB
    * 
    * @return True if the bean is an MDB, false otherwise
    */
   public boolean isMessageDriven();
   /**
    * Gets the EJB name
    * 
    * @return The name
    */
   public String getEjbName();

The EjbDescriptor is fairly self-explanatory, and should return the relevant metadata as defined in the EJB specification. In addition to these two interfaces, there is BusinessInterfaceDescriptor which represents a local business interface (encapsulating the interface class and jndi name used to look up an instance of the EJB).

The resolution of @EJB (for injection into simple beans), the resolution of local EJBs (for backing session beans) and remote EJBs (for injection as a Java EE resource) is delegated to the container. You must provide an implementation of org.jboss.webbeans.ejb.spi.EjbServices which provides these operations. For resolving the @EJB injection point, Web Beans will provide the InjectionPoint; for resolving local EJBs, the EjbDescriptor will be provided, and for remote EJBs the jndiName, mappedName, or ejbLink will be provided.

When resolving local EJBs (used to back session beans) a wrapper (SessionObjectReference) around the EJB reference is returned. This wrapper allows Web Beans to request a reference that implements the given business interface, and, in the case of SFSBs, request the removal of the EJB from the container.

Web Beans must delegate JTA activities to the container. The SPI provides a couple hooks to easily achieve this with the TransactionServices interface.

public interface TransactionServices

{
   /**
    * Possible status conditions for a transaction. This can be used by SPI
    * providers to keep track for which status an observer is used.
    */
   public static enum Status
   {
      ALL, SUCCESS, FAILURE
   }
   /**
    * Registers a synchronization object with the currently executing
    * transaction.
    * 
    * @see javax.transaction.Synchronization
    * @param synchronizedObserver
    */
   public void registerSynchronization(Synchronization synchronizedObserver);
   /**
    * Queries the status of the current execution to see if a transaction is
    * currently active.
    * 
    * @return true if a transaction is active
    */
   public boolean isTransactionActive();
}

The enumeration Status is a convenience for implementors to be able to keep track of whether a synchronization is supposed to notify an observer only when the transaction is successful, or after a failure, or regardless of the status of the transaction.

Any javax.transaction.Synchronization implementation may be passed to the registerSynchronization() method and the SPI implementation should immediately register the synchronization with the JTA transaction manager used for the EJBs.

To make it easier to determine whether or not a transaction is currently active for the requesting thread, the isTransactionActive() method can be used. The SPI implementation should query the same JTA transaction manager used for the EJBs.

The org.jboss.webbeans.bootstrap.api.Bootstrap interface defines the bootstrap for Web Beans. To boot Web Beans, you must obtain an instance of org.jboss.webbeans.bootstrap.WebBeansBootstrap (which implements Boostrap), tell it about the SPIs in use, and then request the container start.

The bootstrap is split into phases, bootstrap initialization and boot and shutdown. Initialization will create a manager, and add the standard (specification defined) contexts. Bootstrap will discover EJBs, classes and XML; add beans defined using annotations; add beans defined using XML; and validate all beans.

The bootstrap supports multiple environments. An environment is defined by an implementation of the Environment interface. A number of standard envrionments are built in as the enumeration Environments. Different environments require different services to be present (for example servlet doesn't require transaction, EJB or JPA services). By default an EE environment is assumed, but you can adjust the environment by calling bootstrap.setEnvironment().

Web Beans uses a generic-typed service registry to allow services to be registered. All services implement the Service interface. The service registry allows services to be added and retrieved.

To initialize the bootstrap you call Bootstrap.initialize(). Before calling initialize(), you must register any services required by your environment. You can do this by calling bootstrap.getServices().add(JpaServices.class, new MyJpaServices()). You must also provide the application context bean store.

Having called initialize(), the Manager can be obtained by calling Bootstrap.getManager().

To boot the container you call Bootstrap.boot().

To shutdown the container you call Bootstrap.shutdown() or webBeansManager.shutdown(). This allows the container to perform any cleanup operations needed.

There are a number of requirements that the Web Beans RI places on the container for correct functioning that fall outside implementation of APIs

Classloader isolation

If you are integrating the Web Beans RI into an environment that supports deployment of multiple applications, you must enable, automatically, or through user configuation, classloader isolation for each Web Beans application.

Servlet

If you are integrating the Web Beans into a Servlet environment you must register org.jboss.webbeans.servlet.WebBeansListener as a Servlet listener, either automatically, or through user configuration, for each Web Beans application which uses Servlet.

JSF

If you are integrating the Web Beans into a JSF environment you must register org.jboss.webbeans.jsf.WebBeansPhaseListener as a phase listener, and org.jboss.webbeans.el.WebBeansELREsolver as an EL resolver, either automatically, or through user configuration, for each Web Beans application which uses JSF.

If you are integrating the Web Beans into a JSF environment you must register org.jboss.webbeans.servlet.ConversationPropagationFilter as a Servlet listener, either automatically, or through user configuration, for each Web Beans application which uses JSF. This filter can be registered for all Servlet deployment safely.

Session Bean Interceptor

If you are integrating the Web Beans into an EJB environment you must register org.jboss.webbeans.ejb.SessionBeanInterceptor as a EJB interceptor for all EJBs in the application, either automatically, or through user configuration, for each Web Beans application which uses enterprise beans.

The webbeans-core.jar

If you are integrating the Web Beans into an environment that supports deployment of applications, you must insert the webbeans-core.jar into the applications isolated classloader. It cannot be loaded from a shared classloader.

Binding the manager in JNDI

You should bind a Reference to the Manager ObjectFactory into JNDI at java:app/Manager. The type should be javax.inject.manager.Manager and the factory class is org.jboss.webbeans.resources.ManagerObjectFactory