SeamFramework.orgCommunity Documentation

Capítulo 3. La implementación de referencia de Web Beans

3.1. El ejemplo numberguess
3.2. Ejemplo de traductor

La implementación de referencia (IR) de Web Beans se desarrolla en the Seam project. La última versión de Web Beans se puede descargar desde the downloads page.

La IR de Web Beans viene con dos ejemplos de aplicaciones de despliegue: webbeans-numberguess, un ejemplo WAR, que contiene sólo beans sencillos y un ejemplo EAR webbeans-translator que contiene beans empresariales. Para ejecutar los ejemplos necesitará lo siguiente:

Actualmente, la IR de Web Beans sólo se ejecuta en JBoss Application Server 5. Necesitará descargar JBoss AS 5.0.0.GA desde jboss.org, y descomprimirlo. Por ejemplo:

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

Luego, descargue la IR de Web Beans desde seamframework.org, y descomprímalo. Por ejemplo:

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

Después necesitaremos decirle a Web Beans en dónde está localizado JBoss. Editar jboss-as/build.properties y establecer la propiedad jboss.home. Por ejemplo:

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

Como Web Beans es una nueva parte de software, necesitaremos actualizar JBoss AS para ejecutar la IR de Web Beans. Versiones futuras de JBOSS AS incluirán dichas actualizaciones, y este paso no será necesario.

Nota

Actualmente, se necesitan dos actualizaciones. Primero, se agrega el nuevo desarrollador, webbeans.deployer. Así se agrega soporte para los archivos de Web Bean a JBoss AS, y permite a la IR de Web Beans solicitar el contenedor EJB3 y descubrir cuáles EJB están instalados en su aplicación. En segundo lugar se necesita una actualización de JBoss EJB3.

Para instalar la actualización, necesitaremos que Ant 1.7.0 esté instalado, y que la variable de entorno ANT_HOME esté configurada. Por ejemplo:

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

Luego, puede instalar la actualización. La actualización utiliza Maven para descargar automáticamente el Web Beans y EJB3.

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

Ahora, ¡está listo para desplegar su primer ejemplo!

Sugerencia

Los scripts creados para los ejemplos ofrecen una cantidad de objetivos, a saber:

  • ant restart - despliega el ejemplo en formato explotado

  • ant explode - actualiza un ejemplo explotado, sin reiniciar el despliegue

  • ant deploy - despliega el ejemplo en formato JAR comprimido

  • ant undeploy - quita el ejemplo del servidor

  • ant clean - borra el ejemplo

Para desplegar el ejemplo numberguess:

$ cd examples/numberguess
ant deploy

Start JBoss AS:

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

Sugerencia

If you use Windows, use the run.batscript.

Espere que despliegue la aplicación, y diviértase en http://localhost:8080/webbeans-numberguess!

La IR de Web Beans incluye un segundo ejemplo que traducirá su texto en Latín. El ejemplo numberguess es un ejemplo WAR, y sólo utiliza beans sencillos; el ejemplo de traductor es un ejemplo EAR e incluye beans empresariales, empaquetados en un módulo EJB. Para probar:

$ cd examples/translator
ant deploy

Espere a que despliegue la aplicación, y ¡visite http://localhost:8080/webbeans-translator!

En la aplicación numberguess se le dan 10 intentos para adivinar un número entre 1 y 100. Después de cada intento, se le dirá si es mayor o menor a su número.

El ejemplo de numberguess consta de una cantidad de Web Beans, archivos de configuración y páginas Facelet JSF, empaquetadas como WAR. Empecemos con los archivos de configuración.

Todos los archivos de configuración para este ejemplo están localizados en WEB-INF/, el cual está almacenado en WebContent en el árbol fuente. Primero, tenemos faces-config.xml, en donde le pedimos a JSF que utilice 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
>

Hay un archivo web-beans.xml vacío, el cual marca esta aplicación como una aplicación de Web Beans.

Por último, está web.xml:

Observemos una vista de Facelet:

<!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
>Adivine un número...</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)>
             Estoy pensando un número entre #{game.smallest} y #{game.biggest}.
             Le quedan #{game.remainingGuesses} de intentos.
          </div>
     
          <div>
             S(4)u número: 
             <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 es un lenguaje de plantilla para JSF, aquí se delimita la página en una plantilla que define el encabezado.

2

Hay una cantidad de mensajes que pueden ser enviados al usuario, "Mayor!", "Menor!" y "Correcto!"

3

