Table of Contents

Capítulo 2: Mi primer proyecto OX
Crear un proyecto nuevo
Configurar base de datos
Nuestro primer componente de negocio
La tabla
Ejecutar nuestra aplicación
Automatizando las pruebas
Las etiquetas

Capítulo 2: Mi primer proyecto OX

Crear un proyecto nuevo

Una vez abierto el Eclipse y apuntando al workspace que viene en la distribución de OpenXava.
Usando el asistente de Eclipse apropiado hemos de crear un nuevo proyecto Java llamado Gestion. Ahora tenemos un proyecto Java vacío en el workspace, el siguiente paso es darle la estructura correcta para un proyecto OpenXava.
Vamos al proyecto OpenXavaPlantilla y editamos el archivo CrearNuevoProyecto.xml de esta forma:
<property name="proyecto" value="Gestion" />
Ahora hemos de ejecutar CrearNuevoProyecto.xml usando Ant. Podemos hacerlo con Botón Derecho en CrearNuevoProyecto.xml > Run as > Ant Build
Seleccionamos el proyecto Gestion y pulsamos F5 para refrescar.
Con esto ya tenemos nuestro proyecto listo para empezar a trabajar, pero antes de nada tenemos que tener una base de datos configurada.

Configurar base de datos

OpenXava genera una aplicación Java EE/J2EE pensada para ser desplegada en un servidor de aplicaciones Java (desde la v2.0 las aplicaciones OpenXava también funcionan en un simple servidor de servlets, como Tomcat). Dentro de OpenXava solo se indica el nombre JNDI de la fuente de datos, y en nuestro servidor de aplicaciones tenemos que configurar nosotros esa base datos. El configurar una fuente de datos en un servidor de aplicaciones es algo que va más allá de esta guía, sin embargo a continuación se da las instrucciones concretas para poder realizar este primer proyecto usando el Tomcat incluido en la distribución de OpenXava e Hypersonic como base de datos. Este Tomcat esta en la carpeta openxava-3.x/tomcat.
Con el Tomcat parado editar el archivo context.xml en el directorio de Tomcat conf, en ese archivo tenemos que añadir la siguiente entrada:
<Resource name="jdbc/GestionDS" auth="Container" type="javax.sql.DataSource"
    maxActive="20" maxIdle="5" maxWait="10000"
    username="sa" password="" driverClassName="org.hsqldb.jdbcDriver"
    url="jdbc:hsqldb:hsql://localhost:1666"/>
 
Lo importante aquí es el nombre JNDI, que es a lo único que se hace referencia desde OpenXava, en este caso MiGestionDS. Los atributos driverClassName y url dependen de nuestra base de datos, en este caso estamos usando Hypersonic.

Nuestro primer componente de negocio

Crear un componente de negocio OpenXava es fácil: La definición para cada componente es una clase Java con anotaciones. Para empezar vamos a crear una clase llamada Almacen:
Ahora hemos de editar nuestra nueva clase y escribir el siguiente código:
package org.openxava.gestion.modelo;
 
import javax.persistence.*;
import org.openxava.annotations.*;
 
@Entity
public class Almacen {
 
    @Id @Column(length=3) @Required
    private int codigo;
 
    @Column(length=40) @Required
    private String nombre;
 
    public int getCodigo() {
        return codigo;
    }
 
    public void setCodigo(int codigo) {
        this.codigo = codigo;
    }
 
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
}
 
Esta clase contiene (y contendrá) toda la información necesaria por la aplicación sobre el concepto de negocio de Almacen. En este momento sólo tenemos la estructura de datos, pero en esta clase podemos poner el mapeo contra la base de datos, la lógica de negocio, la presentación visual, el manejo de datos tabulares, etc.
En realidad esta clase es una Entity que sigue el estándar EJB3. Para definir una clase como una entidad lo único que necesitamos es usar la anotación @Entity en la declaración de la clase.
Dentro de entidad vemos definidas un conjunto de propiedades, vamos a examinarlo:
@Id                                  // 1
@Column(length=3)                    // 2
@Required                            // 3
private int codigo;                  // 4
private int getCodigo() {            // 4
    return codigo;
}
private void setCodigo(int codigo) { // 4
    this.codigo = codigo;
}
 
