SeamFramework.orgCommunity Documentation

Chapter 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

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.