Mientras el usuario adivina, el rango de números que puede adivinar se vuelve cada vez más pequeño-esta oración cambia para estar seguros de que el usuario sabe en qué rango debe adivinar.

4

Este campo de entrada está vinculado a un Web Bean, utilizando la expresión de valor.

5

Un rango de validador se utiliza para garantizar que el usuario por accidente no entre un número fuera del rango en el que se puede adivinar - si el validador no estuviera aquí, el usuario podría tratar de adivinar fuera del rango.

6

Y, obviamente, debe haber una forma para que el usuario pueda enviar el número al servidor. Aquí nos vincularnos a un método de acción en el Web Bean.

El ejemplo existe de 4 clases, las primeras dos son tipos de enlace. Primero, hay un tipo de enlace @Random, utilizado para inyectar un número aleatorio:

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

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

También hay un tipo de enlace @MaxNumber, utilizado para inyectar el número máximo posible:

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

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

La clase Generator es responsable de crear el número aleatorio, a través de un método de productor. También expone el número máximo posible a través del método de productor:

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

Notará que el Generador es una aplicación en ámbito por lo tanto no obtenemos un número aleatorio diferente cada vez.

El Web Bean final en la aplicación es la sesión en ámbito Juego.

Notará que hemos utilizado la anotación @Named, para poder utilizar el bean a través de EL en la página JSF. Por último, hemos utilizado la inyección de constructor para inicializar el juego con un número aleatorio. Y, claro está, necesitamos decirle al jugador cuando haya ganado, por lo tanto le damos retroalimentación con 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
>(){});
   }
   
}

El ejemplo de traductor tomará las oraciones que entre y las traducirá en Latín.

El ejemplo de traductor está incorporado como un EAR, y contiene EJB. Como resultado, su estructura es más compleja que el ejemplo de Numberguess.

Primero, demos una mirada al agregador EAR, el cual está localizado en el módulo webbeans-translator-ear. Maven genera automáticamente la application.xml:


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

Aquí establecemos la ruta de contexto, la cual nos da una url interesante (http://localhost:8080/webbeans-translator).

Sugerencia

Si no está utilizando Maven para generar estos archivos, usted necesitaría 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
>Ejemplo Ear para la implementaci�n de referencia de 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
>

Ahora veamos al WAR. Al igual que el ejemplo de Numberguess, tenemos un faces-config.xml (para Facelets habilitadas) y un web.xml (para habilitar a JSF) en WebContent/WEB-INF.

Más interesante aún es el facelet utilizado para traducir texto. Al igual que en el ejemplo de Numberguess tenemos una plantilla, la cual rodea el formulario (omitido aquí por razones de brevedad):


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

El usuario puede entrar texto en el área de texto a mano izquierda y pulsar el botón de traducir para ver el resultado a la derecha.

Por último, veamos el módulo EJB, webbeans-translator-ejb. En src/main/resources/META-INF sólo hay un web-beans.xml vacío, utilizado para marcar el archivo como si contuviera Web Beans.

Hemos guardado la parte más interesante para el final, ¡el código! El proyecto tiene dos beans sencillos, SentenceParser y TextTranslator y dos beans empresariales, TranslatorControllerBean y SentenceTranslator. Por ahora, debe comenzar a familiarizarse con el aspecto de Web Bean, por lo tanto sólo destacaremos aquí las partes más interesantes.

Tanto SentenceParser como TextTranslator son beans dependientes, y TextTranslator utiliza inicialización de constructor:

public class TextTranslator { 

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

TextTranslator es un bean con estado (con una interfaz local de negocios), donde lo mágico sucede - claro está, que no desarrollaramos un traductor completo, ¡pero le dimos una buena luz!

Por último, hay un controlador orientado a UI que recoge el texto desde el usuario y lo envía al traductor. Esta es una petición en ámbito, llamada bean con estado de sesión que inyecta el traductor.

@Stateful

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

El bean también tiene capturadores y configuradores para todos los campos en la página.

Como este es un bean de sesión con estado, tenemos que tener un método de eliminación:

   @Remove

   public void remove()
   {
      
   }

El administrador de Web Beans llamará al método de eliminación cuando el bean sea destruido, en este caso al final de la petición.

Aquí termina nuestro corto recorrido por los ejemplos de la IR de Web Beans. Para mayor información acerca de la IR o ayuda, por favor consulte http://www.seamframework.org/WebBeans/Development.

Necesitamos ayuda en todas las áreas - corrección de errores, escritura de nuevas funciones, escritura de ejemplos y traducción de esta guía de referencia.