Este es su significado:
  1. @Id: Indica si esta propiedad forma parte de la clave. La clave identifica a cada objeto de forma única y normalmente coincide con la clave en la tabla de base de datos.
  2. @Column(length= ): Longitud de los datos visualizados. Es opcional, pero suele ser útil para hacer mejores interfaces gráficos y generar las tablas de la base de datos.
  3. @Required: Indica si hay que validar la existencia de información en esta propiedad antes de crear o modificar.
  4. La propiedad definida de la forma usual para una clase Java. Todo tipo válido para una propiedad Java se puede poner, lo que incluye tipos integrados, clases del JDK, clases propias, etc.
Las posibilidades de una propiedad van mucho más allá de lo que aquí se muestra, se puede ver una explicación más completa en el capitulo sobre el modelo.

La tabla

Antes de poder probar la aplicación hemos de crear la tabla en la base de datos:

Ejecutar nuestra aplicación

Después de nuestro duro trabajo tenemos derecho a ver el fruto de nuestro sudor, así que allá vamos:
Y ahora podemos jugar con nuestro módulo y ver como funciona.
También puedes desplegar el módulo como portlet JSR-168, de esta forma:

Automatizando las pruebas

Aunque parece que lo más natural es probar la aplicación con un navegador e ir viendo lo mismo que verá el usuario; lo cierto es que es más productivo automatizar las pruebas, de esta forma a medida que nuestro sistema crece, lo tenemos atado y evitamos que al avanzar rompamos lo que ya teníamos.
OpenXava usa un sistema de pruebas basado en JUnit y HttpUnit. Las pruebas JUnit de OpenXava emulan el funcionamiento de un usuario real con un navegador, de esta forma podemos replicar de forma exacta las mismas pruebas que haríamos nosotros mismos con un navegador. La ventaja de este enfoque es que probamos de forma sencilla desde el interfaz gráfico al acceso a la base de datos.
Si probáramos el modulito manualmente normalmente crearíamos un registro nuevo, lo buscaríamos, lo modificaríamos y lo borraríamos. Vamos a hacer eso automáticamente.
En primer lugar crearemos un paquete en donde poner las pruebas, org.openxava.gestion.pruebas, y en este paquete pondremos una clase llamada PruebaAlmacen, y pegaremos en ella el siguiente código:
package org.openxava.gestion.pruebas;
 
import org.openxava.tests.*;
 
/**
 * @author Javier Paniza
 */
 
public class PruebaAlmacen extends ModuleTestBase {
 
    public PruebaAlmacen(String testName) {
        super(testName, "Gestion", "Almacen");    // 1
    }
 
    public void testCrearLeerModificarBorrar() throws Exception {
        // Creamos
        execute("CRUD.new");                      // 2
        setValue("codigo", "7");                  // 3
        setValue("nombre", "Almacen JUNIT");
        execute("CRUD.save");
        assertNoErrors();                         // 4
        assertValue("codigo", "");                // 5
        assertValue("nombre", "");
 
        // Leeemos
        setValue("codigo", "7");
        execute("CRUD.search");
        assertValue("codigo", "7");
        assertValue("nombre", "Almacen JUNIT");
 
        // Modificamos
        setValue("nombre", "Almacen JUNIT MODIFICADO");
        execute("CRUD.save");
        assertNoErrors();
        assertValue("codigo", "");
        assertValue("nombre", "");
 
        // Comprobamos modificado
        setValue("codigo", "7");
        execute("CRUD.search");
        assertValue("codigo", "7");
        assertValue("nombre", "Almacen JUNIT MODIFICADO");
 
        // Borramos
        execute("CRUD.delete");
        assertMessage("Almacen borrado satisfactoriamente"); // 6
    }
 
}
Podemos aprender de este ejemplo:
  1. Constructor: En el constructor indicamos el nombre de la aplicación y el nombre del módulo.
  2. execute: Permite simular la pulsación de un botón o vínculo. Como argumento se envía el nombre de la acción; los nombres de las acciones los podemos ver en OpenXava/xava/default-controllers.xml (los controladores predefinidos) y Gestion/xava/controladores.xml (los propios). También si paseamos el ratón sobre el vínculo el navegador nos mostrará la acción JavaScript a ejecutar, que contiene el nombre de acción OpenXava. Es decir execute(“CRUD.new”) es como pulsar el botón de nuevo en la interfaz gráfica.
  3. setValue: Para asignar valor a un control del formulario. Es decir, setValue(“nombre”, “Pepe”) tiene el mismo efecto que teclear en el campo de texto 'Pepe'. Los valores siempre son alfanuméricos, ya que se asignan a un formulario HTML.
  4. assertNoErrors: Comprueba que no se hayan producido errores. En la interfaz gráfica los errores son mensajes en color rojo, que son añadidos por la lógica de la aplicación.
  5. assertValue: Comprueba que el valor contenido en un elemento del formulario es el indicado.
  6. assertMessage: Verifica que la aplicación ha producido el mensaje informativo indicado.
