Chapter 1. Architecture

Web Beans provides a powerful new set of services to Java EE components. This specification defines:

To take advantage of these facilities, the Java EE component developer provides additional component-level and application-level metadata in the form of Java annotations and/or XML-based deployment descriptors.

A Java EE component with a lifecycle bound to a Web Beans context is called a Web Bean. Any Web Bean may be injected into other Java EE components by the Web Beans dependency injection service.

The use of Web Beans significantly simplifies the task of creating Java EE applications by integrating the Java EE web tier with Java EE enterprise services. In particular, Web Beans allows EJB 3 components to be used as JSF managed beans, thus integrating the the component models of EJB and JSF and significantly simplifying the programming model when EJB and JSF are used together. In an environment that supports Web Beans, all EJB 3 session and singleton beans are Web Beans—no Web Beans specific metadata is required.

Furthermore, Web Beans makes it easy to use most plain Java classes as Java EE components that may inject, or be injected into, other Java EE components such as EJBs or Servlets. Web Beans promotes plain Java classes to the status of managed Java EE components. In particular, in an environment that supports Web Beans, all JavaBeans are Web Beans—no Web Beans specific metadata is required.

Even when EJB, or JSF, or both, are not used, Web Beans may be used to simplify development of the business-logic layer of an application. It is even possible for applications developed using third-party frameworks to take advantage of the services provided by Web Beans via a framework integration SPI.

1.1. Contracts

This specification defines the responsibilities of a user who writes an application that executes inside an environment that supports Web Beans and uses the functionality provided by Web Beans, along with responsibilities of a vendor who implements the functionality defined by this specification and provides a runtime environment in which Web Beans execute — the Web Bean manager. Both the application that uses Web Beans and the Web Bean manager are written to comply with Java EE contracts and may take advantage of the functionality provided by Java EE.

The Web Bean manager may be provided by a Java EE container vendor as integrated functionality of the Java EE container or embeddable EJB Lite implementation. Alternatively, a plugin Web Bean manager may be provided by some third-party for use with various Java EE containers and embeddable EJB Lite implementations.

1.2. Supported environments

A Web Bean application may be designed to execute in either the Java EE 6, Java EE 5 or Java SE environments. When a Web Bean application executes in a Java SE environment, an embeddable EJB Lite implementation provides the Java EE services.

All plugin Web Bean managers are required to support any Java EE 6 compliant container and any embeddable EJB Lite implementation. An integrated Web Bean manager is not required to support any environment other than that in which it is integrated.

A compliant plugin Web Bean manager may optionally support Java EE 5. Certain functionality defined in this specification is optional when the Web Bean manager executes in a Java EE 5 environment. This is the case only when explicitly noted in this specification. All other functionality defined by this specification must be supported by a compliant plugin Web Bean manager that supports Java EE 5 when it executes in the Java EE 5 environment.

A plugin Web Bean manager integrates with the Java EE container or embeddable EJB Lite implementation via standard Java EE APIs such as JNDI, EJB interceptors and servlet filters.

1.3. Relationship to other specifications

An application developer using Web Beans creates Java EE components such as EJBs, Servlets and JavaBeans and then provides additional Web Beans metadata that defines additional behavior in terms of the Web Beans context model. These components may take advantage of the services defined by this specification, together with the enterprise and presentational aspects defined by other Java EE platform technologies.

This specification defines the collaboration between the Web Bean manager and Java EE component technologies such as EJB, JavaServer Faces and Java Servlets.

In addition, this specification defines an SPI that allows a Web Bean manager to be integrated with alternative, non-platform technologies, for example, alternative web presentation technologies.

Open issue: the Web Beans annotations for dependency injection, scope and interceptor binding are currently defined in the package javax.webbeans. To make these annotations more easily consumable by other specifications, should they instead be categorized by concern into packages such as javax.dependency, javax.contexts and javax.interceptors?

1.3.1. Relationship to EJB

EJB defines a programming model for application components that access transactional resources in a multi-user environment. EJB allows concerns such as role-based security, transaction demarcation, concurrency and scalability to be specified declaratively using annotations and XML deployment descriptors and enforced by the EJB container at runtime.

