SeamFramework.orgCommunity Documentation

Web Beans: Contextos Java e Injeção de Dependência

O novo padrão para injeção de dependência e gerenciamento de estado contextual


Nota
I. Utilizando objetos contextuais
1. Introdução a Web Beans
1.1. Seu primeiro Web Bean
1.2. O que é um Web Bean?
1.2.1. Tipos de API, tipos de binding e injeção de dependências
1.2.2. Tipos de publicação (deployment types)
1.2.3. Escopo
1.2.4. Nomes Web Beans e Unified EL
1.2.5. Tipos de interceptor binding
1.3. Que tipos de objetos podem ser Web Beans?
1.3.1. Web Beans Simples
1.3.2. Web Beans corporativos (Enterprise Web Beans)
1.3.3. Métodos produtores (producer methods)
1.3.4. JMS endpoints
2. Aplicação web JSF de exemplo
3. Web Beans, a Implementação de Referência da JSR-299
3.1. Utilizando o JBoss AS 5
3.2. Utilizando o Apache Tomcat 6.0
3.3. Utilizando o GlassFish
3.4. O exemplo numberguess
3.4.1. O exemplo numberguess para o Tomcat
3.5. O exemplo translator
4. Injeção de Dependências
4.1. Anotações de ligação (binding annotations)
4.1.1. Binding annotations with members
4.1.2. Combinações de anotações de binding
4.1.3. Anotações de binding e métodos produtores
4.1.4. O tipo padrão de binding
4.2. Tipo de deploy
4.2.1. Ativando tipos de implantação (deployment types)
4.2.2. Precedencia dos tipos de deploy
4.2.3. Exemplo de tipos de deploy
4.3. Fixing unsatisfied dependencies
4.4. Proxies clientes
4.5. Obtendo um Web Bean via lookup programaticamente
4.6. Chamadas ao ciclo de vida, @Resource, @EJB e @PersistenceContext
4.7. O objeto InjectionPoint
5. Escopos e contextos
5.1. Tipos de escopo
5.2. Escopos pré-definidos
5.3. O escopo de conversação
5.3.1. Demarcação de contexto
5.3.2. Propagação de conversação
5.3.3. Timeout de conversação
5.4. O dependent pseudo-scope
5.4.1. A anotação @New
6. Métodos produtores
6.1. Escopo de um método produtor
6.2. Injeção em métodos produtores
6.3. Uso do @New em métodos produtores
II. Desenvolvendo código fracamente acoplado
7. Interceptadores
7.1. Bindings de interceptadores
7.2. Implementando interceptadores (interceptors)
7.3. Habiliatando interceptadores (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. Decoradores
8.1. Atributos delegados
8.2. Habilitando decoradores
9. Eventos
9.1. Observadores de eventos
9.2. Produtores de Eventos
9.3. Resgistrando observadores (observers) dinamicamente
9.4. Bindings de eventos com os membros
9.5. Múltiplos evento bindings
9.6. Observadores transacionais
III. Obtendo o máximo da tipificação forte
10. Estereótipos
10.1. Escopo padrão e o tipo de implantação para um estereótipo
10.2. Restringindo o escopo e o tipo com um estereótipo
10.3. Bindings de interceptadores para estereótipos
10.4. Padronização de nomes com estereótipos
10.5. Estereótipos padrões
11. Especialização
11.1. Utilizando a especialização
11.2. Vantagens da especialização
12. Definindo Web Beans utilizando XML
12.1. Declarando classes Web Beans
12.2. Declarando metadados Web Bean
12.3. Declarando membros Web Bean
12.4. Declarando inline Web Beans
12.5. Utilizando um esquema
IV. Web Beans e o ecossistema Java EE
13. Integração com o Java EE
13.1. Injetando recursos Java EE em um Web Bean
13.2. Invocando um Web Bean a partir de um Servlet
13.3. Invocando um Web Bean de um Message-Driven Bean
13.4. Endpoints JMS
13.5. Empacotamento e implantação
14. Extendendo a Web Beans
14.1. O objeto Manager
14.2. A classe Bean
14.3. A interface Context
15. Próximos passos
V. Referência à Web Beans
16. Servidores de Aplicação e ambientes suportados pela Web Beans
16.1. Utilizando a Web Beans com o JBoss AS
16.2. Glassfish
16.3. Tomcat (or any plain Servlet container)
16.4. Java SE
16.4.1. Web Beans SE Module
17. Extensões da JSR-299 disponíveis como parte da Web Beans
17.1. Web Beans Logger
17.2. Gerador XSD para descritores de implantação XML da JSR-299
A. Integrando a Web Beans RI em outros ambientes
A.1. A SPI da Web Beans RI (The Web Beans RI SPI)
A.1.1. Descoberta de Web Bean (Web Bean Discovery)
A.1.2. Serviços EJB
A.1.3. Serviços JPA
A.1.4. Servicos de transação
A.1.5. O contexto de aplicação
A.1.6. Bootstrap e shutdown
A.1.7. JNDI
A.1.8. Carregando recursos
A.1.9. Servlet injection
A.2. O contrato com o container

A JSR-299 mudou recentemente seu nome de "Web Beans" para "Contextos Java e Injeção de Dependência". O guia de referência ainda se refere a JSR-299 como "Web Beans" e a Implementação de Referência da JSR-299 como "Web Beans RI". Outra documentação, blogs, fóruns etc. podem utilizar a nova nomenclatura, incluindo o novo nome para a Implementação de Referência da JSR-299 - "Web Beans".

Você também vai descobrir que algumas das mais recentes funcionalidades não estão implementadas (como campos produtores, realização, eventos assíncronos, mapeamento XML dos recursos EE).

A especificação Web Beans (JSR-299) define um conjunto de serviços para o ambiente Java EE que torna muito simples o desenvolvimento de aplicações. Web Beans adiciona um avançado ciclo de vida e um modelo interativo sobre os tipos de componentes Java existentes, incluindo os JavaBeans e Enterprise Java Beans. Como complemento ao tradicional modelo de programação Java EE, a Web Beans provê:

Injeção de dependência, junto com o gerenciamento contextual do ciclo de vida, livra o usuário de uma API desconhecida, de ter de perguntar e reponders as seguintes questões:

Um Web Bean especifica apenas o tipo e a semântica de outros Web Beans que ele dependa. Ele não precisa ser consciente do próprio ciclo de vida, implementação concreta, modelo de threading ou outro cliente de qualquer Web Bean que ele dependa. Ainda melhor, a implementação concreta, ciclo de vida e o modelo de threading do Web Bean que ele dependa, pode variar de acordo com o cenário de implantação, sem afetar qualquer cliente.

Eventos, interceptadores e decoradores permitem o fraco acoplamento que é inerente nesse modelo:

Mais importante, Web Beans oferece todas essas facilidades de uma maneira typesafe. Web Beans nunca utiliza identificadores baseados em strings para determinar o modo como os objetos se relacionam. XML, continua a ser uma opção, mas raramente é utilizado. Em vez disso, Web Beans utiliza a informação de tipo que está disponível no modelo de objeto Java, juntamente com um novo padrão, chamado anotações de binding, para interconectar Web Beans, suas dependências, seus interceptadores e decoradores e seus consumidores de eventos.

Os serviços dos Web Beans são genéricos e aplicados aos seguintes tipo de componentes existentes no ambiente Java EE:

Web Beans prevê ainda pontos de integração necessários para que outros tipos de componentes definidos pelas futuras especificações Java EE ou por frameworks não-padrão possam ser transparentemente integrados com a Web Beans, tirando proveito dos serviços da Web Beans, e interagindo com qualquer outro tipo de Web Bean.

A Web Beans foi influênciada por inúmeros frameworks Java existentes, incluindo Seam, Guice e Spring. Entretanto, Web Beans tem suas prórias características: mais typesafe que o Seam, mais stateful e menos centrada em XML que o Spring, mais web e capaz para aplicações corporativas que o Guice.

O mais importante, Web Beans é um padrão do JCP, que integra-se transparentemente com o Java EE, e com qualquer outro ambiente Java SE onde o EJB Lite embutível está disponível.

Índice

1. Introdução a Web Beans
1.1. Seu primeiro Web Bean
1.2. O que é um Web Bean?
1.2.1. Tipos de API, tipos de binding e injeção de dependências
1.2.2. Tipos de publicação (deployment types)
1.2.3. Escopo
1.2.4. Nomes Web Beans e Unified EL
1.2.5. Tipos de interceptor binding
1.3. Que tipos de objetos podem ser Web Beans?
1.3.1. Web Beans Simples
1.3.2. Web Beans corporativos (Enterprise Web Beans)
1.3.3. Métodos produtores (producer methods)
1.3.4. JMS endpoints
2. Aplicação web JSF de exemplo
3. Web Beans, a Implementação de Referência da JSR-299
3.1. Utilizando o JBoss AS 5
3.2. Utilizando o Apache Tomcat 6.0
3.3. Utilizando o GlassFish
3.4. O exemplo numberguess
3.4.1. O exemplo numberguess para o Tomcat
3.5. O exemplo translator
4. Injeção de Dependências
4.1. Anotações de ligação (binding annotations)
4.1.1. Binding annotations with members
4.1.2. Combinações de anotações de binding
4.1.3. Anotações de binding e métodos produtores
4.1.4. O tipo padrão de binding
4.2. Tipo de deploy
4.2.1. Ativando tipos de implantação (deployment types)
4.2.2. Precedencia dos tipos de deploy
4.2.3. Exemplo de tipos de deploy
4.3. Fixing unsatisfied dependencies
4.4. Proxies clientes
4.5. Obtendo um Web Bean via lookup programaticamente
4.6. Chamadas ao ciclo de vida, @Resource, @EJB e @PersistenceContext
4.7. O objeto InjectionPoint
5. Escopos e contextos
5.1. Tipos de escopo
5.2. Escopos pré-definidos
5.3. O escopo de conversação
5.3.1. Demarcação de contexto
5.3.2. Propagação de conversação
5.3.3. Timeout de conversação
5.4. O dependent pseudo-scope
5.4.1. A anotação @New
6. Métodos produtores
6.1. Escopo de um método produtor
6.2. Injeção em métodos produtores
6.3. Uso do @New em métodos produtores

Então você está interessado em começar a escrever o seu primeiro Web Bean? Ou talvez você é cético, imaginando que tipos de hoops a especificação Web Beans fará com que você passe! A boa notícia é que você provavelmente já escreveu e utilizou centenas, talvez milhares de Web Beans. Você pode até não se lembrar do primeiro Web Bean que escreveu.

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.

Suponha que temos duas classes Java existentes, que temos utilizado por anos em várias aplicações. A primeira classe faz a divisão (parse) de uma string em uma lista de sentenças:

public class SentenceParser {

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

A segunda classe existente é um stateless session bean de fachada (front-end) para um sistema externo que é capaz de traduzir frases de uma língua para outra:

@Stateless

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

Onde Translator é a interface local:

@Local

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

Infelizmente, não temos uma classe preexistente que traduz todo texto de documentos. Então vamos escrever um Web Bean que faz este trabalho:

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

Podemos obter uma instância de TextTranslator injetando-a em um Web Bean, Servlet ou EJB:

@Initializer

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

Alternativamente, nós podemos obter uma instância invocando diretamente o método do gerenciador do Web Bean:

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.

Então, o que, exatamente, é um 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.

No entanto, como o modelo stateless ou singleton, mas ao contrário dos stateful session beans, o cliente não controla o ciclo de vida da instância por explicitamente criar e destruí-lo. Em vez disso, o escopo do Web Bean determina:

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 Seção 4.2, “Tipo de deploy”.

Note que nem todos os clientes de um Web Bean são Web Beans. Outros objetos, tais como Servlets ou Message-Driven Beans — que são, por natureza, não injetável, objetos contextuais — podem também obter referências a Web Beans por injeção.

Chega de mão abanando. Mais formalmente, de acordo com a especificação:

Um Web Bean compreende:

  • Um conjunto (não vazio) de tipos de API (API types)

  • Um conjunto (não vazio) de tipos de anotações de binding

  • Um escopo

  • Um tipo de publicação (deployment type)

  • Opcionalmente, um nome Web Bean

  • Um conjunto de tipos de interceptor binding

  • A implementação de Web Bean

Vamos ver o que alguns destes termos significam, para o desenvolvedor Web Bean.

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 Capítulo 4, Injeção de Dependências.

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

Então, quando deveremos usar Web Bean corporativo (enterprise) em vez de um simples Web Bean? Bem, sempre que tivermos a necessidade de serviços corporatvios (enterprise) avançados oferecidos pelo EJB, tais como:

devemos utilizar um Web Bean corporativo (enterprise). Quando não precisamos de nenhuma destas coisas, um Web Bean simples vai servir muito bem.

Muitos Web Beans (incluindo qualquer Web Bean em escopo de sessão ou de aplicação) estão disponíveis para acesso concorrente. Por isso, o gerenciamento de concorrência fornecida pelo EJB 3.1 é especialmente útil. A maioria dos Web Beans em escopo de sessão e aplicação devem ser 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.

Por último, isso normalmente é óbvio quando gerenciamento de transações e segurança em nível de método, temporizadores, métodos remotos ou assíncronos são necessários.

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.

Vamos ilustrar estas idéias com um exemplo completo. Nós iremos implementar um login/logout de usuário de uma aplicação que utiliza JSF. Primeiro, vamos definir um Web Bean que irá armazenar o nome do usuário (username) e a senha (password) fornecidos durante o 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; }
    
}

