Trinidad

RECU-0135 (Recurso Referencia)

Descripción

Apache Trinidad es una librería de componentes JavaServer Faces. Esta librería es un subproyecto de Apache MyFaces. Oracle donó los componentes ADF Faces a Apache, quien los introdujo al proyecto Apache MyFaces.

El proyecto Apache MyFaces contiene varios subproyectos relacionados con la tecnología JavaServer. Apache MyFaces provee los siguientes elementos:

  • Una implementación JavaServer Faces (MyFaces API, MyFaces implement modules).
  • Contiene varias librerías de componentes “widgets UI” para construir aplicaciones web con JSF (ej. MyFaces Tomahawk, MyFaces Trinidad, MyFaces Tobago).
  • Paquetes de extensiones para JavaServer Faces (ej. MyFaces Orchestra).
  • Módulos de integración para otras tecnologías y estándares (ej. MyFaces Portlet Bridge para la integración con portlet-estándar).

Renderización parcial de la página (PPR)

AJAX es la técnica más usada en aplicaciones web a día de hoy. Trinidad permite una construcción sencilla basada en componentes AJAX y ofrece muchas formas de atender peticiones, tanto de AJAX como de componentes no AJAX.

PartialSubmit - PartialTriggers

Vamos a realizar un ejemplo sencillo con partialSubmit y los componentes de Trinidad "commandbutton" y "command link", el evento lanzado por estos componentes será interpretado como un evento AJAX.

Primero se enviará una notificación al servidor que no realizará ninguna modificación en la página. Para hacer esto se necesita comunicar qué parte de la página debe de recargarse. La manera más fácil de hacer eso es mediante el uso partialTriggers, que conecta componentes que deben de ser recargados con los componentes que son la razón para la recarga.

<tr:commandButton text="Do Something"
                       id="myButton"
                       partialSubmit="true"
                       actionListener="#{myBean.doSomething}"/>

  <-- repaint the outputText any time 'myButton' has an event -->
  <tr:outputText value="#{myBean.textValue}"
                    partialTriggers="myButton"/>


public void doSomething(ActionEvent event)
{
  // Change the text value
  this.textValue = "A new value";
}

  <tr:commandButton text="Do Something"
                       id="myButton"
                       partialSubmit="true"
                       partialTriggers="myButton"
                       actionListener="#{myBean.doSomething}"/>

  <-- repaint the outputText any time 'myButton' has an event -->
  <tr:outputText value="#{myBean.textValue}"
                    partialTriggers="myButton"/>


public void doSomething(ActionEvent event)
{
  ((CoreCommandButton) event.getSource()).setDisabled(true);
  // Change the text value
  this.textValue = "A new value";
}

Limitaciones de la Renderización parcial de la página

Una de las limitaciones más importantes en el uso de la PPR es que no puede usarse para modificar directamente la propiedad "rendered" de un componente.

AutoSubmit

Un uso común de PPR es el atributo autoSubmit. Este atributo es soportado en todos los componentes de entrada y devuelve el valor de los campos ante cualquier petición de tipo AJAX. Para minimizar las comunicaciones, en el caso de introducir texto, solo se lanza el autoSubmit cuando se sale del componente.

En el siguiente ejemplo, un botón se activa automáticamente cuando la cantidad es mayor que cero:

<tr:inputText value="#{myBean.quantity}" autoSubmit="true"
                   id="quantity"/>

  <tr:commandButton text="Put One Back"
                       disabled="#{myBean.quantity le 0}"
                       partialTriggers="quantity"
                       actionListener="#{myBean.putOneBack}"/>

Usando el ContextRequest

No siempre es conveniente identificar un componente mediante el empleo de partialTriggers, como en los siguientes casos:

  • No se conoce qué componente necesita recargarse hasta que se procese en el servidor.
  • Solo se actualiza un componente en determinados casos, no siempre se actualiza el componente.

Para estos casos, se puede programar la recarga de un componente a través de RequestContext.addPartialTarget():

if (_needToRepaint())
  {
    // Repaint another component programatically
    RequestContext rc = RequestContext.getCurrentInstance();
    rc.addPartialTarget(anotherComponent);
  }
  if (_needToRepaintAParticularRow())
  {
   
    RequestContext rc = RequestContext.getCurrentInstance();
    Object oldRowKey = table.getRowKey();
    table.setRowIndex(rowToRepaint);
    rc.addPartialTarget(componentWithinRow);
   
    table.setRowKey(oldRowKey);
  }

Comunicaciones entre páginas

Uno de los aspectos más importantes es la comunicación de valores entre páginas. El valor a comunicar puede almacenarse en la petición o en la sesión. Ambas posibilidades funcionan pero son muy limitadas. Apache Trinidad introduce un nuevo ámbito denominado pageFlowScope que ofrece mejores prestaciones

pageFlowScope

Ademas de los ámbitos proporcionados por JSF (applicationScope, sessionScope, y requestScope), Trinidad añade un ámbito (pageFlowScope). Los valores añadidos a este ambito están disponibles mientras se continua la navegación entre páginas:

<h:outputText value="#{pageFlowScope.someKey}"/>

