Help

Tags
Inactive Bloggers

/This is the fifth installment of a series of articles describing the current status of the Web Beans specification. Please read the first, second, third and fourth installments first./

One of the themes of Web Beans is loose coupling. We've already seen three means of achieving loose coupling:

  • component types enable /deployment time/ polymorphism
  • producer methods enable /runtime/ polymorphism
  • contextual lifecycle management decouples component lifecycles

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

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

  • interceptors decouple technical concerns from business logic
  • event notifications decouple event producers from event consumers

Let's explore these features.

Interceptors

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 components

Suppose we want to declare that some of our components are transactional. The first thing we need is an /interceptor binding annotation/ to specify exactly which components we're interested in:

@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {}

Now we can easily specify that our ShoppingCart is a transactional object:

@Transactional @Component
public class ShoppingCart { ... }

Or, if we prefer, we can specify that just one method is transactional:

@Component
public class ShoppingCart {
    @Transactional public void checkout() { ... }
}

That's great, but somewhere along the line we're going to have to actually implement the interceptor that provides this transaction management aspect. All we need to do is create a standard EJB interceptor, and annotate it @Interceptor and @Transactional.

@Transactional @Interceptor
public class TransactionInterceptor {
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

Finally, we need to /enable/ our interceptor in web-beans.xml.

<interceptors>
    <interceptor>to.relation.in.TransactionInterceptor</interceptor>
</interceptors>

Whoah! Why the angle bracket stew?

Well, the XML declaration solves two problems:

  • it enables us to specify a total ordering for all the interceptors in our system, ensuring deterministic behavior
  • it lets us enable or disable interceptor classes at deployment time

For example, we could specify that our security interceptor runs before our TransactionInterceptor. And we can turn them both off in our test environment.

Interceptor bindings with members

Suppose we want to add some extra information to our @Transactional annotation:

@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Transactional {
    boolean requiresNew() default false;
}

Web Beans will use the value of requiresNew to choose between two different interceptors, TransactionInterceptor and RequiresNewTransactionInterceptor.

@Transactional(requiresNew=true) @Interceptor
public class RequiresNewTransactionInterceptor {
    @AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }
}

Now we can use RequiresNewTransactionInterceptor like this:

@Transactional(requiresNew=true) @Component
public class ShoppingCart { ... }

But what if we only have one interceptor and we want the container to ignore the value of requiresNew when binding interceptors? We can use the @NonBinding annotation:

@InterceptorBindingType
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Secure {
    @NonBinding String[] rolesAllowed() default {};
}

Multiple interceptor binding annotations

Usually we use combinations of interceptor bindings types to bind multiple interceptors to a component. For example, the following declaration would be used to bind TransactionInterceptor and SecurityInterceptor to the same component:

@Secure(rolesAllowed="admin") @Transactional @Component
public class ShoppingCart { ... }

However, in very complex cases, an interceptor itself may specify some combination of interceptor binding types:

@Transactional @Secure @Interceptor
public class TransactionalSecureInterceptor { ... }

Then this interceptor could be bound to the checkout() method using any one of the following combinations:

@Component
public class ShoppingCart {
    @Transactional @Secure public void checkout() { ... }
}
@Secure @Component
public class ShoppingCart {
    @Transactional public void checkout() { ... }
}
@Transactionl @Component
public class ShoppingCart {
    @Secure public void checkout() { ... }
}
@Transactional @Secure @Component
public class ShoppingCart {
    public void checkout() { ... }
}

Binding an interceptor to /everything/

What if we want an interceptor for /every/ component? Easy, just declare the interceptor without any interceptor binding type!

@Interceptor
public class UberInterceptor { ... }

Interceptor binding type inheritance

One of the awful, embarrassing, mistakes of the Java language is the lack of support for annotation inheritance. Really, annotations should have reuse built in, to allow this kind of thing to work:

public @interface Action extends Transactional, Secure { ... }

Well, fortunately, Web Beans works around this missing feature of Java:

@Transactional @Secure
@InterceptorBindingType
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action { ... }

And now any component annotated @Action will be bound to both TransactionInterceptor and SecurityInterceptor. (And even TransactionalSecureInterceptor, if it exists.)