Esse Web Bean é vinculado ao prompt de login do seguinte formulário JSF:

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

O verdadeiro trabalho é realizado por um Web Bean em escopo de sessão que mantém informações sobre o atual usuário conectado e expõe a entidade User para outros 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;
    }
}

Certamente, @LoggedIn é uma anotação de binding (binding annotation):

@Retention(RUNTIME)

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

Agora, qualquer outro Web Bean pode facilmente injetar o usuário atual:

public class DocumentEditor {


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

Esperamos que esse exemplo pôde dar um gostinho do modelo de programação com Web Beans. No capítulo seguinte, iremos explorar a injeção de dependência da Web Beans em profundidade.

A Web Beans está sendo desenvolvida no projeto Seam. Você pode baixar a última versão da Web Beans na página de downloads.

A Web Beans vem com duas aplicações de exemplo: webbeans-numberguess, um war, contendo apenas beans simples (simple beans), e webbeans-translator um ear, contendo beans corporativos (enterprise beans). Existem ainda, duas variações do exemplo numberguess: o exemplo tomcat (adequado para a implantação no Tomcat) e o exemplo jsf2, que você pode usar se estiver utilizando JSF2. Para executar os exemplos, você precisará do seguinte:

  • a última versão da Web Beans,

  • JBoss AS 5.0.1.GA, e