Limitaciones de pageFlowScope

El uso de pageFlowScope tiene una serie de limitaciones. Al no ser pageFlowScope parte de la especificación JSF estándar, no se soportan los siguientes aspectos:

  • Las expresiones EL no buscan automáticamente en pageFlowScope, si desea localizar un valor incluido en pageFlowScope, es necesario incluir el prefijo "pageFlowScope" (Por ejemplo, en lugar de incluir #{empleado} habría que incluir #{pageFlowScope.empleado}.
  • pageFlowScope no puede ser utilizado como un <managed-bean-scope>. (Pero el <valor> de un <managed-property> puede hacer referencia a los valores de pageFlowScope).

Además de esto, las páginas deben ponerse de acuerdo sobre el nombre de la variable incluida en pageFlowScope, lo que aumenta el acoplamiento.

Por último, pageFlowScope nunca se vacía a sí mismo, la única manera de limpiar pageFlowScope es forzarlo manualmente.

Uso de tr:setActionListener

Trinidad ofrece una nueva etiqueta ActionListener nueva que permite transmitir información de una variable a otra sin necesidad de código java subyacente. La etiqueta <tr:setActionListener> tiene dos propiedades, "from" y "to", y simplemente toma un valor del atributo indicado como "from" y lo copia en el atributo indicado como "to".

Modelo de tabla

El componente tabla se utiliza para mostrar una lista de datos estructurados. Por ejemplo, si tenemos una estructura de datos llamada Persona que tiene dos propiedades, Nombre y Apellidos, podríamos utilizar una tabla con dos columnas - una para el nombre y otra para el apellido - para mostrar una lista de objetos Persona.

El componente de tabla es similar al componente UIData estándar en JSF, pero incluye una serie de características adicionales, como el apoyo para la identificación de las filas por clave (en lugar de por el índice), soporte integrado para la paginación a través de modelos de gran tamaño, clasificación del modelo, y selección de elementos únicos o múltiples en el modelo

Componente Tabla

El componente Apache Trinidad utiliza un modelo para acceder a los datos en la lista subyacente. La clase de modelo específico es org.apache.myfaces.trinidad.model.CollectionModel. También puede utilizar otras instancias de modelo, por ejemplo, java.util.List, matriz, y javax.faces.model.DataModel. La tabla se convertirá automáticamente en la instancia en un CollectionModel.

Para acceder a una fila en particular en la lista, en primer lugar es necesario que dicha fila sea la fila actual y luego hay que emplear el método getRowData () (método de la tabla). Para convertir una fila en la fila actual, se empleará el métodosetRowIndex() (en la tabla) con el índice adecuado. Alternativamente, también se puede emplear el método setRowKey() con el rowKey apropiado.

Para obtener el número total de filas en la lista se emplea el método getRowCount () . En el caso de que el modelo todavía no sepa el número total de filas que están disponibles, getRowCount() devolverá el valor -1.

El objeto tabla dispone de un método isRowAvailable () que devuelve "true" si la fila actual está disponible. Este método es especialmente útil cuando el número total de filas es desconocido.

Columnas

Los hijos inmediatos de un componente tabla deben ser todos componentes <tr:column>. Cada componente visible del tipo ADF Column crea una columna separada en la tabla.

Encabezados

La etiqueta f:facet se emplea para crear el encabezado de la columna. También puede usarse el atributo "headerText" para establecer el encabezado de la columna. El ejemplo siguiente crea una tabla de dos columnas con los encabezados de columna - "Nombre" y "Apellidos":

<tr:table> 
   <tr:column>
     <f:facet name="header">
       <tr:outputText value="Nombre"/>
     </ f: facet>
     ...
   </ tr: column>
   <tr:

Ejemplos

Aplicación de Ejemplo En este apartado haremos una aplicación que mostrará una de las características de la librería Apache Trinidad. La idea es mostrar las capacidades AJAX de esta librería por lo que el ejemplo hará uso de la "Renderización Parcial de Página".

El ejemplo será muy sencillo, compuesto por dos campos de formulario (uno de entrada y otro de salida), de forma que el usuario introduce un valor en el primer campo y cuando éste pierde el foco (por ejemplo cuando el usuario pulsa el tabulador) el contenido es enviado al servidor, procesado (en concreto pasado a mayúsculas) y devuelto al cliente para que se rellene el segundo campo.

Diseño de las Páginas JSP

Puesto que Apache Trinidad es una librería de etiquetas AJAX, para aplicaciones complejas es necesario trabajar con documentos JSP. Los documentos JSP son una variante de las páginas JSP en la que los documentos se forman como archivos XML que deben estar bien formados. Si nuestras páginas JSP son documentos XML bien formados, el renderizador podrá construir un árbol DOM correcto y podrá aplicar AJAX con facilidad.

Un documento JSP se caracteriza por tener extensión .jspx e incluir código XML en su interior. Puesto que no podemos incluir directivas jsp la forma de incluir una librería de etiquetas es la siguiente:

<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:trh="http://myfaces.apache.org/trinidad/html"
                xmlns:tr="http://myfaces.apache.org/trinidad">
          <!-- Contenido -->
     </jsp:root>

Nuestro ejemplo estará formado por un único documento JSP, llamado ejemplo.jspx, que tendrá el siguiente código fuente:

<?xml version="1.0" encoding="UTF-8"?>
     <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:trh="http://myfaces.apache.org/trinidad/html"
                xmlns:tr="http://myfaces.apache.org/trinidad">
          <jsp:directive.page contentType="text/html;charset=utf-8"/>
          <link rel="stylesheet" type="text/css" href="/servicios/madeja/css/estilos.css" />
          <f:loadBundle basename="org.javacenter.jsf.Mensajes" var="msg"/>
          <f:view>
              <h1> <h:outputText value="#{msg.tituloPrueba}"/> </h1>
           <p> Fecha de Carga: <h:outputText value="#{bean.fecha}"/> </p>
           <tr:document title="Ejemplo de Renderización Parcial de Página">
                  <tr:form>
                      <tr:panelPage>
                          <tr:panelHeader text="Bienvenido a la Página de
     Ejemplos de Apache Trinidad">
                              <tr:panelGroupLayout layout="horizontal">
        <tr:panelHeader text="Escribe algo en el campo de texto y pulsa el
     tabulador.">
            <tr:inputText value="#{bean.nombre}" autoSubmit="true"
                          id="campoTexto1"/>
        </tr:panelHeader>
                              </tr:panelGroupLayout>
                              <tr:panelGroupLayout layout="horizontal">
        <tr:panelHeader text="Aquí aparecerá la cadena insertada pasada a
     mayúsculas.">
            <tr:inputText id="campoTexto2" disabled="true"
                    value="#{bean.nombre}" partialTriggers="campoTexto1"/>
        </tr:panelHeader>
                              </tr:panelGroupLayout>
                          </tr:panelHeader>
                      </tr:panelPage>
                  </tr:form>
              </tr:document>
          </f:view>
     </jsp:root>

Lo más destacable son los dos campos inputText, ambos asociados al campo "nombre" del bean. El primero de ellos tiene el atributo autoSubmit="true" lo que indica que cuando cambie y pierda el foco, el formulario será enviado mediante AJAX al servidor. El segundo campo tiene el atributo partialTriggers="campoTexto1" que indica que cuando se envíe el formulario con id igual a "campoTexto1" se actualice también este campo.

También hemos incluido un fichero de mensajes, cuyo contenido es el siguiente: titulo=Ejemplo de Renderización Parcial con Apache Trinidad tituloPrueba=Ejemplo de Renderización Parcial de Página

Implementación del Bean

El código del bean es muy simple. Su código es el siguiente:

package org.javacenter.jsf;
   import java.util.Date;
   public class Bean {
        private String nombre = "";
        public String getNombre() {
            return nombre.toUpperCase();
        }
        public void setNombre(String nombre) {
            this.nombre = nombre;
        }
        public String getFecha() {
            return new Date().toString();
        }
   }

Como podemos observar, el bean no tiene nada en especial. Simplemente tiene un atributo nombre con su correspondiente método setter y getter y un método getFecha() que permitirá al documento JSP acceder a un atributo no existente llamado fecha.

Configuración

La configuración del fichero web.xml debe hacerse tal y como se muestra. Podemos ver un ejemplo a continuación:

<?xml version="1.0" encoding="UTF-8"?>
   <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                            http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <context-param>
            <param-name>com.sun.faces.verifyObjects</param-name>
            <param-value>false</param-value>
        </context-param>
        <context-param>
            <param-name>com.sun.faces.validateXml</param-name>
            <param-value>true</param-value>
        </context-param>
        <context-param>
            <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
            <param-value>client</param-value>
        </context-param>
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>/faces/*</url-pattern>
        </servlet-mapping>
        <session-config>
            <session-timeout>30</session-timeout>
        </session-config>
        <filter>
            <filter-name>trinidad</filter-name>
            <filter-class>
                org.apache.myfaces.trinidad.webapp.TrinidadFilter
            </filter-class>
        </filter>
        <filter-mapping>
            <filter-name>trinidad</filter-name>
            <servlet-name>Faces Servlet</servlet-name>
        </filter-mapping>
        <servlet>
            <servlet-name>resources</servlet-name>
            <servlet-class>
                org.apache.myfaces.trinidad.webapp.ResourceServlet
            </servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>resources</servlet-name>
            <url-pattern>/adf/*</url-pattern>
        </servlet-mapping>
   </web-app>

Ahora debemos configurar JSF para añadir el render kit de Apache Trinidad y poner el bean dentro del alcance de los documentos JSP. Para ello escribiremos lo siguiente:

<?xml version='1.0' encoding='UTF-8'?>
   <!DOCTYPE faces-config PUBLIC
   "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
   "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
   <faces-config>
        <application>
            <default-render-kit-id>
                 org.apache.myfaces.trinidad.core
            </default-render-kit-id>
        </application>
        <managed-bean>
            <managed-bean-name>bean</managed-bean-name>
            <managed-bean-class> org.javacenter.jsf.Bean </managed-bean-class>
            <managed-bean-scope> request </managed-bean-scope>
        </managed-bean>
   </faces-config>