EJB components may be stateful, but are not by nature contextual. References to stateful component instances must be explicitly passed between clients and stateful instances must be explicitly destroyed by the application.

Any EJB bean obtained via the Web Beans dependency injection service is a contextual object. It is bound to a context and available to other Web Beans that execute in that context. The Web Bean manager automatically calls the EJB container to create the EJB bean when it is needed by a client. When the context ends, the Web Bean manager automatically calls the EJB container to destroy the bean.

For any EJB bean, even EJB beans which are not obtained via the Web Beans dependency injection service, the Web Bean manager provides certain services, including injection of Web Bean instances and binding of Web Bean interceptors and decorators.

In general, The EJB container provides the services defined by the EJB specification, and the Web Bean manager provides the services defined by this specification. In particular, the Web Bean manager provides contextual lifecycle management, delegating the actual creation and destruction of the EJB bean to the EJB container. The Web Bean manager integrates with the EJB container via standard EJB and Java EE APIs.

1.3.2. Relationship to JSF

JavaServer Faces is a web-tier presentation framework that provides a component model for graphical user interface components, a managed bean component model for application logic, and an event-driven interaction model that binds the two component models. The managed bean component model is a contextual model where managed beans are bound to one of the three web tier contexts and may hold contextual state.

Any Web Bean may fulfill the role of the managed bean in a JSF application. Thus, a JSF application may take advantage of the more sophisticated context and dependency injection model defined by this specification. Even better, the Web Bean may be an EJB bean, allowing direct use of EJB in any JSF page.

The Web Bean manager integrates with JSF via standard JSF APIs.

1.3.3. Relationship to Java Servlets

Web Beans may be called by a Servlet or JSP. The Web Bean manager integrates with the Servlet engine via standard APIs defined by the Java Servlets specification.

Servlets are not themselves Web Beans, because they may not be injected into another object by the Web Beans dependency injection mechanism. However, in the Java EE 6 environment, the Web Bean manager does provide injection of Web Beans into Servlets and binding of Web Bean interceptors and decorators to Servlets.

Note: we have requested an additional API from the Servlet specification to make this possible!

1.3.4. Relationship to Common Annotations for the Java Platform

Certain functionality defined by Common Annotations for the Java Platform is available to any Web Bean. For Web Beans which are not EJB beans, this functionality is provided by the Web Bean manager.

1.4. Introductory examples

The following examples demonstrate the Web Beans programming model.

1.4.1. JSF example

The following JSF page defines a login prompt for a web application:

<f:view>
    <f: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}"/>
    </f:form>
</f:view>

The Unified EL expressions in this page refer to Web Beans named credentials and login.

The Credentials class is a Web Bean whose lifecycle is bound to the JSF request:

@Model
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; }
    
}

The @Model annotation is a stereotype that identifies the Credentials class as a Web Bean which acts as a model object in an MVC architecture.

The Login class is a Web Bean whose lifecycle is bound to the HTTP session:

@SessionScoped @Model
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() {
        if (user==null) {
            throw new NotLoggedInException();
        }
        else {
            return user;
        }
    }

}

The @SessionScoped annotation is a scope type that specifies the lifecycle of instances of Login.

The @Current annotation is a binding annotation and causes the Credentials Web Bean to be injected into an instance of Login when it is created by the Web Bean manager.

The Common Annotations @PersistenceContext annotation causes a JPA EntityManager to be injected by the Web Bean manager.

The @LoggedIn annotation is also a binding annotation. The method annotated @Produces is a producer method, which will be called whenever another Web Bean in the system needs the currently logged-in user, for example, whenever the user attribute of the DocumentEditor class is injected by the Web Bean manager:

@Model
public class DocumentEditor {

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

When the login form is submitted, JSF sets the entered username and password onto an instance of the Credentials Web Bean that is automatically instantiated and provided by the Web Bean manager. Next, JSF calls the login() method on an instance of Login that is automatically instantiated and provided by the Web Bean manager. This instance continues to exist for and be available to other requests in the same HTTP session, and provides the User object representing the current user to any other Web Bean that requires it (for example, DocumentEditor). If the producer method is called before the login() method initializes the user object, it throws a NotLoggedInException.

1.4.2. EJB example

Our Login class may take advantage of the functionality defined by EJB:

@Stateful @SessionScoped @Model
public class Login {