Events

/Please note that the following section describes functionality that is still under active discussion in the Web Beans expert group!/

The Web Beans event notification facility allows components to interact in a totally decoupled manner. Event /producers/ raise events that are then delivered to event /observers/. This basic schema might sound similar to the 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
  • observers can be notified immediately, or can specify that delivery of the event should be delayed until the end of the current transaction

Event observers

An /observer method/ is a method of any Web Bean with a parameter annotated @Observes.

public void onAnyDocumentEvent(@Observes Document document) { ... }

The annotated parameter is called the /event parameter/. Observer methods may also specify selectors, which are called /event binding types/. An event binding type is just an annotation:

@EventBindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Updated { ... }

We specify the selector by annotating the event parameter:

public void afterDocumentUpdate(@Observes @Updated Document document) { ... }

The observer method may have additional parameters, which are injected, according to the usual Web Beans semantics:

public void afterDocumentUpdate(@Observes @Updated Document document, @Current User user) { ... }

Event producers

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

@In @Notifier Event<Document> documentEvent;

The @Notifier annotation implicitly defines a Web Beans component with scope @Dependent and component type @Standard.

A producer raises events by calling the one and only method of the Event interface:

documentEvent.raise(document);

To specify a selector, the producer may either pass an instance of the event binding type to the raise():

documentEvent.raise(document, new Updated(){});

Of may specify the selector at the injection point:

@In @Notifier @Updated Event<Document> documentUpdatedEvent;

Event bindings with members

An event binding type may have annotation members:

@EventBindingType
@Target({PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Role {
    RoleType value();
}

The member value is used to narrow the messages delivered to the observer:

public void adminLoggedIn(@Observes @Role(ADMIN) LoggedIn event) { ... }

And can be specified by the event producer either statically:

@In @Notifier @Role(ADMIN) Event<LoggedIn> LoggedInEvent;

Or dynamically:

documentEvent.raise( document, new Role() { public void value() { return user.getRole(); } } );

Multiple event bindings

Event binding types can be combined, for example:

@In @Notifier @Blog Event<Document> blogEvent;
...
if (document.isBlog()) blogEvent.raise(document, new Updated(){});

In this case, any of the following observer methods would be notified:

public void afterBlogUpdate(@Observes @Updated @Blog Document document) { ... }
public void afterDocumentUpdate(@Observes @Updated Document document) { ... }
public void onAnyBlogEvent(@Observes @Bog Document document) { ... }
public void onAnyDocumentEvent(@Observes Document document) { ... }

Transactional observers

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:

  • @AfterTransactionSuccess observers are called during the after completion phase of the transaction, but only if the transaction completes successfully
  • @AfterTransactionCompletion observers are called during the after completion phase of the transaction
  • @BeforeTransactionCompletion observers are called during the before completion phase of the transaction

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

/This is the fourth installment of a series of articles describing the current status of the Web Beans specification. Please read the first, second and third installments first./

So far, we've seen a few examples of /scope type annotations/. The scope of a component determines the lifecycle of the component instances, and makes a particular instance visible to all components executing in a particular context.

For example, if we have a session scoped component, CurrentUser, all components 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.

Scope types

Web Beans features an /extensible context model/. It is possible to define new scopes by creating a new scope type annotation:

@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ScopeType
public @interface ClusterScoped {}

Of course, that's the easy part of the job. For this scope type to be useful, we will also need to define a Context object that implements the scope! Implementing a Context is usually a very technical task, intended for framework development only.

We can apply a scope type annotation to a Web Bean implementation class to specify the scope of the component:

@ClusterScoped @Component
public class SecondLevelCache { ... }

We can even use the scope type to obtain an instance of the Context object for the scope:

Component<SecondLevelCache> cacheComponent = container.resolveByType(SecondLevelCache.class);
SecondLevelCache cache = container.getContext(ClusterScoped.class).get(cacheComponent);

Built-in scopes

Web Beans defines four built-in scopes:

  • @RequestScoped
  • @SessionScoped
  • @ApplicationScoped
  • @ConversationScoped

For a web application that uses Web Beans:

  1. any servlet has access to active request, session and application contexts
  2. any JSF request has access to an active conversation context

If the application tries to use a component with a scope that does not have an active context, a ContextNotActive exception is thrown by the Web Beans container at runtime.

The dependent psuedo-scope

In addition, there is the notion of the /dependent psuedo-scope/. We use the term psuedo-scope because there is no Context for this special scope.

A Web Bean may be declared to be a @Dependent component:

@Dependent @Component
public class Calculator { ... }

If this case, a new instance of the component is created each time the Web Beans container injects it. This means that any instance of a dependent component is bound to the object into which it was injected. Different clients always see different instances of a dependent component, no matter what context they execute in.

A open issue that currently exists in the Web Beans specification is the question of the default scope for a Web Bean component that does not explicitly declare a scope type. We've narrowed the options down to @RequestScoped and @Dependent, each of which has advantages and disadvantages.

Implicit dependent components

The built-in @New binding annotation allows /implicit/ definition of a dependent component at an injection point. Suppose we declare the following injected attribute:

@In @New Calculator calculator

Then a component with component type @Component, scope @Dependent, binding annotation @New, API type Calculator and implementation class Calculator is implicitly defined.

This is true even if Calculator is /already/ declared as a Web Beans component, for example:

@ConversationScoped @Component
public class Calculator { ... }

So the following injected attributes each get a different instance of Calculator:

@Component 
public class PaymentCalc {

    @In Calculator calculator;
    @In @New Calculator newCalculator;

}

The calculator field has a conversation-scoped instance of Calculator injected. The newCalculator field has a new instance of Calculator injected, with a lifecycle that is bound to the owning PaymentCalc.

This feature is particularly useful with resolver methods.

Resolver methods

According to the spec:

A Web Beans resolver 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 components,
  • 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, resolver methods let us:

  • expose a JPA entity as a Web Bean component
  • expose a JDK class as a Web Bean component
  • define multiple Web Bean components, with different scopes or initialization, for the same implementation class
  • vary a Web Bean component implementation class at runtime

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

@SessionScoped @Component
public class Preferences {
    
    private PaymentStrategyType paymentStrategy;
    
    ...
    
    @Resolves @Preferred @ApplicationScoped
    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 this injection point:

@In @Preferred PaymentStrategy paymentStrat;

When the container injects this field, the resolver method will be called and the returned PaymentStrategy will be injected into the field and bound to the application context. The resolver method won't be called again in the same application context. On the other hand, if we were to remove the @ApplicationScoped annotation:

@Resolves @Preferred
public PaymentStrategy getPaymentStrategy() {
    ...
}

Then the resolver method defaults to dependent scope, and it will be called /every time/ the field is injected!

Injection into resolver methods

There's one problem with this code. If CreditCardPaymentStrategy is a Web Bean component, it should be created by the Web Beans container, not by calling new. We can solve this problem by using injection into the resolver method:

@Resolves @Preferred @ApplicationScoped
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 component? Then the resolver method has the effect of promoting the current request scoped instance into application scope. This is almost certainly a bug. We can fix the bug using the special @New binding annotation described above:

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

Then a new /dependent/ instance of CreditCardPaymentStrategy will be created, passed to the resolver method, returned by the resolver and finally bound to the application context.

/This is the third installment of a series of articles describing the current status of the Web Beans specification. You can find the first installment here and the second installment here./

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

  • when the implementation class comes from some pre-existing library
  • when there should be multiple components with the same implementation class

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

  • write a /resolver method/
  • declare the component using XML

In a future installment we'll talk more about all the crazy kinds of things we can do with resolver methods. First, let's just prove that Web Beans is not entirely annotation-centric.

We can declare a component in web-beans.xml:

<component>
    <class>java.util.Date</class>
</component>

Then an instance of Date could be injected by another component:

@In Date date;

By default, any component declared in XML has the component type @Component. We can use a custom component type:

<component>
    <class>java.util.Date</class>
    <type>org.jboss.test.Mock</type>
</component>

We can override the default component name:

<component>
    <class>java.util.Date</class>
    <name>now</name>
</component>

Or we can specify a scope for the component:

<component>
    <class>java.util.Date</class>
    <scope>javax.webbeans.SessionScoped</scope>
</component>

We can even specify binding annotations using XML, to distinguish between multiple components with the same implementation class:

<component>
    <class>java.util.Date</class>
    <name>now</name>
    <binding>org.jboss.eg.Now</binding>
</component>

<component>
    <class>java.util.Date</class>
    <name>logInTime</name>
    <scope>javax.webbeans.SessionScoped</scope>
    <binding>org.jboss.eg.LogInTime</binding>
</component>

<component>
    <class>java.util.Date</class>
    <name>startupTime</name>
    <scope>javax.webbeans.ApplicationScoped</scope>
    <binding>org.jboss.eg.StartupTime</binding>
</component>

Where @Now, @LogIn and @Startup are binding annotations used at the injection points:

@In @Now Date currentTime;
@In @LogInTime Date loginTime
@In @StartupTime Date startupTime

As usual, a component may support multiple binding annotations:

<component>
    <class>org.jboss.eg.AsynchronousChequePaymentProcessor</class>
    <binding>org.jboss.eg.PayByCheque</binding>
    <binding>org.jboss.eg.Asynchronous</binding>
</component>

Eventually, Web Beans will also support XML-based configuration of component properties, using literal or EL values, something like this:

<component>
    <class>org.jboss.framework.Captcha</class>
    <property name="strategy">math2digit</property>
    <property name="language">#{user.language}</property>
</component>

However, we've not yet worked out all the details of this. In particular, I would love to support a namespaced approach to component configuration, as seen in Seam or Spring 2.0.

/This is the second installment of a series of articles describing the current status of the Web Beans specification. You can find the first installment here./

Web Beans supports three primary mechanisms for dependency injection:

Direct field injection:

@Component
public class Checkout {

    @In ShoppingCart cart;
    
}

Method injection:

@Component
public class Checkout {
        
    private ShoppingCart cart;

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

And constructor injection:

@Component
public class Checkout {
        
    private final ShoppingCart cart;

    public Checkout(ShoppingCart cart) {
        this.cart = cart;
    }

}

In addition, resolver methods support parameter injection:

@Resolves Checkout createCheckout(ShoppingCart cart) {
    return new Checkout(cart);
}

Dependency injection always occurs when the component instance is first instantiated.

The Web Beans specification defines a procedure, called the /typesafe resolution algorithm/, that the Web Beans container follows when identifying the component 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 container will inform the user immediately if a component's dependencies cannot be satisfied.

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

  • allow the client to select which implementation it requires using /binding annotations/, or
  • allow one implementation of an API to override another implementation of the same API at deployment time, without changes to the client, using /component type precedence/.

Let's explore how the Web Beans container determines a component to be injected.

Binding annotations

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

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

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

Where @PayByCheque and @PayByCreditCard are binding annotations:

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

A client component developer uses the binding annotation to specify exactly which component should be injected:

@In @PayByCheque PaymentProcessor chequePaymentProcessor;
@In @PayByCreditCard PaymentProcessor creditCardPaymentProcessor;

Equivalently, using constructor injection:

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

Binding annotations with members

Binding annotations may have members:

@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface PayBy {
    PaymentType value();
}

In which case, the member value is significant:

@In @PayBy(CHEQUE) PaymentProcessor chequePaymentProcessor;
@In @PayBy(CREDIT_CARD) PaymentProcessor creditCardPaymentProcessor;

Combinations of binding annnotations

An injection point may even specify multiple binding annotations:

@In @Asynchronous @PayByCheque paymentProcessor

In this case, only a component which supports /both/ binding annotation would be eligable for injection.

Binding annotations and resolver methods

Of course, even resolver methods may specify binding annotations:

@Resolves 
@Asynchronous @PayByCheque 
PaymentProcessorService createAsyncPaymentProcessor(@PayByCheque PaymentProcessor processor) {
    return new AsynchronousPaymentProcessorService(processor);
}

This method would be called to create an instance for injection to the following injection point:

@In @Asynchronous @PayByCheque PaymentProcessorService service;

Component types

All Web Bean components have a /component type/. Each component type identifies a set of components that should be conditionally installed in some deployments of the system.

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

@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ComponentType
public @interface Mock {}

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

@Component
public class PaymentProcessor {
        
    public void process(Payment p) {
        ...
    }
    
}

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

@Mock 
public class MockPaymentProcessor extends PaymentProcessor {

    @Override
    public void process(Payment p) {
        p.setSuccessful(true);
    }

}

Installing component types

Web Beans defines two built-in component types: @Component and @Standard. By default, only components with the built-in component types are installed when the system is deployed. We can identify additional component types to be installed in a particular deployment by listing them in web-beans.xml.

Going back to our example, when we deploy our integration tests, we want all our @Mock objects to be installed:

<web-beans>
    <component-types>
        <component-type>javax.webbeans.Standard</component-type>
        <component-type>javax.webbeans.Component</component-type>
        <component-type>org.jboss.test.Mock</component-type>
    </component-types>
</web-beans>

Now the Web Beans container will identify and install all components annotated @Component, @Standard or @Mock at deployment time.

(Note that a component with no component type annotation will never be discovered by the Web Beans container; the container searches for classes with component type annotations when scanning the classpath to discover components.)

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

Component type precedence

If you've been paying attention, you're probably wondering how the container decides which implementation - PaymentProcessor or MockPaymentProcessor - to choose. Consider what happens when the container encounters this injection point:

@In PaymentProcessor pp;

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

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

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

Example component types

Component types are useful for all kinds of things, some more examples:

  • @Mock and @Staging component types for testing
  • @AustralianTaxLaw for site-specific components
  • @SeamFramework, @Guice for third-party frameworks which build on Web Beans
  • @Standard for standard components defined by the Web Beans specification

I'm sure you can think of more applications...

Two more rules to remember?

As we've seen, the typesafe resolution algorith considers:

  1. API type
  2. binding annotations
  3. component type precedence

when resolving a component to be injected. If these rules fail to produce a unique component (if there are multiple components which all have the same high precedence, implement the required API type and support the required binding annotations), an exception will be thrown by the container at system initialization time.

The Web Beans group has discussed the possibility of introducing two additional rules to be used only when the rules above fail to narrow the list of components to a unique component. On balance, I'm in favor of these rules, since I think they're useful. However, the group as a whole is concerned that the additional complexity is confusing to developers. Therefore, we're seeking feedback from the community on the following ideas.

/Note:/ If you're not used to thinking in terms of binding annotations and component precendence, you're probably thinking that component resolution is already complex enough! But I'm confident that once you get used to it, the resolution algorithm is extremely robust and will grow to become totally intuitive.

Rule 1: The /least-derived implementation/ rule

This proposed rule states that if the algorithm above fails to result in a unique component, and if there is a /least-derived/ component in the set of candidates - one candidate that the other candidates all (directly or indirectly) extend, then the least-derived component will be chosen.

This rule is designed to ensure that it is easy to introduce new components into the system using implementation inheritance from pre-existing components, without breaking or changing the behavior of pre-existing clients.

For example, if I have this pre-existing component:

@Component @PayByCheque
ChequePaymentProcessor implements PaymentProcessor { ... }

and I introduce a new component that extends this one:

@Component @PayByCheque
AsynchronousChequePaymentProcessor 
    extends ChequePaymentProcessor 
    implements AsynchronousPaymentProcessor { ... }

Then the following injection point would continue to resolve to the base ChequePaymentProcessor component:

@In @PayByCheque PaymentProcessor processor;

While this new injection point would of course receive an instance of AsynchronousChequePaymentProcessor:

@In @PayByCheque AsynchronousPaymentProcessor processor;

Rule 2: The /least-specific bindings/ rule

This proposed rule is analogous to the previous rule, but refers to binding annotations rather than API types. It could be adopted either in addition to, or as an alternative to, Rule 1. It states that if the algorithm above fails to result in a unique component, and if there is exactly one component in the set of candidates that has /exactly/ the same binding annotations specified at the injection point, then this least-specific component will be chosen.

For example, if I have this pre-existing component:

@Component @PayByCheque 
ChequePaymentProcessor implements PaymentProcessor { ... }

and I introduce a new component that also supports the @PayByCheque binding annotation:

@Component @PayByCheque @Asynchronous
AsynchronousChequePaymentProcessor 
    extends ChequePaymentProcessor { ... }

Then the following injection point would continue to resolve to the base ChequePaymentProcessor component:

@In @PayByCheque PaymentProcessor paymentProcessor;

While this new injection point would of course receive an instance of AsynchronousPaymentProcessor:

@In @PayByCheque @Asynchronous PaymentProcessor paymentProcessor;

Are you scared yet?

Phew, we started to get a bit esoteric there! Don't worry, this is as complex as it gets, and if we get too much negative feedback about the two proposed rules above, it won't even get /that/ complex.

We're now really close to releasing a Community Review Draft for Web Beans. The purpose of the draft is to gather feedback on the component model, dependency management model and extensible context model that we've defined, and hopefully get people excited about Web Beans. We also need to get our work in front of the other EE6-related expert groups, so that they can start thinking about how they can possibly re-use and integrate with some of the mechanisms we have defined. However, the specification is by nature written in highly technical language, so this blog entry is the first in a serious of articles giving a friendly, introductory guide to Web Beans. When the Community Review Draft is released, please take the time to download and review it. But please read this series /first/.

A little history

First, some background. Web Beans was initiated by JBoss to help fill a gap in Java EE 5. The EE 5 platform has strong support for access to transactional resources via mature technologies including EJB3, JTA, JCA and JPA. Of course, the platform also features various widely-used web presentation technologies such as Java Servlets, JSP and JSF. However, the /web tier/ and /transactional tier/ have evolved independently and have missed the opportunity to develop a shared component model for web applications which provide access to transactional enterprise resources. Today, Web Beans is being driven by representatives of JBoss, Sun, Oracle and Google, along with several individual members. The component model is deeply influenced by Google Guice and Seam.

A unified component model for Java EE

Web Beans is a component model that is compatible with technologies in both tiers. Web Beans integrates with both JSF and EJB3, allowing an EJB3 session bean to act as a JSF managed bean, thus unifying the two component models. Additionally, Web Beans provides a /conversation model/ and /persistence context management/, thereby solving state management problems and optimistic transaction management problems that affect JSF and JPA. In sum, Web Beans makes it /much/ easier to build Java EE web applications which access the database via JPA.

While Web Beans provides a sweet spot for the integration of JSF and EJB3, the component model is much more generally useful. In particular, it supports use without either JSF or EJB3. An early question that arose was to what extent Web Beans would be limited to the EE and EJB3 environment. The unanimous decision of the group was that:

  1. A Web Bean does not /have/ to be an EJB
  2. Web Beans should be executable outside the EE environment

The first decision merely recognizes the fact that not every component needs the services that EJB provides (transaction demarcation, authorization, etc). However, Web Beans will not duplicate this functionality, so when these services are needed, the Web Bean should be written as a session bean.

The second decision allows components to be integration/unit testable outside the application server environment, and allows reuse of code in, for example, a batch process.

Some members, notably Bob Lee, argue that the work we've done is just as useful outside of the EE platform and that the component model in particular should be considered for use in Java SE. However, as spec lead, and in view of the language of our JSR proposal, I've made the decision to clearly specify the target environment as Java EE, and limit our discussions to what is needed by EE developers.

If, in future, there was pressure from the community and the JCP to open up some parts of Web Beans (for example, the sophisticated Guice-style dependency injection engine), we could at that time follow the precedent established by JPA in the EJB3 expert group and define behavior outside of the EE platform.

Web Bean components

So what, /exactly/, is a Web Bean?

A Web Bean is an application component containing 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 Beans container. Most Web Beans are /stateful/ and /contextual/. The lifecycle of a Web Bean is always managed by the container.

Let's back up a second. What does it 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), different clients of a component see the component in different states. The client-visible state depends upon which instance of the component the client has a reference to.

However, like a stateless or singleton model, and like JSF, but /unlike/ stateful session beans, the client does not control the lifecycle of the instance by explicitly creating and destroying it. Instead, a /context/ defines:

  • the lifecycle of an instance
  • the scope of visibility of this instance to clients

So clients (for example, other Web Beans) executing in the same /scope/ will see the same instance. But clients in a different scope will see a different instance.

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

  • they interact via well-defined public APIs
  • their lifecycles are completely decoupled

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

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

A Web Bean component comprises:
  • A component type
  • Either a bean implementation class or a resolver method
  • A set of API types
  • A (possibly empty) set of binding annotation types
  • A scope
  • A component name

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

Component types

All we need to know about /component types/ for now is that a Web Beans developer may define some kind of stereotype as an annotation, for example @Mock, @Staging or @AustralianTaxLaw that allows whole sets of components to be conditionally installed in particular deployments of the system. We'll talk more about this unique and powerful feature in a later installment.

A very simple Web Bean might just use the built-in component type @Component:

@Component
public class Credentials { ... }

The prescence of a component type annotation identifies this class as a Web Bean to the Web Beans container.

API types, binding annotation and dependency injection

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

  • An API
  • A (possibly empty) set of binding annotations

An API is a user-defined class or interface. (If the component is an EJB session bean, the API type is the @Local interface.) A /binding annotation/ is a user-defined annotation that is itself annotated @BindingType.

The container searches for a component which satisfies this contract (implements the API, and supports the binding annotations), and injects that component.

For example, if this was the injection point:

@In @CreditCard PaymentProcessor paymentProcessor;

The following component could be injected:

@CreditCard @Component
public class CreditCardPaymentProcessor 
    implements PaymentProcessor { ... }

Web Beans defines a sophisticated but intuitive /resolution algorithm/ that helps the container decide what to do if there is more than one component that satisfies a particular contract. We'll get into the details in a later installment.

Component scope

The /scope/ defines the lifecycle and visibility of instances of the component. The Web Beans context model is extensible, accommodating arbitrary scopes. However, certain important scopes are built-in to the specification, and provided by the Web Beans container. For example, any web application has access to a /session/ scope:

@SessionScoped @Component
public class ShoppingCart { ... }

We'll talk more about scopes in a later installment.

Component names and Unified EL

All Web Beans may be used by /name/ in Unified EL expressions. It is easy to customize the name of a Web Bean:

@SessionScoped @Component @Named("cart")
public class ShoppingCart { ... }

Then we can easily use the component in a JSF page:

<h:dataTable value="#{cart.lineItems}" var="item">
    ....
</h:dataTable>

Resolver methods and web-beans.xml

Most Web Beans are defined by writing an implementation class and annotating it. However, there are two extra ways to define a Web Bean:

  1. via an XML deployment descriptor named web-beans.xml
  2. by writing a resolver method

We'll cover web-beans.xml in a future installment.

A /resolver method/ is a method that is called by the container to obtain an instance of the component when no instance exists in the current context. For example:

@SessionScoped @Component
public class Login {

    User user;
    ...
    
    public void login() {
        user = ...;
    }
    
    @Resolves @LoggedIn User getCurrentUser() {
        return user;
    }

}

A resolver method is a first-class Web Beans component. Once again, we'll talk more about resolver method in a future installment.

Logging in

Let's illustrate these ideas by fleshing out the previous example. We're going to implement user login/logout. First, we'll define a component to hold the username and password entered during login:

@Component
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 component is bound to the login prompt in the following JSF form:

<f:form>
    <h:panelGrid columns="2" rendered="#{!login.isLoggedIn}">
        <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.isLoggedIn}"/>
    <h:commandButton value="Logout" acion="#{login.logout}" rendered="#{login.isLoggedIn}"/>
</f:form>

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

@SessionScoped @Component
public class Login {

    @In Credentials credentials;
    @In @UserDatabase 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;
    }
    
    @Resolves @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 component can easily inject the current user:

@Component
public class DocumentEditor {

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

Stay with me, folks!

Hopefully, this gives a flavor of the Web Beans component model. There's lots more to talk about, I hope you'll find the time to follow along with the rest of the series.