Se puede ver como de forma sencilla podemos probar que el mantenimiento funciona, escribir un código como este puede costar 5 minutos, pero a la larga ahorra horas de trabajo, porque a partir de ahora podemos probarlo todo en 1 segundo, y porque nos va a avisar a tiempo cuando rompamos la gestión de Almacenes tocando otra cosa.
Para más detalle podemos ver el API JavaDoc de org.openxava.tests.ModuleTestBase y examinar los ejemplos que hay en org.openxava.test.tests de OpenXavaTest.
Por defecto la prueba se ejecuta contra el módulo en modo solitario (fuera del portal) (es decir desplegado con desplegarWar). Pero si lo deseamos es posible testear contra la versión de portlet (es decir desplegado con generarPortlets). Solo necesitamos editar el archivo properties/xava-junit.properties y escribir:
liferay.url=web/guest
Esto para probar contra el portal Liferay. También es posible probar contra el portal JetSpeed2, mira en OpenXavaTest/properties/xava-junit.properties para ver cómo.

Las etiquetas

Ya nos funciona, pero hay un pequeño detalle que se ha quedado suelto. Posiblemente queramos definir las etiquetas que se mostrarán al usuario. La forma de hacerlo es escribiendo un archivo con todas las etiquetas, y así podemos traducir nuestro producto a otro idioma con facilidad.
Para definir las etiqueta solo tenemos que editar el archivo EtiquetasGestion_es.properties en la carpeta i18n. Editar ese archivo y añadir:
Almacen=Almacén
No es necesario poner todas las propiedades, porque los casos más comunes (codigo, nombre, descripcion y un largo etc) ya los tiene OpenXava incluidos en Español, Inglés, Polaco, Alemán, Francés, Indonesio y Catalán.
Si queremos una versión en otro idioma (inglés, por ejemplo) solo tenemos que copiar y pegar con el sufijo apropiado. Por ejemplo, podemos tener un EtiquetasGestion_en.properties con el siguiente contenido:
Almacen=Warehouse
Las etiquetas y mensaje por defecto de OpenXava están en OpenXava/i18na/Labels.properties y OpenXava/i18n/Messages.properties. Si queremos sobreescribir algunos de estos recursos no necesitamos editar estos archivos, sino que podemos usar los mismos nombres de clave en los archivos de recursos de nuestro proyecto, entonces nuestras etiqueta y mensajes seran usadas en vez de las estándar de OpenXava (nuevo en v2.0.3). Por ejemplo, si queremos cambiar el mensaje estandar en modo lista ''Hay 23663 registros en la lista” por otro, hemos de añadir a MensajesGestion_es.properties esta entrada:
# list_count está en Messages_en.properties de OpenXava, este es un ejemplo
# de sobreescritura de un mensaje  estándar de OpenXava
list_count=Hay {0} objetos en la lista
Ahora, nuestra aplicación mostrará “Hay 23663 objetos en la lista” en vez del mensaje por defecto de OpenXava “'Hay 23663 registros en la lista”.
Para saber más sobre como definir las etiquetas de nuestros elementos OpenXava podemos echar un vistazo a los archivos de OpenXavaTest/i18n.