    @Current Credentials credentials;
    @PersistenceContext EntityManager userDatabase;

    private User user;
    
    @TransactionAttribute(REQUIRES_NEW) 
    @RolesAllowed("guest")
    public void login() {
        ...
    }
    
    public void logout() {
        user = null;
    }
    
    public boolean isLoggedIn() {
        return user!=null;
    }
    
    @RolesAllowed("user")
    @Produces @LoggedIn User getCurrentUser() {
        ...
    }

}

The @Stateful annotation specifies that this Web Bean is also an EJB stateful session bean. The @TransactionAttribute and @RolesAllowed annotations declare the EJB transaction demarcation and security attributes.

1.4.3. Interceptor example

Web Beans interceptors allow common, cross-cutting concerns to be applied to Web Beans via custom annotations. Interceptor types may be individually enabled or disabled at deployment time.

The AuthorizationInterceptor class defines a custom authorization check:

@Secure @Interceptor public class AuthorizationInterceptor {
    
    @LoggedIn User user;
    
    @AroundInvoke public void authorize(InvocationContext ic) {
        try {
            if ( !user.isBanned() ) {
                System.out.println("Authorized");
                ic.proceed();
            }
            else {
                System.out.println("Not authorized");
                throw new NotAuthorizedException();
            }
        }
        catch (NotAuthenticatedException nae) {
            System.out.println("Not authenticated");
            throw nae;
        }
    }
    
}

The Web Beans @Interceptor annotation identifies the AuthorizationInterceptor class as a Web Beans interceptor. The @Secure annotation is a custom interceptor binding type.

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

The @Secure annotation is used to apply the interceptor to a Web Beans or EJB bean:

@Model
public class DocumentEditor {

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

When the save() method is invoked, the authorize() method of the interceptor will be called. The invocation will proceed to the DocumentEditor class only if the authorization check is successful.

1.4.4. Decorator example

Web Beans decorators are similar to interceptors, but apply only to Web Beans of a particular Java interface. Like interceptors, decorators may be easily enabled or disabled at deployment time. Unlike interceptors, decorators are aware of the semantics of the intercepted method.

For example, the DataAccess interface might be implemented by many Web Beans:

public interface DataAccess {
      
    public Object load(Object id);
    public Object getId();

    public void save();
    public void delete();
    
    public Class getDataType();
      
}

The DataAccessAuthorizationDecorator class defines the authorization checks:

@Decorator public abstract class DataAccessAuthorizationDecorator 
    implements DataAccess {
    
    @Decorates DataAccess delegate;
    
    @LoggedIn User user;
    
    public void save() {
        authorize("save");
        delegate.save();
    }
      
    public void delete() {
        authorize("delete");
        delegate.delete();
    }
    
    private void authorize(String action) {
        try {
            Object id = delegate.getId();
            Class type = delegate.getDataType();
            if ( user.hasPermission(action, type, id) )
            {
                System.out.println("Authorized for " + action);
            }
            else {
                System.out.println("Not authorized for " + action);
                throw new NotAuthorizedException(action);
            }
        }
        catch (NotAuthenticatedException nae) {
            System.out.println("Not authenticated");
            throw nae;
        }
    }
    
}

The @Decorator annotation identifies the DataAccessAuthorizationDecorator class as a Web Beans decorator. The @Decorates annotation identifies the delegate attribute, which the decorator uses to delegate method calls to the Web Bean manager. The decorator applies to any Web Bean that implements DataAccess.

The decorator intercepts invocations just like an interceptor. However, unlike an interceptor, the decorator contains functionality that is specific to the semantics of the method being called.

Decorators may be declared abstract, relieving the developer of the responsibility of implementing all methods of the decorated interface. If a decorator does not implement a method of an API type, the decorator will simply not be called when that method is invoked upon the decorated Web Bean.