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:

Currently, the Web Beans RI only runs on JBoss Application Server 5. You'll need to download JBoss AS 5.0.1.GA from jboss.org, and unzip it. For example:

$ cd /Applications
$ unzip ~/jboss-5.0.1.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.1.GA

Nota

A new deployer, webbeans.deployer is added to JBoss AS. This adds supports for Web Bean archives to JBoss AS, and allows the Web Beans RI to query the EJB3 container and discover which EJBs are installed in your application.

Web Beans is bundled with JBoss AS 5.1 and above.

To install Web Beans, you'll need Ant 1.7.0 installed, and the ANT_HOME environment variable set. For example:

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

Then, you can install the update. The update script will use Maven to download Web Beans automatically.

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

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.

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.

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.

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.