  • Apache Tomcat 6.0.x, e

  • Ant 1.7.0.

Você precisa fazer o download do JBoss AS 5.0.1.GA em jboss.org e descompactá-lo. Por exemplo:"

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

Depois, faça o download da Web Beans em seamframework.org e descompacte-o. Por exemplo

$ cd ~/
$ unzip ~/webbeans-1.0.0.ALPHA1.zip

Em seguida, temos de dizer aos Web Beans onde o JBoss está localizado. Editar o jboss-as/build.properties e definir a propriedade jboss.home. Por exemplo:

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

Para instalar a Web Beans, você precisará do Ant 1.7.0 instalado e a variável de ambiente ANT_HOME setada. Por exemplo:

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

Então, você pode instalar a atualização. O script de atualização irá utilizar o Maven para fazer o download da Web Beans automaticamente.

$ cd webbeans-1.0.0.ALPHA1/jboss-as
$ ant update

Agora, você está pronto para fazer a publicação do seu primeiro exemplo!

Dica

Os scripts para criar os exemplos oferecem uma série de alvos para JBoss AS, entre eles:

  • ant restart - implanta o exemplo no formato explodido

  • ant explode - atualiza o exemplo explodido, sem reiniciar

  • ant deploy - implanta o exemplo no formato jar compactado

  • ant undeploy - remove o exemplo do servidor

  • ant clean - limpa o exemplo

Para implantar o exemplo numberguess:

$ cd examples/numberguess
ant deploy

Inicializando o JBoss AS:

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

Dica

Se você utiliza o Windows, utilize o script run.bat.

Aguarde até que a aplicação seja implantada, e desfrute de horas de diversão em 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

Aguarde até que a aplicação seja implantada, e acesse http://localhost:8080/webbeans-translator!

Depois, faça o download do Tomcat 6.0.18 ou posterior em tomcat.apache.org, e descompacte-o. Por exemplo

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

Depois, faça o download da Web Beans em seamframework.org e descompacte-o. Por exemplo

$ cd ~/
$ unzip ~/webbeans-1.0.0.ALPHA1.zip

Em seguida, temos de dizer aos Web Beans onde o Tomcat está localizado. Editar o jboss-as/build.properties e definir a propriedade tomcat.home. Por exemplo:

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

Dica

Os scripts para criar os exemplos oferecem uma série de alvos para Tomcat, estes são:

  • ant tomcat.restart - publica o exemplo no formato explodido

  • ant tomcat.explode - atualiza o exemplo explodido, sem reiniciar

  • ant tomcat.deploy - publica o exemplo no formato jar compactado

  • ant tomcat.undeploy - remove o exemplo do servidor

  • ant tomcat.clean - clean the example

Para implantar o exemplo numberguess no tomcat:

$ cd examples/tomcat
ant tomcat.deploy

Inicializando o Tomcat:

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

Dica

Se você utiliza o Windows, utilize o script startup.bat.

Aguarde até que a aplicação seja implantada, e desfrute de horas de diversão em http://localhost:8080/webbeans-numberguess!

Na aplicação numberguess você terá 10 tentativas para adivinhar um número entre 1 e 100. Após cada tentativa, você será informado se você disse muito acima, ou muito a baixo.

O exemplo numberguess é composto de um número de Web Beans, arquivos de configuração, e páginas Facelet JSF , empacotados como um war. Vamos começar com os arquivos de configuração.

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
>

Existe um arquivo web-beans.xml vazio, que assinala esta aplicação como uma aplicação Web Beans.

Finalmente no 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(2) id="NumberGuessMain">
          <div 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(3)>
             I'm thinking of a number between #{game.smallest} and #{game.biggest}.
             You have #{game.remainingGuesses} guesses.
          </div>
     
          <div>
             Y(4)our guess: 
             <h:inputText id="inputGuess" 
                          value="#{game.guess}" 
                          required="true" 
                          size="3" 
              (5)            disabled="#{game.number eq game.guess}">
                <f:validateLongRange maximum="#{game.biggest}" 
                                     minimum="#{game.smallest}"/>
             <(6)/h:inputText>
            <h: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 {}

Há também o binding type @MaxNumber, utilizado para injetar o número máximo que pode ser injetado:

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

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

A classe Generator é responsável por criar um número aleatório, através de um método produtor. Ela também expõe o número máximo possível através de um método produtor:

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

Você perceberá que o Generator está no escopo de aplicação; portanto, não obtemos um número aleatório diferente a cada vez.

O Web Bean final da aplicação é o Game em escopo de sessão.

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

O exemplo translator pegará qualquer frase que você fornecer, e traduzi-las para o Latim.

O exemplo translator é construído como um ear, e contém EJBs. Como resultado, a sua estrutura é mais complexa do que exemplo numberguess.

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
>

Aqui nós definiremos o caminho do contexto, que nos dá uma url amigável (http://localhost:8080/webbeans-translator). ulink>) .

Dica

Se você não está usando o Maven para gerar esses arquivos, você precisaria 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.

Mais interessante é o facelet utilizado para traduzir texto. Tal como no exemplo numberguess temos um template, que envolve o formulário (omitido aqui por brevitude):


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

O usuário pode digitar um texto no textarea esquerdo, e clicar no botão traduzir para ver o resultado à direita.

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.

Tanto SentenceParser e TextTranslator são beans dependentes, e TextTranslator usa inicialização por construtor :

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

TextTranslator é um bean stateless (com uma interface de negócios local), onde a mágica acontece - obviamente, não poderíamos desenvolver um tradutor completo, mas demos-lhe um bom caminho!

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;

O bean também tem getters e setters para todos os campos da página.

Como esse é um stateful session bean, temos de ter um método de remoção:

   @Remove

   public void remove()
   {
      
   }

O gerenciador do Web Beans irá chamar o método remover para você quando o bean for destruído, neste caso no final da requisição.

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.

Precisamos de ajuda em todas as áreas - correção de bugs, escrita de novas funcionalidades, escrita de exemplos e tradução deste guia de referência.

Web Beans suporta três principais mecanismos de injeção de dependências:

Injeção de parametros no construtor:

public class Checkout {

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

Initializer injeção por parâmetro de método:

public class Checkout {

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

E injeção direta de campos:

public class Checkout {


    private @Current ShoppingCart cart;
    
}

A injeção de dependências sempre ocorre quando a instância do Web Bean é instanciada.

  • Em primeiro lugar, a gerenciador do Web Bean chama o construtor do Web Bean para obter uma instância do Web Bean.

  • Em seguida, o gerenciador do Web Bean inicializa os valores de todos os campos injetados do Web Bean.

  • Em seguida, o gerenciador do Web Bean chama todos os métodos do Web Bean.

  • Finalmente, o método @PostConstruct do Web Bean, se for o caso, é chamado.

Injeção de parâmetros no construtor não é suportado em EJB beans, uma vez que o EJB é instanciado pelo container EJB e não pelo gerenciador do Web Bean.

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.

Métodos produtores também suportam injeção de parâmetros:

@Produces Checkout createCheckout(ShoppingCart cart) {

    return new Checkout(cart);
}

Por fim, métodos de observação (que iremos detalhar em Capítulo 9, Eventos), métodos de disposal e métodos destrutores, todos suportam injeção de parâmetros.

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.

O objetivo deste algoritmo é permitir que vários Web Beans implementem o mesmo tipo de API e também:

  • permitir que o cliente escolha a implementação que lhe melhor convier utilizando anotações de binding (binding annotations),

  • permitir ao implantador (deployer) da aplicação escolher qual a implentação é adequada para uma determinada implantação, sem alterações para o cliente, por ativar ou desativar tipos de implantação (deployment types), ou

  • permitir uma implementação de uma API sobrescrever uma outra implementação da mesma API em tempo de implantação, sem alterações no cliente, utilizando precedência do tipo de implantação (deployment type precedence).

Vamos explorer como o gerenciador do Web Beans determina qual o Web Bean deve ser injetado.

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

Onde @PayByCheque e @PayByCreditCard são anotações de binding:

@Retention(RUNTIME)

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

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

Um desenvolvedor cliente de um Web Bean utiliza a anotação de binding para especificar exatamente quais Web Bean devem ser injetados.

Utilizando injeção por campos (field injection):

@PayByCheque PaymentProcessor chequePaymentProcessor;

@PayByCreditCard PaymentProcessor creditCardPaymentProcessor;

Utilizando injeção de método de inicialização:

@Initializer

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

Ou utilizando injeção de construtor

@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 {}

Suponha que temos alguns Web Beans que interajam com um sistema externo para processar pagamentos:

public class ExternalPaymentProcessor {

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

Uma vez que esse Web Bean não especifica explicitamente um tipo de implantação, ele tem o tipo de implantação padrão @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.

Clientes de um Web Bean injetado, geralmente não possuem uma referência direta a uma instância do Web Bean .

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.

Os seguintes tipos Java não podem ser "proxied" pelo gerenciador do Web Bean:

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

Podemos agora escrever:

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

O seguinte método produtor faz o trabalho:

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

Até agora, vimos alguns exemplos de anotações de tipo de escopo. O escopo de um Web Bean determina o ciclo de vida das instâncias do Web Bean. O escopo também determina que clientes se referem a quais instâncias do Web Bean. De acordo com a especificação Web Beans, um escopo determina:

  • Quando uma nova instância de qualquer Web Bean com esse escopo é criada

  • Quando uma instância de qualquer Web Bean com esse escopo é destruída

  • Cada referências injetada refere-se a qualquer instância de um Web Bean com esse escopo

Por exemplo, se temos um Web Bean de escopo de sessão CurrentUser, todos os Web Beans que são chamados no contexto do mesmo HttpSession verão a mesma instância do CurrentUser. Essa instância será criada automaticamente na primeira vez que um CurrentUser for necessário nessa sessão, e automaticamente destruído quando a sessão terminar.

O escopo de conversação da Web Beans é um parecido com o tradicional escopo de sessão na medida em que mantém estado associado a um usuário do sistema, e o matém durante várias requisições para o servidor. No entanto, ao contrário do escopo de sessão, o escopo de conversação:

Uma conversação representa uma tarefa, uma unidade de trabalho do ponto de vista do usuário. O contexto de conversação mantém o estado associado com o que o usuário está atualmente fazendo. Se o usuário está fazendo várias coisas ao mesmo tempo, existem várias conversações.

A conversação está ativa durante qualquer requisição JSF. No entanto, a maioria das coversações são destruídas no final da requisição. Se uma conversação deve manter estado através de múltiplas requisições, deve explicitamente ser promovida para uma conversação de longa duração (long-running conversation).

Web Beans oferece um Web Bean pré-definido para o controle do ciclo de vida das conversações em uma aplicação JSF. Este Web Bean pode ser obtido por injeção:

@Current Conversation conversation;

Para promover a conversação associada a requisição atual em uma conversação de longa duração, chame o método begin() no código da aplicação. Para agendar a destruição do atual contexto de conversão de longa duração no final da requisição atual, chame end().

No exemplo a seguir, um Web Bean em escopo de conversação controla a conversação com o qual está associado:

@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() {}
    
}

Este Web Bean é capaz de controlar seu próprio ciclo de vida através do uso da API Conversation. Mas alguns outros Web Beans tem um cliclo vida que depende totalmente de um outro objeto.

Além dos quatro escopos pré-definidos, Web Beans possui o chamado dependent pseudo-scope. Este é o escopo padrão para um Web Bean que não declara explicitamente um tipo de escopo.

Por exemplo, esse Web Bean tem o tipo de escopo @Dependent:

public class Calculator { ... }

Quando um ponto de injeção num Web Bean resolve para um Web Bean dependente, uma nova instância do Web Bean dependente é criada a cada vez que o primeiro Web Bean é instanciado. Instâncias de Web Beans dependentes nunca são compartilhadas entre diferentes Web Beans ou diferentes pontos de injeção. Eles são objetos dependentes de alguma outra instância de Web Bean.

Instâncias de Web Bean dependentes são destruídas quando a instância que eles dependem é destruída.

Web Beans torna fácil a obtenção de uma instância dependente de uma classe Java ou um EJB, mesmo se a classe ou EJB já foram declarados como um Web Bean com outro tipo de escopo.

Métodos produtores permitem superarmos certas limitações que surgem quando o gerenciador do Web Bean, em vez da aplicação, é responsável por instanciar objetos. Eles são também a forma mais fácil de integrar os objetos que não são Web Beans ao ambiente Web Beans. (Vamos ver uma segunda abordagem em Capítulo 12, Definindo Web Beans utilizando XML.)

De acordo com a especificação:

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.

.

Existe um problema potencial com o código acima. As implementações de CreditCardPaymentStrategy são instanciadas utilizando o operador de Java new. Objetos instanciados diretamente pela aplicação não usufruem da injeção de dependência e não possuem interceptadores.

Se isso não é o que queremos, podemos utilizar a injeção de dependência no método produtor para obter instâncias do Web Bean:

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

Espere, o que se CreditCardPaymentStrategy é um Web Bean de escopo de requisição? Então o método produtor tem o efeito de "promover" a instância atual no escopo de requisição para o escopo de sessão. Isso certamente é um erro! O objeto no escopo de requisição será destruído pelo gerenciador do Web Bean antes de terminar a sessão, mas a referência ao objeto será deixada "presa" no escopo sessão. Este erro não será detectado pelo gerenciador do Web Bean, por isso, tome cuidado quando retornar instâncias de Web Bean em métodos produtores!

Existem pelo menos três maneiras de corrigirmos esse erro. Podemos alterar o escopo da implementação do CreditCardPaymentStrategy, mas isso poderia afetar outros clientes desse Web Bean. A mehor opção seria alterar o escopo do médoto produtor para @Dependent ou @RequestScoped.

Mas, uma solução mais comum é utilizar a anotação especial de binding @New

O primeiro grande tema da Web Beans é fraco acoplamento. Já vimos três meios de alcançar o fraco acoplamento:

Essas técnicas servem para habilitar o fraco acoplamento entre o cliente e o servidor. O cliente não está mais fortemente acoplado a uma implementação de uma API, nem é obrigado a gerenciar o ciclo de vida do objeto servidor. Essa abordagem permite que objetos stateful interajam como se fossem serviços.

O fraco acoplamento torna o sistema mais dinâmico. O sistema pode responder à mudanças de uma maneira bem definida. No passado, frameworks que tentaram prover essas facilidades acima listadas, invariavelmente acabaram sacrificando a type safety. A Web Beans é a primeira tecnologia que alcança esse nível de fraco acoplamento de uma meneira typesafe.

Web Beans provê três facilidades extras importantes que ultrapassam o objetivo do fraco acoplamento:

Vamos primeiramente explorar os interceptadores

Web Beans re utiliza a arquitetura básica do interceptor de EJB 3.0, que extende a funcionalidade em duas direções:

  • Qualquer Web Bean pode ter interceptores, não apenas session beans.

  • Web Beans possui uma abordagem mais sofisticadas baseada em anotações para associar interceptores aos Web Beans.

A especificação de EJB define dois tipos de pontos de interceptação:

  • interceptação de métodos de negócios, e

  • interceptadores de chamadas de ciclo de vida

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.

Interceptores são um meio poderoso para capturar e separar preocupações ortogonais para o tipo de sistema. Qualquer interceptador é capaz de interceptar invocações de qualquer tipo Java. Isto torna-os ideais para resolver questões técnicas, tais como gerenciamento de transação e segurança. No entanto, por natureza, interceptores desconhecem a real semântica dos eventos que interceptam. Assim, interceptores não são um instrumentos adequados para a separação de questões relacionadas à negócios.

O contrário é verdadeiro decoradores. O decorator intercepta invocações apenas para uma determinada interface Java e, portanto, é ciente de toda a semântica que acompanha a interface. Isto torna os decoradores uma ferramenta perfeita para modelar alguns tipos de questões de negócios. Significa também que um decorador não tem a generalidade de um interceptador. Decoradores não são capazes de resolver questões técnicas que atravessam muitos tipos diferentes.

Suponha que temos uma interface que representa contas:

public interface Account {

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

Vários Web Beans em nosso sistema implementam a interface Account. No entanto, temos uma obrigação legal que, para qualquer tipo de conta, as grandes transações devem ser registadas pelo sistema, em um registro especial (log). Este é um trabalho perfeito para um decorador.

Um decorador é um Web Bean simples que implementa o tipo que decora e é anotado com @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) );
        }
    }
    
}

Ao contrário de outros Web Beans simples, um decorador pode ser uma classe abstrata. Se não há nada de especial que o decorador precisa fazer para um determinado método da interface decorada, você não precisa implementar esse método.

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:

  • não só os produtores são desacoplados dos observadores; os observadores são totalmente desacoplados dos produtores,

  • observadores podem especificar uma combinação de "seletores" para reduzir o conjunto de eventos que irão receber notificações, e

  • observadores podem ser notificados imediatamente ou podem especificar que a notificação do evento deveria esperar até o têrmino da transação corrente

O evento produtor pode obter um objeto notificador de evento (event notifier) por injeção:

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

Um produtor lança eventos chamando o método fire() da interface Event, passando um objeto event object:

documentEvent.fire(document);

Um objeto de evento pode ser uma instância de qualquer classe Java que não tem qualquer tipo de variáveis ou parâmetros tipo curinga. O evento será entregue a cada método observador que:

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.

Para especificar um "seletor", o produtor do evento pode passar uma instância do tipo de binding do evento para o método fire():

documentEvent.fire( document, new AnnotationLiteral<Updated

>(){} );

O classe auxiliar AnnotationLiteral permite instanciar tipo de binding inline, uma vez que, esta é de outra maneira, difícil de fazer em Java.

O evento será entregue a todo método observador (observer method) que:

Alternativamente, bindings de eventos podem ser especificados anotando o ponto de injeção do notificador do evento:

@Observable @Updated Event<Document

> documentUpdatedEvent

Em seguida, todos os eventos disparados por essa instância de Event tem o binding de evento anotada. O evento será entregue a cada método observador que:

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

Existem três tipos de observadores transacionais:

Observadores transacionais são muito importantes para um modelo de objetos stateful como o Web Beans, porque o estado é muitas vezes mantido por mais de uma única transação atômica.

Imagine que fizemos cache do conjunto de resultados da consulta JPA no escopo de aplicação (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!

O Web Bean que cria e remove Products pode lançar eventos, por exemplo:

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

E agora Catalog pode observar os eventos após o término da transação com sucesso:

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

O segundo grande tema da Web Beans é a tipificação forte. As informações sobre as dependências, interceptores e decoradores de um Web Bean, e as informações sobre os consumidores de eventos para um produtor de evento, estão contidas em construtores Java typesafe, que podem ser validadas pelo compilador.

Você não vê identificadores baseados em strings no código Web Beans, não porque o framework está escondendo-os de você utilizando padrões de regras inteligentes — o chamado "configuração por convenção" -, mas porque simplesmente não existem strings ali!

A óbvia vantagem desta abordagem é que qualquer IDE pode fornecer auto completion, validação e refactoring sem necessidade de ferramentas especiais. Mas há um segundo, menos imediatamente óbvio, benefício. Acontece que quando você começar a pensar na identificação de objetos, eventos ou interceptores através de anotações em vez de nomes, você tem uma oportunidade para aumentar o nível semântico do seu código.

Web Beans incentiva você desenvolver anotações que modelam conceitos, por exemplo,

em vez de utilizar nomes compostos como

As anotações são reutilizáveis. Elas ajudam a descrever qualidades comuns de partes direntes do sistema. Elas nos ajudam a categorizar e entender o nosso código. Elas nos ajudam a lidar com questões comuns de uma maneira comum. Elas tornam o nosso código mais legível e mais compreensível.

Estereótipos Web Beans levam essa idéia um pouco mais longe. Um estereótipo modela um papel comum na sua arquitetura da aplicação. Eles incorporam várias propriedades do papel, incluindo o escopo, bindings de interceptadores, tipos de implantação, etc, em um único pacote reutilizável.

Mesmo os metadados da Web Beans são fortemente tipados! Não há um compilador para XML, então a Web Beans tira proveito de esquemas XML para validar os tipos Java e os atributos que aparecem em XML. Esta abordagem acaba por tornar o XML mais legível, assim como anotações deixam nosso código Java mais legível.

Nós agora estamos prontos para verificar mais algumas funcionalidades avançadas da Web Beans. Tenha em mente que essas funcionalidades existem para tornar nosso código fácil para validar e ao mesmo tempo mais fácil de entender. Na maioria das vezes você nem precisa se preocupar em utilizar essas funcionalidades, mas se são fáceis de usar, você irá apreciar seu poder.

De acordo com a especificação Web Beans:

Em muitos sistemas, a utilização de padrões arquiteturais produz um conjunto de papéis Web Bean recorrentes. Um estereótipo permite a um desenvolvedor de framwework identificar esse papel e declarar alguns metadados comums para Web Beans com esse papel em um local centralizado.

Um estereótipo encapsula qualquer combinação de:

  • um tipo padrão de implantação,

  • um tipo de escopo padrão,

  • uma restrição ao escopo do Web Bean,

  • uma exigência de que o Web Bean implemente ou estenda um certo tipo, e

  • um conjunto de anotações para binding de interceptadores

Um estereótipo também pode especificar que todos os Web Beans com o estereótipo têm um nome Web Bean padrão.

Um Web Bean pode declarar zero, um ou vários estereótipos.

Um estereótipo é um tipo de anotação Java. Este estereótipo identifica classes de ação em algum framework MVC:

@Retention(RUNTIME)

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

Nós utilizamos o esteriótipo aplicando a anotação ao Web Bean.

@Action 

public class LoginAction { ... }

Nós já vimos a forma como o modelo de injeção de dependências da Web Beans permite sobrescrever a implementação da API em tempo de implantação. Por exemplo, o seguinte Bean Web corporativo fornece uma implementação da API PaymentProcessor em produção:

@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

Pode receber uma instância de StagingCreditCardPaymentProcessor.

Infelizmente, existem várias armadilhas que facilmente podemos cair:

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

Em cada um destes casos, o Web Bean que tentamos sobrescrever ainda podia ser chamado em tempo de execução. Portanto, a sobrescrita é algo propensa a erros de desenvolvimento.

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.

Até agora, temos visto muitos exemplos de declaração de Web Beans usando anotações. No entanto, há várias situações em que não podemos usar anotações para definir um Web Bean:

  • quando a classe de implementação vem de alguma biblioteca preexistente, ou

  • quando deveria haver vários Web Beans com a mesma classe de implementação.

Em qualquer destes casos, We Beans nos dá duas opções:

  • escrever um método produtor (producer method), ou

  • declarar um Web Bean utilizando XML.

Muitos frameworks usam XML para fornecer metadados relativos às classes Java. No entanto, Web Beans utiliza uma abordagem muito diferente para especificar os nomes de classes Java, atributos ou métodos dos outros frameworks. Em vez de escrever os nomes das classes e dos membros como uma String de valores em elementos e atributos XML, Web Beans permite que você use o nome da classe ou membro como o nome do elemento XML.

A vantagem desta abordagem é que você pode escrever um esquema XML (XML schema) que evita erros ortográficos no seu documento XML. É até mesmo possível para uma ferramenta gerar o esquema XML (XML schema) automaticamente a partir do código Java compilado. Ou, um ambiente integrado de desenvolvimento poderia fazer a mesma validação sem a necessidade explicíta do passo intermediário de geração.

A terceira motivação da Web Beans é integração. Web Beans foi projetada para trabalhar em conjunto com outras tecnologias, ajudando o desenvolvedor a trabalhar outras tecnologias em conjunto. Web Beans é uma tecnologia aberta. Ela faz parte do ecossistema Java EE, e é por si só a base para um novo ecossistema de extensões portáteis e integração com os frameworks e as tecnologias existentes.

Nós já temos visto como Web Beans ajuda a integrar EJB e JSF, permitindo EJBs serem associados diretamente à páginas JSF . Isso é só o começo. Web Beans oferece o mesmo potencial para diversas outras tecnologias, tais como motores de Gerenciamento de Processos de Negócios, outros Frameworks Web , e modelos de componentes de terceiros. A plataforma Java EE nunca será capaz de padronizar todas as tecnologias interessantes que são utilizadas no mundo de desenvolvimento de aplicações Java, mas a Web Beans facilita a utilização das tecnologias que ainda não fazem parte da plataforma suavemente dentro do ambiente Java EE.

Estamos prestes a ver como tirar o máximo de proveito da plataforma Java EE em uma aplicação que utiliza Web Beans. Iremos também, brevemente reunir um conjunto de SPIs que são fornecidas para suportar extensões portáveis para Web Beans. Talvez você nunca precisará usar estas SPIs diretamente, mas é bom saber que estão lá se você precisar delas. Mais importante, você irá se aproveitar delas indiretamente, toda vez que você utilizar uma extensão de terceiros.

A Web Beans está plenamente integrada ao ambiente Java EE. Web Beans tem acesso aos recursos Java EE e contextos de persistência JPA. Eles podem se utilizados em expressões EL Unificadas (Unified EL) e em páginas JSF e JSP. Podem até ser injetados em objetos que não são Web Benas, tais como Servlets e Message-Driven Beans.

O envio de mensagens usando JMS pode ser bastante complexo, devido a quantidade de objetos diferentes que precisamos utilizar. Para filas temos Queue, QueueConnectionFactory, QueueConnection, QueueSession e QueueSender. Para os tópicos temos Topic, TopicConnectionFactory, TopicConnection, TopicSession e TopicPublisher. Cada um desses objetos tem seus próprios ciclo de vida e modelo de threads a que temos que nos preocupar.

Web Beans cuida de tudo isso para nós. Tudo que precisamos fazer é declarar a fila ou o tópico no web-beans.xml, especificando e associando o tipo de binding e a fábrica de conexão (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
>

Agora, podemos injetar a Queue, QueueConnection, QueueSession ou QueueSender para uma fila, ou Topic, TopicConnection, TopicSession ou TopicPublisher para um tópico.

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

O ciclo de vida do objeto JMS injetado é completamente controlado pelo gerenciador do Web Bean.

Web Beans pretende ser uma plataforma para frameworks, extensões e integração com outras tecnologias. Portanto, Web Beans expõe um conjunto de SPIs para a utilização pelos desenvolvedores de extensões portáveis para Web Beans. Por exemplo, os seguintes tipos de extensões estavam previstas pelos designers da Web Beans:

  • Integração com motores de gerenciamento de processos de negócios (Business Process Management )

  • integração com frameworks de terceiros, tais como Spring, Seam, GWT ou Wicket, e

  • nova tecnologia baseada no modelo de programação.da Web Beans.

O nervo central para extender a Web Beans é o objeto Manager.

A interface Manager permite registrar e obter Web Beans, interceptadores, decoradores, observadores e contextos programaticamente.

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

Nós podemos obter uma instância do Manager via injeção:

@Current Manager manager

Instâncias da classe abstrata Bean representam Web Beans. Existe uma instância do Bean registrado com o objeto Manager para todos os Web Bean da aplicação.

public abstract class Bean<T> {

    
    private final Manager manager;
    
    protected Bean(Manager manager) {
        this.manager=manager;
    }
    
    protected Manager getManager() {
        return manager;
    }
    
    public abstract Set<Class> getTypes();
    public abstract Set<Annotation> getBindingTypes();
    public abstract Class<? extends Annotation> getScopeType();
    public abstract Class<? extends Annotation> getDeploymentType(); 
    public abstract String getName();
    
    public abstract boolean isSerializable();
    public abstract boolean isNullable();
    public abstract T create();
    public abstract void destroy(T instance);
    
}

É possível estender a classe Bean e registrar instâncias através da chamada Manager.addBean() para fornecer suporte para novos tipos de Web Beans, além dos definidos pela especificação Web Beans (Web Beans simples e coporativos, métodos produtores e endpoints JMS). Por exemplo, poderíamos usar a classe Bean para permitir que os objetos gerenciados por um outro framework possam ser injetados nos Web Beans.

Existem duas subclasses de Bean definidas pela especificação de Web Beans: Interceptor e Decorator.

Web Beans é a implementação de referência da JSR-299, e é utilizada pelo JBoss AS e pelo Glassfish para provêr serviços JSR-299 para aplicações Java Enterprise Edition. Web Beans vai além dos ambientes e APIs definidos pela especificação JSR-299 e fornece suporte a uma série de outros ambientes (tais como um servlet container como o Tomcat, ou o Java SE) e APIs e módulos adicionais (como logging, geração de XSD para os descritores de implantação XML da JSR-299).

Se pretende começar a utilizar rapidamente a Web Beans com o JBoss AS ou com o Tomcat, e experimentar um dos exemplos, dê uma olhada em Capítulo 3, Web Beans, a Implementação de Referência da JSR-299. De qualquer maneira, continue lendo para uma discussão exaustiva da utilização da Web Beans em todos os ambientes e servidores de aplicações suportados, bem como as extensões da Web Beans .

Web Beans pode ser utilizada no Tomcat 6.0.

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

You also need to explicitly specify the Tomcat 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
>

O Tomcat tem um JNDI de leitura apenas, assim a Web Beans não pode vincular automaticamente o Manager. Para vincular o Manager no JNDI, você deve adicionar o seguinte ao seu META-INF/context.xml:

<Resource name="app/Manager" 
          auth="Container"
          type="javax.inject.manager.Manager"
          factory="org.jboss.webbeans.resources.ManagerObjectFactory"/>

e torná-lo disponível para a sua implantação, acrescentando-o no web.xml:

<resource-env-ref>
  <resource-env-ref-name>
    app/Manager
  </resource-env-ref-name>
  <resource-env-ref-type>
    javax.inject.manager.Manager
  </resource-env-ref-type>
</resource-env-ref
>

Tomcat only allows you to bind entries to java:comp/env, so the Manager will be available at java:comp/env/app/Manager

Web Beans also supports Servlet injection in Tomcat. To enable this, place the webbeans-tomcat-support.jar in $TOMCAT_HOME/lib, and add the following to your META-INF/context.xml:

<Listener className="org.jboss.webbeans.environment.tomcat.WebBeansLifecycleListener" />

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

Currently the Web Beans RI 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 webbeans-spi module, and packaged as webbeans-spi.jar. Some SPIs are optional, if you need to override the default behavior, others are required.

Todas as interfaces na SPI suportam o padrão decorator e provêm a classe Forwarding.

The Web Beans RI 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 EjbServices

{
   
   /**
    * Gets a descriptor for each EJB in the application
    * 
    * @return The bean class to descriptor map 
    */
   public Iterable<EjbDescriptor<?>
> discoverEjbs();
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 and @Resource is delegated to the container. You must provide an implementation of org.jboss.webbeans.ejb.spi.EjbServices which provides these operations. Web Beans passes in the javax.inject.manager.InjectionPoint the resolution is for, as well as the NamingContext in use for each resolution request.

A Web Beans RI deve delegar as atividades JTA para o container. A SPI fornece vários ganchos para facilmente conseguir isso com a interface TransactionServices.

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.

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

Isolamento de Classloader (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.

Listener e filtros de servlets

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.

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.

Interceptador de Session Bean (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.

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