OpenXava-Manual.pdf

download OpenXava-Manual.pdf

of 115

Transcript of OpenXava-Manual.pdf

  • 5/24/2018 OpenXava-Manual.pdf

    1/115

    OpenXava Manual

    Mauro Miguel Melo

  • 5/24/2018 OpenXava-Manual.pdf

    2/115

    CONTENIDO

    Captulo 2: Mi primer proyecto OX..........................................................6Crear un proyecto nuevo ....................................................................7Configurar base de datos....................................................................7Nuestro primer componente de negocio ...............................................7La tabla............................................................................................9Ejecutar nuestra aplicacin ...............................................................10Automatizando las pruebas...............................................................10Las etiquetas ..................................................................................13

    Captulo 3: Modelo .............................................................................14Componente de negocio ...................................................................15

    Entidad ..........................................................................................15Propiedades....................................................................................16

    Estereotipo ..................................................................................18Estereotipo GALERIA_IMAGENES ....................................................19Concurrencia y propiedad versin ...................................................20Enums.........................................................................................21Propiedades calculadas..................................................................21Calculador valor por defecto...........................................................23Valores por defecto al crear ...........................................................27Validador de propiedad..................................................................28

    Validador por defecto (nuevo en v2.0.3)..........................................30Referencias.....................................................................................30Calculador valor por defecto en referencias......................................32Usar referencias como clave...........................................................33

    Colecciones.....................................................................................34Mtodos .........................................................................................37Buscadores.....................................................................................37Validador de entidad........................................................................38Validador al borrar...........................................................................41Mtodos de retrollamada de JPA........................................................43Clases incrustables (Embeddable)......................................................43

    Referencias incrustadas.................................................................44Colecciones incrustadas.................................................................46

    Herencia.........................................................................................50Clave mltiple.................................................................................53

    Clase id .......................................................................................53Id inscrustado ..............................................................................56

    Hibernate Validator (nuevo en v3.0.1) ...............................................57Captulo 5: Datos tabulares .................................................................58

    Propiedades iniciales y resaltar filas...................................................59Filtros y condicin base ....................................................................60

  • 5/24/2018 OpenXava-Manual.pdf

    3/115

    Select ntegro .................................................................................63Orden por defecto ...........................................................................64

    Captulo 6: Mapeo objeto/relacional......................................................64Mapeo de entidad ............................................................................64Mapeo propiedad.............................................................................65Mapeo de referencia ........................................................................65Mapeo de coleccin..........................................................................66Mapeo de referencia incrustada .........................................................66Conversin de tipo...........................................................................66

    Conversin de propiedad ...............................................................67Conversin con multiples columnas.................................................69Conversin de referencia ...............................................................73

    Captulo 7: Controladores....................................................................75

    Variable de entorno .........................................................................75Objectos de sesin ..........................................................................76El controlador y sus acciones ............................................................77Herencia de controladores ................................................................82Acciones en modo lista.....................................................................82Sobreescribir bsqueda por defecto ...................................................85Inicializando un mdulo con una accin..............................................87Llamar a otro mdulo.......................................................................88Cambiar el modelo de la vista actual..................................................91Ir a una pgina JSP .........................................................................92

    Generar un informe propio con JasperReports .....................................93Cargar y procesar un fichero desde el cliente (formulario multipart).......95Sobreescribir los controladores por defecto (nuevo en v2.0.3) ..............97Todos los tipos de acciones...............................................................98

    Captulo 8: Aplicacin .........................................................................99Un mdulo tpico ...........................................................................101Mdulos por defecto (nuevo en v2.2.2) ............................................101Mdulo con solo detalle .................................................................. 102Mdulo con solo lista...................................................................... 103Mdulo de documentacin .............................................................. 103Mdulo de solo lectura ................................................................... 103

    Table of Contents .............................................................................104Captulo 9: Personalizacin................................................................ 104

    Editores .......................................................................................104Configuracin de editores ............................................................ 104Editores para valores mltiples..................................................... 108Editores personalizables y estereotipos para crear combos............... 110

    Vistas JSP propias y taglibs de OpenXava .........................................112Ejemplo.....................................................................................112xava:editor ................................................................................114xava:action, xava:link, xava:image, xava:button............................ 114

  • 5/24/2018 OpenXava-Manual.pdf

    4/115

    xava:message (nuevo en v2.0.3) .................................................115xava:descriptionsList (nuevo en v2.0.3) ........................................ 115

  • 5/24/2018 OpenXava-Manual.pdf

    5/115

    Captulo 1: Visin general

    Presentacin

    OpenXava es un marco de trabajo para desarrollar aplicaciones JavaEE/J2EErpida y fcilmente. La filosofa subyacente es definir con anotaciones deJava o con XML y programar con Java, pero cuanto ms definimos y menosprogramamos mejor. El objetivo principal es hacer que las cosas ms tpicasen una aplicacin de gestin sean fciles de hacer, mientras que ofrecemosla flexibilidad suficiente para desarrollar las funciones ms avanzadas yespecificas.A continuacin se echa un vistazo a algunos conceptos bsico de OpenXava.

    Componente de negocio

    Las piezas fundamentales para crear una aplicacin OpenXava son loscomponentes, en el contexto de OpenXava un componente de negocio esuna clase Java (aunque existe tambin una versin XML) que contiene todala informacin necesaria sobre un concepto de negocio para poder crearaplicaciones sobre eso. Es decir toda la informacin que el sistema ha desaber sobre el concepto de factura se define en un archivo Factura.java. Enun componente de negocio se define: La estructura de datos.

    Las validaciones, clculos y en general toda la lgica de negocio asociadaa ese concepto. Las posibles vista, esto es, la configuracin de todos las posibles

    interfaces grficas para este componente. Se define las posibilidades para la presentacin tabular de los datos. Esto

    se usa para el modo lista (consultar y navegar por los datos), los listados,exportacin a excel, etc.

    Mapeo objeto-relacional, lo que incluye informacin sobre las tablas de labase de datos y la forma de convertir a objetos la informacin que enellas hay.

    Esta forma de dividir es ideal para el trabajo en grupo, y permite desarrollarun conjunto de componentes interproyecto.

    Controladores

    Los componentes de negocio no definen lo que un usuario puede hacer conla aplicacin; esto se define con los controladores. Los controladores estnen el archivoxava/controladores.xmlde cada proyecto; adems OpenXavatiene un conjunto de controladores predefinidos en OpenXava/xava/default-controllers.xml.Un controlador es un conjunto de acciones. Una accin es un botn o vnculo

    que el usuario puede pulsar. Los controladores estn separados de los

  • 5/24/2018 OpenXava-Manual.pdf

    6/115

    componentes de negocio porque un mismo controlador puede ser asignado adiferentes componentes de negocio. Por ejemplo, un controlador para hacerun mantenimiento, imprimir en PDF, o exportar a archivos planos, etc.puede ser usado y reusado para facturas, clientes, proveedores, etc.

    Aplicacin

    Una aplicacin OpenXava es un conjunto de mdulos. Un mdulo une uncomponente de negocio con uno o ms controladores. Cada mdulo de laaplicacin es lo que al final utiliza el usuario, y generalmente se configuracomo un portlet dentro de un portal.

    Estructura de un proyecto

    Un proyecto OpenXava tpico suele contener las siguientes carpetas:

    [raiz]:En la raz del proyecto nos encontraremos el build.xml (con las tareas

    Ant). src[carpeta fuente]:

    contiene el cdigo fuente Java escrito por nosotros. xava:

    Los archivos XML para configurar nuestras aplicaciones OpenXava. Losprincipales son aplicacion.xmlycontroladores.xml. i18n:

    Archivos de recursos con las etiquetas y mensajes en varios idiomas. properties[carpeta fuente]:

    Archivos de propiedades para configurar nuestro aplicacin. data:

    til para guardar los scripts para crear las tablas de nuestra aplicacin,si aplicara. web:

    Contenido de la parte web. Normalmente archivos JSP, lib y classes. La

    mayora del contenido es puesto automticamente, pero es posible poneraqu nuestros propios archivos JSP.

    Captulo 2: Mi primer proyecto OX

  • 5/24/2018 OpenXava-Manual.pdf

    7/115

    Crear un proyecto nuevo

    Una vez abierto el Eclipse y apuntando al workspaceque viene en ladistribucin de OpenXava. Usando el asistente de Eclipse apropiado hemosde crear un nuevo proyecto Java llamado Gestion. Ahora tenemos unproyecto Java vaco en el workspace, el siguiente paso es darle la estructuracorrecta para un proyecto OpenXava. Vamos al Proyecto OpenXavaPlantillayejecutamos CrearNuevoProyecto.xmlusando Ant. Podemos hacerlocon Botn Derecho en CrearNuevoProyecto.xml > Run as > Ant Build. Antnos preguntar por el nombre del proyecto, ponemos Gestion.Seleccionamos el proyecto Gestiony 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 aplicacin Java EE/J2EE pensada para ser desplegadaen un servidor de aplicaciones Java (desde la v2.0 las aplicacionesOpenXava tambin funcionan en un simple servidor de servlets, comoTomcat). Dentro de OpenXava solo se indica el nombre JNDI de la fuente dedatos, y en nuestro servidor de aplicaciones tenemos que configurarnosotros esa base datos. El configurar una fuente de datos en un servidor de

    aplicaciones es algo que va ms all de esta gua, sin embargo acontinuacin se da las instrucciones concretas para poder realizar esteprimer proyecto usando el Tomcat incluido en la distribucin de OpenXava eHypersonic como base de datos. Este Tomcat esta en la carpeta openxava-3.x/tomcat.Con el Tomcat parado editar el archivo context.xmlen el directorio deTomcat conf, en ese archivo tenemos que aadir la siguiente entrada:

    Lo importante aqu es el nombre JNDI, que es a lo nico que se hacereferencia desde OpenXava, en este caso MiGestionDS. Lostributos driverClassNamey urldependen de nuestra base de datos, en estecaso estamos usando Hypersonic.

    Nuestro primer componente de negocio

  • 5/24/2018 OpenXava-Manual.pdf

    8/115

    Crear un componente de negocio OpenXava es fcil: La definicin para cadacomponente es una clase Java con anotaciones. Para empezar vamos acrear una clase llamadaAlmacen:

    Nos ponemos en la carpeta srcy usamos Botn Derecho > New >Package

    Creamos un paquete llamado org.openxava.gestion.modelo Nos ponemos en el paquete org.openxava.gestion.modeloy

    usamos Botn Derecho > New > Class Creamos una clase llamadaAlmacen

    Ahora hemos de editar nuestra nueva clase y escribir el siguiente cdigo:

    packageorg.openxava.gestion.modelo;

    importjavax.persistence.*;importorg.openxava.annotations.*;

    @Entity

    publicclassAlmacen {

    @Id @Column(length=3) @Required

    privateint codigo;

    @Column(length=40) @RequiredprivateStringnombre;

    publicint getCodigo() {returncodigo;

    }

    publicvoid setCodigo(int codigo) {

    this.codigo = codigo;}

    publicStringgetNombre() {

    returnnombre;}

    publicvoid setNombre(Stringnombre) {

    this.nombre = nombre;}

    }

  • 5/24/2018 OpenXava-Manual.pdf

    9/115

    Esta clase contiene (y contendr) toda la informacin necesaria por laaplicacin sobre el concepto de negocio de Almacen. En este momento slotenemos la estructura de datos, pero en esta clase podemos poner el mapeocontra la base de datos, la lgica de negocio, la presentacin visual, elmanejo de datos tabulares, etc.En realidad esta clase es una Entityque sigue el estndar EJB3. Para definiruna clase como una entidad lo nico que necesitamos es usar laanotacin @Entityen la declaracin de la clase.Dentro de entidad vemos definidas un conjunto de propiedades, vamos aexaminarlo:

    @Id // 1@Column(length=3) // 2@Required // 3privateint codigo; // 4privateint getCodigo() { // 4

    returncodigo;}privatevoid setCodigo(int codigo) {// 4

    this.codigo = codigo;}

    Este es su significado:

    1. @Id: Indica si esta propiedad forma parte de la clave. La clave identificaa cada objeto de forma nica y normalmente coincide con la clave en latabla de base de datos.

    2. @Column(length= ): Longitud de los datos visualizados. Es opcional,pero suele ser til para hacer mejores interfaces grficos y generar lastablas de la base de datos.

    3. @Required: Indica si hay que validar la existencia de informacin enesta propiedad antes de crear o modificar.

    4. La propiedad definida de la forma usual para una clase Java. Todo tipovlido para una propiedad Java se puede poner, lo que incluye tiposintegrados, clases del JDK, clases propias, etc.

    Las posibilidades de una propiedad van mucho ms all de lo que aqu semuestra, se puede ver una explicacin ms completa en el capitulo sobreel modelo.

    La tabla

  • 5/24/2018 OpenXava-Manual.pdf

    10/115

    Antes de poder probar la aplicacin hemos de crear la tabla en la base dedatos:

    Arrancamos la base de datos: Desde la lnea de rdenes vamos a lacarpeta openxava-3.x/tomcat/biny ejecutamos:

    o En Linux/Unix: ./start-hsqldb.sh gestion-db 1666o En Windows: start-hsqldb gestion-db 1666 Creamos la tabla:o Editamos Gestion/build.xml. Buscamos la tarea ant actualizarEsquema.o Ponemos el valor correcto para schema.path, en este

    caso ../OpenXavaTest/lib/hsqldb.jar.o Ejecutamos la tarea ant actualizarEsquema. Arrancamos el Tomcat, si ya est arrancado lo paramos y lo

    rearrancamos, y ya est todo listo.

    Ejecutar nuestra aplicacinDespus de nuestro duro trabajo tenemos derecho a ver el fruto de nuestrosudor, as que all vamos:

    Ejecutamos la tarea ant desplegarWar. Abrimos un navegador de internet y vamos a la

    direccin http://localhost:8080/Gestion/xava/module.jsp?application=Gestion&module=Almacen

    Y ahora podemos jugar con nuestro mdulo y ver como funciona.Tambin puedes desplegar el mdulo como portlet JSR-168, de esta forma:

    Ejecutamos la tarea ant generarPortlets. Coge el archivo Gestion.waren la carpeta openxava-

    3.x/workspace.dist/Gestion.disty despliegalo en tu portal.

    Automatizando las pruebasAunque parece que lo ms natural es probar la aplicacin con un navegadore ir viendo lo mismo que ver el usuario; lo cierto es que es ms 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 tenamos.OpenXava usa un sistema de pruebas basado en JUnit y HttpUnit. Laspruebas JUnit de OpenXava emulan el funcionamiento de un usuario real conun navegador, de esta forma podemos replicar de forma exacta las mismaspruebas que haramos nosotros mismos con un navegador. La ventaja deeste enfoque es que probamos de forma sencilla desde el interfaz grfico alacceso a la base de datos.Si probramos el modulito manualmente normalmente crearamos unregistro nuevo, lo buscaramos, lo modificaramos y lo borraramos. Vamos ahacer eso automticamente.

  • 5/24/2018 OpenXava-Manual.pdf

    11/115

    En primer lugar crearemos un paquete en donde poner laspruebas, org.openxava.gestion.pruebas, y en este paquete pondremos unaclase llamada PruebaAlmacen, y pegaremos en ella el siguiente cdigo:

    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 {// Creamosexecute("CRUD.new"); // 2setValue("codigo", "7"); // 3setValue("nombre", "Almacen JUNIT");execute("CRUD.save");

    assertNoErrors(); // 4assertValue("codigo", ""); // 5assertValue("nombre", "");

    // LeeemossetValue("codigo", "7");execute("CRUD.search");assertValue("codigo", "7");assertValue("nombre", "Almacen JUNIT");

    // ModificamossetValue("nombre", "Almacen JUNIT MODIFICADO");execute("CRUD.save");assertNoErrors();assertValue("codigo", "");assertValue("nombre", "");

    // Comprobamos modificadosetValue("codigo", "7");execute("CRUD.search");assertValue("codigo", "7");

  • 5/24/2018 OpenXava-Manual.pdf

    12/115

    assertValue("nombre", "Almacen JUNIT MODIFICADO");

    // Borramosexecute("CRUD.delete");assertMessage("Almacen borrado satisfactoriamente"); // 6

    }

    }

    Podemos aprender de este ejemplo:

    1. Constructor: En el constructor indicamos el nombre de la aplicacin y elnombre del mdulo.

    2. execute: Permite simular la pulsacin de un botn o vnculo. Comoargumento se enva el nombre de la accin; los nombres de las accioneslos podemos ver en OpenXava/xava/default-controllers.xml(loscontroladores predefinidos) yGestion/xava/controladores.xml(lospropios). Tambin si paseamos el ratn sobre el vnculo el navegador nosmostrar la accin JavaScript a ejecutar, que contiene el nombre deaccin OpenXava. Es decir execute(CRUD.new)es como pulsar el botnde nuevo en la interfaz grfica.

    3. setValue: Para asignar valor a un control del formulario. Esdecir, setValue(nombre, Pepe)tiene el mismo efecto que teclear en el

    campo de texto 'Pepe'. Los valores siempre son alfanumricos, ya que seasignan a un formulario HTML.4. assertNoErrors: Comprueba que no se hayan producido errores. En la

    interfaz grfica los errores son mensajes en color rojo, que son aadidospor la lgica de la aplicacin.

    5. assertValue: Comprueba que el valor contenido en un elemento delformulario es el indicado.

    6. assertMessage: Verifica que la aplicacin ha producido el mensajeinformativo indicado.

    Se puede ver como de forma sencilla podemos probar que el mantenimiento

    funciona, escribir un cdigo como este puede costar 5 minutos, pero a lalarga ahorra horas de trabajo, porque a partir de ahora podemos probarlotodo en 1 segundo, y porque nos va a avisar a tiempo cuando rompamos lagestin de Almacenes tocando otra cosa.Para ms detalle podemos ver el API JavaDocde org.openxava.tests.ModuleTestBasey examinar los ejemplos que hayenorg.openxava.test.testsde OpenXavaTest.Por defecto la prueba se ejecuta contra el mdulo en modo solitario (fueradel portal) (es decir desplegado con desplegarWar). Pero si lo deseamos esposible testear contra la versin de portlet (es decir desplegado

  • 5/24/2018 OpenXava-Manual.pdf

    13/115

    con generarPortlets). Solo necesitamos editar el archivoproperties/xava-junit.propertiesy escribir:

    liferay.url=web/guestEsto para probar contra el portal Liferay. Tambin es posible probar contrael portal JetSpeed2, mira enOpenXavaTest/properties/xava-junit.propertiespara ver cmo.

    Las etiquetasYa nos funciona, pero hay un pequeo detalle que se ha quedado suelto.Posiblemente queramos definir las etiquetas que se mostrarn al usuario. Laforma de hacerlo es escribiendo un archivo con todas las etiquetas, y aspodemos traducir nuestro producto a otro idioma con facilidad.

    Para definir las etiqueta solo tenemos que editar elarchivo EtiquetasGestion_es.propertiesen la carpeta i18n. Editar ese archivoy aadir:

    Almacen=Almacn

    No es necesario poner todas las propiedades, porque los casos ms comunes(codigo, nombre, descripcion y un largo etc) ya los tiene OpenXava incluidosen Espaol, Ingls, Polaco, Alemn, Francs, Indonesio y Cataln.Si queremos una versin en otro idioma (ingls, por ejemplo) solo tenemosque copiar y pegar con el sufijo apropiado. Por ejemplo, podemos tener

    un EtiquetasGestion_en.propertiescon el siguiente contenido:Almacen=Warehouse

    Las etiquetas y mensaje por defecto de OpenXava estnen OpenXava/i18na/Labels.propertiesyOpenXava/i18n/Messages.properties.Si queremos sobreescribir algunos de estos recursos no necesitamos editarestos archivos, sino que podemos usar los mismos nombres de clave en losarchivos de recursos de nuestro proyecto, entonces nuestras etiqueta ymensajes seran usadas en vez de las estndar de OpenXava (nuevo env2.0.3). Por ejemplo, si queremos cambiar el mensaje estandar en modo

    lista ''Hay 23663 registros en la listapor otro, hemos de aadiraMensajesGestion_es.propertiesesta entrada:

    # list_count est en Messages_en.properties de OpenXava, este es unejemplo# de sobreescritura de un mensaje estndar de OpenXavalist_count=Hay {0} objetos en la lista

    Ahora, nuestra aplicacin mostrar Hay 23663 objetos en la listaen vezdel mensaje por defecto de OpenXava 'Hay 23663 registros en la lista.Para saber ms sobre como definir las etiquetas de nuestros elementosOpenXava podemos echar un vistazo a los archivos deOpenXavaTest/i18n.

  • 5/24/2018 OpenXava-Manual.pdf

    14/115

    Captulo 3: ModeloLa capa del modelo en una aplicacin orientada a objetos es la que contienela lgica de negocio, esto es la estructura de los datos con los que se trabajay todos los clculos, validaciones y procesos asociados a esos datos.OpenXava es un marco orientado al modelo, en donde el modelo es lo msimportante, y todo lo dems (p. ej. la interfaz grfica) depende de l.La forma de definir el modelo en OpenXava es mediante simples clases Java

    (aunque tambin existe una versin XML) y un poquito de Java. OpenXava

  • 5/24/2018 OpenXava-Manual.pdf

    15/115

    provee una aplicacin completamente funcional a partir de la definicin delmodelo.

    Componente de negocioLa unidad bsica para crear aplicaciones OpenXava es el componente denegocio. Un componente de negocio se define usando una clase Javallamada Entity.Esta clase es una entidad EJB3 convencional, o con otraspalabras, un POJOcon anotaciones que sigue el estndar Java PersistenceAPI(JPA).JPA es el estndar de Java para la persistencia, es decir, para objetos queguardan su estado en una base de datos. Si sabes desarrollar usando POJOscon JPA, ya sabes como desarrollar aplicaciones OpenXava.Usando una simple clase Java podemos definir un Componente de Negocio

    con:

    Modelo: Estrutura de datos, validaciones, calculos, etc. Vista: Cmo se puede mostrar el modelo al usuario. Datos tabulares: Cmo se muestra los datos de este componentes en modo

    lista (en formato tabular). Mapeo objeto/relacional: Cmo grabar y leer el estado de los objetos desde

    la base de datos.

    Este captulo explica cmo definir la parte del modelo, es decir, todo sobre laestructura, las validaciones, los clculos, etc.

    EntidadPara define la parte del modelo hemos de definir a clase Java conanotaciones. Adems de sus propias anotaciones, OpenXava sportaanotaciones de JPAe Hibernate Validator. Esta clase Java es una entidad, esdecir, una clase persistente que representa concepto de negocio.En este captulo JPA se usa para indicar que es una anotacin estndar deJava Persistent API, HV para indicar que es una anotacin de HibernateValidator, y OX para indicar que es una anotacin de OpenXava.sta es la sintxis para una entidad:

    @Entity // 1

    @EntityValidator // 2@RemoveValidator // 3publicclassNombreEntidad { // 4// Propiedades // 5// Referencias // 6// Colecciones // 7// Mtodos // 8// Buscadores // 9// Mtodos de retrollamada // 10

  • 5/24/2018 OpenXava-Manual.pdf

    16/115

    }

    1. @Entity(JPA, uno, obligado): Indica que esta clase es una entidad JPA, conotras palabras, sus instancias sern objetos persistentes.

    2. @EntityValidator(OX, varios, opcional): Ejecuta una validacin a nivel demodelo. Este validador puede recibir el valor de varias propiedades delmodelo. Para validar una sola propiedad es preferible poner el validador anivel de propiedad.

    3. @RemoveValidator(OX, varios, opcional): Se ejecuta antes de borrar, ytiene la posibilidad de vetar el borrado del objeto.

    4. Declaracin de la clase: Como en un clase de Java convencional. Podemosusar extendse implements.

    5. Propiedades: Propiedades de Java convencionales. Representan el estadoprincipal del objeto.

    6. Referencias: Referencias a otras entidades.7. Colecciones: Colecciones de referencias a otras entidades.8. Mtodos: Mtodos Java con lgica de negocio.9. Buscadores: Los buscadores son mtodos estticos que hacen bsquedas

    usando las prestaciones de consulta de JPA.10. Mtodos de retrollamada: Los mtodos JPA de retrollamada (callbacks)

    para insertar lgica al crear, modificar, cargar, borrar, etc

    PropiedadesUna propiedad representa parte del estado de un objeto que se puedeconsultar y en algunos casos cambiar. El objeto no tiene la obligacin deguardar fsicamente la informacin de la propiedad, solo de devolverlacuando se le pregunte.La sintaxis para definir una propiedad es:

    @Stereotype // 1@Column(length=) @Max @Length(max=) @Digits(integerDigits=) // 2@Digits(fractionalDigits=) // 3@Required @Min @Range(min=) @Length(min=) // 4

    @Id // 5@Hidden // 6@SearchKey // 7@Version // 8@DefaultValueCalculator // 9@PropertyValidator // 10privatetipo nombrePropiedad; // 11publictipo getNombrePropiedad() { ... } // 11publicvoid setNombrePropiedad(tipo nuevoValor) { ... } // 11

  • 5/24/2018 OpenXava-Manual.pdf

    17/115

    1. @Stereotype(OX, opcional): Permite especificar un comportamientoespecial para cierta propiedades.

    2. @Column(length=)(JPA), @Max(HV), @Length(max=)(HV), @Digits(integerDigits=)(HV, opcional, normalmente solo se usa una): Longitud encaracteres de la propiedad, excepto para @Maxque es el valor mximo.Especialmente til a la hora de generar interfaces grficas. Si noespecificamos longitud asume un valor por defecto asociado al tipo oestereotipo que se obtiene de default-size.xmlo longitud-defecto.xml.

    3. @Digits(fractionalDigits=)(HV, opcional): Escala (tamao de la partedecimal) de la propiedad. Solo aplica a propiedades numricas. Si noespecificamos escala asume un valor por defecto asociado al tipo oestereotipo que se obtiene de default-size.xmlo longitud-defecto.xml.

    4. @Required(OX), @Min(HV), @Range(min=)(HV), @Length(min=)(H

    V) (opcional, normalmente solo se usa una): Indica si esa propiedad esrequerida. En el caso de @Min, @Rangey @Lengthtenemos que poner unvalor mayor que cero para minpara que se asuma la propiedad comorequerida. Por defecto es true para las propiedades clave ocultas (nuevo env2.1.3)y false en todos los dems casos. Al grabar OpenXava comprobar silas propiedades requeridas estn presentes, si no lo estn no se producir lagrabacin y se devolver una lista de errores de validacin. La lgica paradeterminar si una propiedad est presente o no se puede configurar creandoun archivo validators.xmlovalidadores.xmlen nuestro proyecto. Podemosver la sintaxis en OpenXava/xava/validators.xml. @Required es una

    resctriccin de Hibernate Validator(nuevo en v3.0.1).5. @Id(JPA, opcional): Para indicar si una propiedad forma parte de la clave.Al menos una propiedad (o referencia) ha de ser clave. La combinacin depropiedades (y referencias) clave se debe mapear a un conjunto de camposen la base de datos que no tengan valores repetidos, tpicamente con laclave primaria.

    6. @Hidden(OX, opcional): Una propiedad oculta es aquella que tiene sentidopara el desarrollador pero no para el usuario. Las propiedades ocultas seexcluyen cuando se generan interfaces grficas automticas, sin embargo anivel de cdigo generado estn presentes y son totalmente funcionales,incluso si se les hace alusin explicita podran aparecer en una interfaz

    grfica.7. @SearchKey(OX, optional): Las propiedades clave de bsqueda se usan

    por los usuarios para buscar los objetos. Son editables en la interfaz deusuario de las referencias permitiendo al usuario teclear su valor parabuscar. OpenXava usa las propiedades clave (@Id) para buscar por defecto,y si la propiedades clave (@Id) estn ocultas usa la primera propiedad en lavista. Con @SearchKeypodemos elegir las propiedades para buscarexplicitamente.

    8. @Version(JPA, opcional): Una propiedad versin se usa para el control deconcurrencia optimista. Si queremos control de concurrencia solo

    necesitamos tener una propiedad marcada como @Versionen nuestra

  • 5/24/2018 OpenXava-Manual.pdf

    18/115

    entidad. Solo podemos especificar una propiedad de versin por entidad. Lossiguientes tipos son soportados para propiedades versin: int, Integer,short, Short, long, Long, Timestamp. Las propiedades de versin tambin seconsideran ocultas.

    9. @DefaultValueCalculator(OX, uno, optional): Para implementar la lgicapara calcular el valor inicial de la propiedad. Una propiedadcon @DefaultValueCalculators tiene settery es persistente.

    10. @PropertyValidator(OX, varios, opcional): Indica la lgica devalidacin a ejecutar sobre el valor a asignar a esta propiedad antes decrear o modificar.

    11. Declaracin de la propiedad: Una declaracin de propiedad Javanormal y corriente con gettersy setters. Podemos crear una propiedadcalculada usando solo un gettersin campo ni setter. Cualquier tipo legal

    para JPA est permitido, solo hemos de proveer un Hibernate Typeparagrabar en la base de datos y un editor OpenXava para dibujar como HTML.

    EstereotipoUn estereotipo (@Stereotype) es la forma de determinar un comportamientoespecifico dentro de un tipo. Por ejemplo, un nombre, un comentario, unadescripcin, etc. todos corresponden al tipo Java java.lang.String pero siqueremos que los validadores, logitud por defecto, editores visuales, etc.sean diferente en cada caso y necesitamos afinar ms; lo podemos hacerasignando un esterotipo a cada uno de estos casos. Es decir, podemos tener

    los estereotipos NOMBRE, TEXTO_GRANDE o DESCRIPCION y asignarlos anuestras propiedades.El OpenXava viene configurado con los siguientes estereotipos:

    DINERO, MONEY FOTO, PHOTO, IMAGEN, IMAGE TEXTO_GRANDE, MEMO, TEXT_AREA ETIQUETA, LABEL ETIQUETA_NEGRITA, BOLD_LABEL HORA, TIME FECHAHORA, DATETIME GALERIA_IMAGENES, IMAGES_GALLERY (instrucciones) RELLENADO_CON_CEROS, ZEROS_FILLED TEXTO_HTML, HTML_TEXT (texto con formato editable) ETIQUETA_IMAGEN, IMAGE_LABEL (imagen que depende del contenido de

    la propiedad) EMAIL TELEFONO, TELEPHONE WEBURL IP ISBN

    TARJETA_CREDITO, CREDIT_CARD

  • 5/24/2018 OpenXava-Manual.pdf

    19/115

    LISTA_EMAIL, EMAIL_LIST

    Vamos a ver como definiramos un estereotipo propio. Crearemos unollamado NOMBRE_PERSONA para representar nombres de persona.Editamos (o creamos) el archivo editors.xmlo editores.xmlen nuestracarpetaxava. Y aadimos

    De esta forma indicamos que editor se ha de ejecutar para editar yvisualizar propiedades con el estereotipo NOMBRE_PERSONA.Adems es til indicar la longitud por defecto, eso se hace editando default-size.xmlo longitud-defecto.xml:

    Y as si no ponemos longitud asumir 40 por defecto.Menos comn es querer cambiar el validador para requerido, pero siqueremos cambiarlo lo podemos hacer aadiendoavalidators.xmlo validadores.xmlde nuestro proyecto lo siguiente:

    Ahora podemos definir propiedades con estereotipo NOMBRE_PERSONA:

    @Stereotype("PERSON_NAME")privateStringnombre;

    En este caso asume 40 longitud y tipo String, as como ejecutar elvalidador NotBlankCharacterValidatorpara comprobar que es requerido.

    Estereotipo GALERIA_IMAGENESSi queremos que una propiedad de nuestro componente almacene unagalera de imgenes. Solo necesitamos declarar que nuestra propiedad seadel estereotipo GALERIA_IMAGENES. De esta manera:

    @Stereotype("GALERIA_IMAGENES")privateStringfotos;

    Adems, en el mapeo tenemos que mapear la propiedad contra una columnaadecuada para almacenar una cadena (String) con 32 caracteres de longitud(VARCHAR(32)).

  • 5/24/2018 OpenXava-Manual.pdf

    20/115

    Y ya est todo.Pero, para que nuestra aplicacin soporte este estereotipo necesitamosconfigurar nuestro sistema.Lo primero es crear a tabla en la base de datos para almacenar lasimgenes:

    CREATETABLEIMAGENES (ID VARCHAR(32) NOTNULLPRIMARYKEY,GALLERY VARCHAR(32) NOTNULL,IMAGE BLOB);

    CREATEINDEXIMAGENES01ONIMAGENES (GALLERY);

    El tipo de la columna IMAGE puede ser un tipo ms adecuado paraalmacenar byte [] en el caso de nuestra base de datos (por ejemploLONGVARBINARY) .Y finalmente necesitamos definir el mapeo en nuestroarchivopersistence/hibernate.cfg.xml, as:

    ...

    ...

    Despus de todo esto ya podemos usar el estereotipo GALERIA_IMAGENESen los componentes de nuestra aplicacin.

    Concurrencia y propiedad versinConcurrencia es la habilidad de una aplicacin para permitir que variosusuarios graben datos al mismo tiempo sin perder informacin. OpenXavausa un esquema de concurrencia optimista. Usando concurrencia optimistalos registros no se bloquean permitiendo un alto nivel de concurrencia sinperder la integridad de la informacin.Por ejemplo, si un usuario A lee un registro y entonces un usuario B lee elmismo registro, lo modifica y graba los cambios, cuando el usuario A intentegrabar el registro recibir un error y tendr que refrescar los datos yreintentar su modificacin.Para activar el soporte de concurrencia para un componente OpenXava solonecesitamos declarar una propiedad usando@Version, de esta manera:

    @Versionprivateint version;

  • 5/24/2018 OpenXava-Manual.pdf

    21/115

    Esta propiedad es para uso del mecanismo de persistencia (Hibernate oJPA), ni nuestra aplicacin ni usuarios deberan acceder directamente a ella.

    EnumsOpenXava suporta enumsde Java 5. Un enumpermite definir una propiedadque solo puede contener los valores indicados.Es fcil de usar, veamos un ejemplo:

    privateDistancia distancia;publicenumDistancia { LOCAL, NACIONAL, INTERNACIONAL };

    La propiedad distanciasolo puede valer LOCAL, NACIONAL oINTERNACIONAL, y como no hemos puesto @Requiredtambin permitevalor vaco (null).

    A nivel de interfaz grfico la implementacin web actual usa un combo. Laetiqueta para cada valor se obtienen de los archivosi18n.A nivel de base datos por defecto guarda el entero (0 para LOCAL, 1 paraNACIONAL, 2 para INTERNACIONAL y null para cuando no hay valor), peroesto se puede configurar fcilmente para poder usar sin problemas bases dedatos legadas. Ver ms de esto ltimo en el captulo sobre mapeo.

    Propiedades calculadasLas propiedades calculadas son de solo lectura (solo tienen getter) y nopersistentes (no se almacenan en ninguna columna de la tabla de base de

    datos).Una propiedad calculada se define de esta manera:

    @Depends("precioUnitario") // 1@Max(9999999999L) // 2publicBigDecimalgetPrecioUnitarioEnPesetas() {

    if (precioUnitario == null) returnnull;returnprecioUnitario.multiply(newBigDecimal("166.386"))

    .setScale(0, BigDecimal.ROUND_HALF_UP);

    }

    De acuerdo con esta definicin ahora podemos usar el cdigo de estamanera:

    Producto producto = ...producto.setPrecioUnitario(2);BigDecimalresultado = producto.getPrecioUnitarioEnPesetas();

    Y resultadocontendr 332,772.Cuando la propiedadprecioUnitarioEnPesetasse visualiza al usuario no eseditable, y su editor tiene una longitud de 10, indicado

    usando @Max(9999999999L)(2). Tambin, dado que

  • 5/24/2018 OpenXava-Manual.pdf

    22/115

    usamos @Depends("precioUnitario")(1) cuando el usuario cambie lapropiedadprecioUnitarioen la interfaz de usuario lapropiedadprecioUnitarioEnPesetasser recalculada y su valor serrefrescado de cara al usuario.Desde una propiedad calculada tenemos acceso a conexiones JDBC. Unejemplo:

    @Max(999)publicint getCantidadLineas() {

    // Un ejemplo de uso de JDBCConnectioncon = null;try{

    con =

    DataSourceConnectionProvider.getByComponent("Factura").getConnection(); // 1Stringtabla = MetaModel.get("LineaFactura").getMapping().getTable();

    PreparedStatementps = con.prepareStatement("select count(*) from " +

    tabla +" where FACTURA_AO = ? and FACTURA_NUMERO = ?");

    ps.setInt(1, getAo());ps.setInt(2, getNumero());ResultSetrs = ps.executeQuery();rs.next();Integerresult = newInteger(rs.getInt(1));

    ps.close();returnresult;

    }catch(Exceptionex) {

    log.error("Problemas al calcular cantidad de lneas de una Factura",ex);

    // Podemos lanzar cualquier RuntimeException aquthrownewSystemException(ex);

    }finally{

    try{con.close();}catch(Exceptionex) {

    }}

    }

    Es verdad, el cdigo JDBC es feo y complicado, pero a veces puede ayudar aresolver problemas de rendimiento. La

    claseDataSourceConnectionProvidernos permite obtener la conexin

  • 5/24/2018 OpenXava-Manual.pdf

    23/115

    asociada a la misma fuente de datos que la entidad indicada (en estecaso Factura). Esta clase es para nuestra conveniencia, tambin podemosacceder a una conexin JDBC usando JNDI o cualquier otro medio quequeramos. De hecho, en una propiedad calculada podemos escribir cualquiercdigo que Java nos permita.Si estamos usando acceso basado en propiedades, es decir si anotamoslos getterso setters,entonces hemos de aadir la anotacin @Transientanuestra propiedad calculada, de esta forma:

    privatelong codigo;

    @Id @Column(length=10) // Anotamos el getter,publiclong getCodigo() { // por tanto JPA usar acceso basado en

    propiedades para nuestra clasereturncodigo;}publicvoid setCodigo(long codigo) {

    this.codigo = codigo;}

    @Transient // Hemos de anotar como Transient nuestrapropiedad calculadapublicStringgetZoneOne() { // porque usamos acceso basado en

    propiedades

    return"En ZONA 1";}

    Calculador valor por defectoCon @DefaultValueCalculatorpodemos asociar lgica a una propiedad, eneste caso la propiedad es lectura y escritura. Este calculador se usa paracalcular el valor inicial. Por ejemplo:

    @DefaultValueCalculator(CurrentYearCalculator.class)privateint ao;

    En este caso cuando el usuario intenta crear una nueva factura (porejemplo) se encontrar con que el campo de ao ya tiene valor, que lpuede cambiar si quiere. La lgica para generar este valor est en laclase CurrentYearCalculatorclass, as:

    packageorg.openxava.calculators;

    importjava.util.*;

    /**

  • 5/24/2018 OpenXava-Manual.pdf

    24/115

    * @author Javier Paniza*/

    publicclassCurrentYearCalculator implementsICalculator {

    publicObjectcalculate() throwsException{

    Calendar

  • 5/24/2018 OpenXava-Manual.pdf

    25/115

    (referencia.propiedad).Adems podemos usar @PropertyValuesin fromni value:

    @DefaultValueCalculator(value=CalculadorPrecioDefectoProducto.class,properties=

    @PropertyValue(name="codigoFamilia"))

    En este caso OpenXava coge el valor de la propiedadvisualizada codigoFamiliay lo inyecta en la propiedad codigoFamiliadelcalculador, es decir @PropertyValue(name="codigoFamilia")equivalea @PropertyValue(name="codigoFamilia", from="codigoFamilia").Desde un calculador tenemos acceso a conexiones JDBC, he aqu unejemplo:

    @DefaultValueCalculator(value=CalculadorCantidadLineas.class,properties= {

    @PropertyValue(name="ao"),@PropertyValue(name="numero"),

    })privateint cantidadLineas;

    Y la clase del calculador:

    packageorg.openxava.test.calculadores;

    importjava.sql.*;

    importorg.openxava.calculators.*;importorg.openxava.util.*;

    /*** @author Javier Paniza*/

    publicclassCalculadorCantidadLineas implementsIJDBCCalculator { //1

    privateIConnectionProvider provider;privateint ao;privateint numero;

    publicvoid setConnectionProvider(IConnectionProvider provider) {// 2this.provider = provider;

    }

  • 5/24/2018 OpenXava-Manual.pdf

    26/115

    publicObjectcalculate() throwsException{

    Connectioncon = provider.getConnection();

    try{PreparedStatementps = con.prepareStatement(

    "select count(*) from XAVATEST.LINEAFACTURA +where FACTURA_AO = ? and FACTURA_NUMERO = ?");

    ps.setInt(1, getAo());ps.setInt(2, getNumero());ResultSetrs = ps.executeQuery();rs.next();Integerresult = newInteger(rs.getInt(1));

    ps.close();

    returnresult;}finally{

    con.close();}

    }

    publicint getAo() {returnao;

    }

    publicint getNumero() {returnnumero;

    }

    publicvoid setAo(int ao) {this.ao = ao;

    }

    publicvoid setNumero(int numero) {this.numero = numero;

    }}

    Para usar JDBC nuestro calculador tiene queimplementar IJDBCCalculator(1) y entonces recibirun IConnectionProvider(2) que podemos usar dentro de calculate().OpenXava dispone de un conjunto de calculadores incluidos de uso genrico,que se pueden encontrar enorg.openxava.calculators.

  • 5/24/2018 OpenXava-Manual.pdf

    27/115

    Valores por defecto al crearPodemos indicar que el valor sea calculado justo antes de crear (insertar enla base de datos) un objeto por primera vez.Usualmente para las claves usamos el estndar JPA. Por ejemplo, siqueremos usar una columna identity(auto incremento) como clave:

    @Id @Hidden@GeneratedValue(strategy=GenerationType.IDENTITY)privateIntegerid;

    Podemos usar otras tcnicas de generacin, por ejemplo, una sequencedebase de datos puede ser definida usando el estndar JPA de esta manera:

    @SequenceGenerator(name="SIZE_SEQ", sequenceName="SIZE_ID_SEQ",allocationSize=1 )@Hidden @Id @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="SIZE_SEQ")privateIntegerid;

    Si queremos generar un identificador nico de tipo String y 32 caracteres,podemos usar una extensin de Hibernate de JPA:

    @Id @GeneratedValue(generator="system-uuid") @Hidden@GenericGenerator(name="system-uuid", strategy = "uuid")privateStringoid;

    Ver la seccin 9.1.9 de la especificacin JPA 1.0 (parte de JSR-220) paraaprender ms sobre @GeneratedValues.Si queremos usar nuestra propia lgica para generar el valor al crear, o bienqueremos generar un nuevo valor para propiedades que no son claveentonces no podemos usar el @GeneratedValuede JPA, aunque es fcilresolver estos casos con JPA. Solo necesitamos aadir este cdigo a nuestraclase:

    @PrePersistprivatevoid calcularContador() {

    contador = newLong(System.currentTimeMillis()).intValue();

    }

    La anotacin JPA @PrePersisthace que este mtodo se ejecute antes deinsertar datos por primera vez en la base de datos, en este mtodopodemos calcular el valor para nuestra clave o incluso para propiedades noclave con nuestra propia lgica.

  • 5/24/2018 OpenXava-Manual.pdf

    28/115

    Validador de propiedadUn validador de propiedad (@PropertyValidator) ejecuta la lgica devalidacin sobre el valor que se vaya a asignar a esa propiedad antes degrabar. Una propiedad puede tener varios validadores:

    @PropertyValidators ({@PropertyValidator(value=ValidadorExcluirCadena.class, properties=

    @PropertyValue(name="cadena", value="MOTO")),@PropertyValidator(value=ValidadorExcluirCadena.class, properties=

    @PropertyValue(name="cadena", value="COCHE"),onlyOnCreate=true

    )

    })privateStringdescripcion;

    La forma de configurar el validador (con los @PropertyValue) esexactamente igual como en los calculadores. Con elatributoonlyOnCreate=truese puede definir que esa validacin solo seejecute cuando se crea el objeto, y no cuando se modifica.El cdigo del validador es:

    packageorg.openxava.test.validadores;

    importorg.openxava.util.*;importorg.openxava.validators.*;

    /*** @author Javier Paniza*/

    publicclassValidadorExcluirCadena implementsIPropertyValidator { // 1

    privateStringcadena;

    publicvoid validate(Messages errores, // 2Objectvalor, // 3

    StringnombreObjecto, // 4

    StringnombrePropiedad) // 5

    throwsException{

    if (valor==null) return;if (valor.toString().indexOf(getCadena()) >= 0) {

    errores.add("excluir_cadena",nombrePropiedad, nombreObjeto, getCadena());

    }

  • 5/24/2018 OpenXava-Manual.pdf

    29/115

    }

    publicStringgetCadena() {

    returncadena==null?"":cadena;}

    publicvoid setCadena(Stringcadena) {

    this.cadena = cadena;}

    }

    Un validador ha de implementar IPropertyValidator(1), esto le obliga a

    tener un mtodo validate()en donde se ejecuta la validacin de lapropiedad. Los argumentos del mtodo validate()son:

    1. Messages errores: Un objeto de tipo Messagesque representa un conjuntode mensajes (una especie de coleccin inteligente) y es donde podemosaadir los problemas de validacin que encontremos.

    2. Object valor: El valor a validar.3. String nombreObjeto: Nombre del objeto al que pertenece la propiedad a

    validar. til para usarlo en los mensajes de error.4. String nombrePropiedad: Nombre de la propiedad a validar. til para

    usarlo en los mensajes de error.Como se ve cuando encontramos un error de validacin solo tenemos queaadirlo (con errores.add()) enviando un identificador de mensaje y losargumentos. Para que este validador produzca un mensaje significativotenemos que tener en nuestro archivo de mensajes i18n la siguienteentrada:

    excluir_cadena={0} no puede contener {2} en {1}

    Si el identificador que se enva no est en el archivo de mensajes, sale talcual al usuario; pero lo recomendado es siempre usar identificadores delarchivo de mensajes.La validacin es satisfactoria si no se aaden mensajes y se supone fallida sise aaden. El sistema recolecta todos los mensajes de todos los validadoresantes de grabar y si encuentra los visualiza al usuario y no graba.El paquete org.openxava.validatorscontiene algunos validadores de usocomn.@PropertyValidatorest definida como una restriccin de HibernateValidator(nuevo en v3.0.1).

  • 5/24/2018 OpenXava-Manual.pdf

    30/115

    Validador por defecto (nuevo en v2.0.3)Podemos definir validadores por defecto para las propiedades de cierto tipoo estereotipo. Para esto se usa el archivoxava/validadores.xmlde nuestroproyecto para definir en l los validadores por defecto.Por ejemplo, podemos definir en nuestroxava/validadores.xmllo siguiente:

    En este caso estamos asociando el validador ValidadorNombrePersonaalestereotipo NOMBRE_PERSONA. Ahora si definimos una propiedad como lasiguiente:

    @Required @Stereotype("NOMBRE_PERSONA")privateStringnombre;

    Esta propiedad ser validada usando ValidadorNombrePersonaaunque lapropiedad misma no defina ningun validador.ValidadorNombrePersonaseaplica a todas las propiedades con el estereotipo NOMBRE_PERSONA.Podemos tambin asignar validadores por defecto a un tipo.

    En el archivo validadores.xmlpodemos definir tambin los validadores paradeterminar si un valor requerido est presente (ejecutado cuandousamos @Required). Adems podemos asignar nombre (alias) a las clasesde los validadores.Podemos aprender ms sobre los validadoresexaminando OpenXava/xava/validators.xmly OpenXavaTest/xava/validators.xml.Los validadores por defecto no se aplican cuando grabamos nuestrasentidades directamente con la api de JPA.

    ReferenciasUna referencia hace que desde una entidad o agregado se pueda accederotra entidad o agregado. Una referencia se traduce a cdigo Java como unapropiedad (con su gettery su setter) cuyo tipo es el del modelo al que sereferencia. Por ejemplo unClientepuede tener una referencia asu Comercial, y as podemos escribir cdigo Java como ste:

    Cliente cliente = ...cliente.getComercial().getNombre();

    para acceder al nombre del comercial de ese cliente.

    La sintaxis para definir referencias es:

  • 5/24/2018 OpenXava-Manual.pdf

    31/115

    @Required // 1@Id // 2

    @SearchKey // 3 Nuevo en v3.0.2@DefaultValueCalculator // 4@ManyToOne( // 5

    optional=false // 1)privatetipo nombreReferencia; // 5publictipo getNombreReferencia() { ... } // 5publicvoid setNombreReferencia(tipo nuevoValor) { ... } // 5

    1. @ManyToOne(optional=false)(JPA), @Required(OX) (opcional, el JPA

    es el preferido): Indica si la referencia es requerida. Al grabar OpenXavacomprobar si las referencias requeridas estn presentes, si no lo estn nose producir la grabacin y se devolver una lista de errores de validacin.

    2. @Id(JPA, opcional): Para indicar si la referencia forma parte de la clave. Lacombinacin de propiedades y referencias clave se debe mapear a unconjunto de campos en la base de datos que no tengan valores repetidos,tpicamente con la clave primaria.

    3. @DefaultValueCalculator(OX, one, opcional): Para implementar la lgicapara calcular el valor inicial de la referencia. Este calculador ha de devolverel valor de la clave, que puede ser un dato simple (solo si la clave del objeto

    referenciado es simple) o un objeto clave (un objeto especial que envuelvela clave primaria).4. @SearchKey(OX, optional): (Nuevo en v3.0.2)Las referencias clave de

    bsqueda se usan por los usuarios para buscar los objetos. Son editables enla interfaz de usuario de las referencias permitiendo al usuario teclear suvalor para buscar. OpenXava usa los miembros clave (@Id) para buscar pordefecto, y si los miembros clave (@Id) estn ocultos usa la primerapropiedad en la vista. Con @SearchKeypodemos elegir referencias parabuscar explcitamente.

    5. Declaracin de la referencia: Una declaracin de referencia convencionalde Java con sus gettersy setters. La referencia se marca con @ManyToOne(JPA)y el tipo ha de ser otra entidad.

    Un pequeo ejemplo de referencias:

    @ManyToOneprivateComercial comercial; // 1publicComercial getComercial() {

    returncomercial;}publicvoid setComercial(Comercial comercial) {

    this.comercial = comercial;

  • 5/24/2018 OpenXava-Manual.pdf

    32/115

    }

    @ManyToOne(fetch=FetchType.LAZY)privateComercial comercialAlternativo; // 2publicComercial getComercialAlternativo() {

    returncomercialAlternativo;}publicvoid setComercialAlternativo(Comercial comercialAlternativa) {

    this.comercialAlternativo = comercialAlternativo;}

    1. Una referencia llamada comerciala la entidad Comercial.2. Una referencia llamada comercialAlternativoa la entidad Comercial. En este

    caso usamos fetch=FetchType.LAZY, de esta manera los datos son leidos dela base de datos bajo demanda. Este es el enfoque ms eficiente, pero no esel valor por defecto en JPA, por tanto es aconsejable usarsiempre fetch=FetchType.LAZYal declarar las referencias.

    Si asumimos que esto est en una entidad llamada Cliente, podemosescribir:

    Cliente cliente = ...

    Comercial comercial = cliente.getComercial();Comercial comercialAlternativo = cliente.getComercialAlternativo();

    Calculador valor por defecto en referenciasEn una referencia @DefaultValueCalculatorfunciona como en una propiedad,solo que hay que devolver el valor de la clave de la referencia.Por ejemplo, en el caso de una referencia con clave simple podemos poner:

    @ManyToOne(optional=false, fetch=FetchType.LAZY)@JoinColumn(name="FAMILY")

    @DefaultValueCalculator(value=IntegerCalculator.class, properties=@PropertyValue(name="value", value="2"))privateFamilia familia;

    El mtodo calculate()de este calculador es:

    publicObjectcalculate() throwsException{

    returnnewInteger(value);

    }

  • 5/24/2018 OpenXava-Manual.pdf

    33/115

    Como se puede ver se devuelve un entero, es decir, el valor para familia pordefecto es la familia cuyo cdigo es el 2.En el caso de clave compuesta sera as:

    @ManyToOne(fetch=FetchType.LAZY)@JoinColumns({

    @JoinColumn(name="ZONA", referencedColumnName="ZONA"),@JoinColumn(name="ALMACEN", referencedColumnName="CODIGO")

    })@DefaultValueCalculator(CalculadorDefectoAlmacen.class)privateAlmacen almacen;

    Y el cdigo del calculador:

    packageorg.openxava.test.calculadores;

    importorg.openxava.calculators.*;

    /*** @author Javier Paniza*/

    publicclassCalculadorDefectoAlmacen implementsICalculator {

    publicObjectcalculate() throwsException{

    AlmacenKey clave = newAlmacenKey();clave.setNumber(4);clave.setZoneNumber(4);returnclave;

    }

    }

    Devuelve un objeto de tipoAlmacenKey.

    Usar referencias como clavePodemos usar referencias como clave, o como parte de la clave. Hemos dedeclarar la referencia como@Id, y usar una clase clave, como sigue:

    @Entity

    @IdClass(DetalleAdicionalKey.class)publicclassDetalleAdicional {

    // JoinColumn se especifica tambin en DetalleAdicionalKey por un// bug de Hibernate, ver

    http://opensource.atlassian.com/projects/hibernate/browse/ANN-361

    @Id @ManyToOne(fetch=FetchType.LAZY)

  • 5/24/2018 OpenXava-Manual.pdf

    34/115

    @JoinColumn(name="SERVICIO")privateServicio servicio;

    @Id @Hiddenprivateint contador;

    ...

    }

    Adems, necesitamos escribir la clase clave:

    publicclassDetalleAdicionalKey implementsjava.io.Serializable{

    @ManyToOne(fetch=FetchType.LAZY)@JoinColumn(name="SERVICIO")privateServicio servicio;

    @Hiddenprivateint contador;

    // equals, hashCode, toString, getters y setters...

    }

    Necesitamos escribir la clase clave aunque la clave sea solo una referenciacon una sola columna clave.Es mejor usar esta caracterstica slo cuando estemos trabajando contrabases de datos legadas, si tenemos control sobre el esquema es mejor usarun id autogenerado.

    ColeccionesPodemos definir colecciones de referencias a entidades. Una coleccin esuna propiedad Java que devuelvejava.util.Collection.Aqu la sintaxis para definir una coleccin:

    @Size // 1@Condition // 2@OrderBy // 3@XOrderBy // 4@OneToMany/@ManyToMany // 5privateCollection nombreColeccion; // 5publicCollection getNombreColeccion() { ... } // 5publicvoid setNombreColeccion(Collection nuevoValor) { ... } // 5

  • 5/24/2018 OpenXava-Manual.pdf

    35/115

    1. @Size(HV, opcional): Cantidad mnima (min) y/o mxima (max) deelementos esperados. Esto se valida antes de grabar.

    2. @Condition(OX, opcional): Para restringir los elementos que aparecen enla coleccin.

    3. @OrderBy(JPA, opcional): Para que los elementos de la coleccinaparezcan en un determinado orden.

    4. @XOrderBy(OX, opcional): @OrderByde JPA no permite usar propiedadescalificadas (propiedades de referencias).@XOrderBys lo permite.

    5. Declaracion de la coleccin: Una declaracin de coleccin convencional deJava con sus gettersy setters. La coleccin se marca con @OneToMany(JPA)o @ManyToMany (JPA)y el tipo ha de ser otra entidad.

    Vamos a ver algunos ejemplos. Empecemos por uno simple:

    @OneToMany (mappedBy="factura")privateCollection albaranes;publicCollection getAlbaranes() {

    returnalbaranes;}publicvoid setAlbaranes(Collection albaranes) {

    this.albaranes = albaranes;}

    Si ponemos esto dentro de una Factura, estamos definiendo una coleccinde los albaranesasociados a esa Factura. La forma de relacionarlo se haceen la parte del mapeo objeto-relacional. Usamos mappedBy="factura"paraindicar que la referencia facturadeAlbaranse usa para mapear estacoleccin.Ahora podemos escribir cdigo como este:

    Factura factura = ...for (Albaran albaran: factura.getAlbaranes()) {

    albaran.hacerAlgo();}

    Para hacer algo con todos los albaranes asociados a una factura.Vamos a ver otro ejemplo ms complejo, tambin dentro de Factura:

    @OneToMany (mappedBy="factura", cascade=CascadeType.REMOVE) // 1@OrderBy("tipoServicio desc") // [email protected](min=1) // 3privateCollection facturas;

    1. Usar REMOVE como tipo de cascadaas cascade type hace que cuando elusuario borra una factura sus lneas tambin se borran.

  • 5/24/2018 OpenXava-Manual.pdf

    36/115

    2. Con @OrderByobligamos a que las lineas se devuelvan ordenadaspor tipoServicio.

    3. La restriccin de @Size(min=1)hace que sea obligado que haya al menosuna lnea para que la factura sea vlida.

    Tenemos libertad completa para definir como se obtienen los datos de unacoleccin, con @Conditionpodemos sobreescribir la condicin por defecto:

    @Condition("${almacen.codigoZona} = ${this.almacen.codigoZona} AND " +"${almacen.codigo} = ${this.almacen.codigo} AND " +"NOT (${codigo} = ${this.codigo})"

    )

    publicCollection getCompaeros() {returnnull;}

    Si ponemos esta coleccin dentro de Transportista, podemos obtener todoslos transportista del mismo almacn menos l mismo, es decir, la lista desus compaeros. Es de notar como podemos usar thisen la condicin parareferenciar al valor de una propiedad del objeto actual. @Conditionsoloaplica a la interfaz de usuario generada por OpenXava, si llamamosdirectamente a getFellowCarriers()it will be returns null.Si con esto no tenemos suficiente, podemos escribir completamente la lgica

    que devuelve la coleccin. La coleccin anterior tambin se podra haberdefinido as:

    publicCollection getCompaeros() {Queryquery = XPersistence.getManager().createQuery("from

    Transportista t where " +"t.almacen.codigoZona = :zona AND " +"t.almacen.codigo = :codigoAlmacen AND " +"NOT (t.codigo = :codigo) ");

    query.setParameter("zona", getAlmacen().getCodigoZona());query.setParameter("codigoAlmacen", getAlmacen().getCodigo());

    query.setParameter("codigo", getCodigo());returnquery.getResultList();}

    Como se ve es un mtodo getter. Obviamente ha de devolverunajava.util.Collectioncuyos elementos sean de tipoTransportista.Las referencias de las colecciones se asumen bidireccionales, esto quieredecir que si en un Comercialtengo una coleccinclientes, en Clientetengoque tener una referencia a Comercial. Pero puede ocurrir queen Clientetenga ms de una referencia a Comercial(porejemplo, comercialy comercialAlternativo) y entonce JPA no sabe cual

  • 5/24/2018 OpenXava-Manual.pdf

    37/115

    escoger, por eso tenemos el atributomappedByde @OneToMany. En estecaso pondramos:

    @OneToMany(mappedBy="comercial")privateCollection clientes;

    Para indicar que es la referencia comercialy no comercialAlternativola quevamos a usar para esta coleccin.La anotacin @ManyToMany (JPA)permite definir una coleccin con unamulticiplidad de muchos-a-muchos. Como sigue:

    @Entity

    publicclassCliente {...

    @ManyToManyprivateCollection provincias;...

    }

    En este caso un cliente tiene una coleccin de provincias, pero una mismaprovincia puede estar presente en varios clientes.

    MtodosLos mtodos se definen en una entidad OpenXava (mejor dicho, en una

    entidad JPA) como una clase de Java convencional. Por ejemplo:publicvoid incrementarPrecio() {

    setPrecioUnitario(getPrecioUnitario().multiply(newBigDecimal("1.02")).setScale(2));

    }

    Los mtodos son la salsa de los objetos, sin ellos solo seran caparazonestontos alrededor de los datos. Cuando sea posible es mejor poner la lgicade negocio en los mtodos (capa del modelo) que en las acciones (capa delcontrolador).

    BuscadoresUn buscador es mtodo esttico especial que nos permite buscar un objeto ouna coleccin de objetos que sigue algn criterio.Algunos ejemplos:

    publicstaticCliente findByCodigo(int codigo) throwsNoResultException {Queryquery = XPersistence.getManager().createQuery(

    "from Cliente as o where o.codigo = :codigo");query.setParameter("codigo", codigo);return(Cliente) query.getSingleResult();

    }

  • 5/24/2018 OpenXava-Manual.pdf

    38/115

    publicstaticCollectionfindTodos() {

    Queryquery = XPersistence.getManager().createQuery("from Cliente as

    o");returnquery.getResultList();

    }

    publicstaticCollectionfindByNombreLike(Stringnombre) {

    Queryquery = XPersistence.getManager().createQuery(

    "from Cliente as o where o.nombre like :nombre order by o.nombredesc");

    query.setParameter("nombre", nombre);

    returnquery.getResultList();}

    Estos mtodos se pueden usar de esta manera:

    Cliente cliente = Cliente.findByCodigo(8);Collectionjavieres = Cliente.findByNombreLike(%JAVI%);

    Como se ve, usar mtodo buscadores produce un cdigo ms legible queusando la verbosa API de JPA. Pero esto es solo una recomendacin deestilo, podemos escoger no escribir mtodos buscadores y usardirectamente consultas de JPA.

    Validador de entidadEste validador (@EntityValidator) permite poner una validacin a nivel demodelo. Cuando necesitamos hacer una validacin sobre varias propiedadesdel modelo, y esta validacin no corresponde lgicamente a ninguna de ellasse puede usar este tipo de validacin.Su sintaxis es:

    @EntityValidator(value=clase, // 1onlyOnCreate=(true|false), // 2

    properties={ @PropertyValue ... } // 3)

    1. value(opcional, obligada si no se especifica nombre): Clase queimplementa la validacin. Ha de ser del tipo IValidator.

    2. onlyOnCreate(opcional): Si true el validador es ejecutado solo cuandoestamos creando un objeto nuevo, no cuando modificamos uno existente. Elvalor por defecto es false.

    3. properties(varios @PropertyValue, opcional): Para establecer valor a laspropiedades del validador antes de ejecutarse.

  • 5/24/2018 OpenXava-Manual.pdf

    39/115

    Un ejemplo:

    @EntityValidator(value=org.openxava.test.validadores.ValidadorProductoBar

    ato.class, properties= {@PropertyValue(name="limite", value="100"),@PropertyValue(name="descripcion"),@PropertyValue(name="precioUnitario")

    })publicclassProducto {

    Y el cdigo del validador:

    packageorg.openxava.test.validadores;

    importjava.math.*;

    /*** @author Javier Paniza*/

    publicclassValidadorProductoBarato implementsIValidator { // 1

    privateint limite;privateBigDecimalprecioUnitario;

    privateStringdescripcion;

    publicvoid validate(Messages errores) { // 2if (getDescripcion().indexOf("CHEAP") >= 0 ||

    getDescripcion().indexOf("BARATO") >= 0 ||getDescripcion().indexOf("BARATA") >= 0) {if (getLimiteBd().compareTo(getPrecioUnitario()) < 0) {

    errors.add("producto_barato", getLimiteBd()); // 3}

    }}

    publicBigDecimalgetPrecioUnitario() {

    returnprecioUnitario;}

    publicvoid setPrecioUnitario(BigDecimaldecimal) {

    precioUnitario = decimal;}

    publicStringgetDescripcion() {

    returndescripcion==null?"":descripcion;

  • 5/24/2018 OpenXava-Manual.pdf

    40/115

    }

    publicvoid setDescripcion(Stringstring) {

    descripcion = string;}

    publicint getLimite() {returnlimite;

    }

    publicvoid setLimite(int i) {limite = i;

    }privateBigDecimalgetLimiteBd() {

    returnnewBigDecimal(Integer.toString(limite));

    }

    }

    Este validador ha de implementar IValidator(1), lo que le obliga a tener unmtodo validate(Messages messages)(2). En este mtodo solo hay que

    aadir identificadores de mensajes de error (3) (cuyos textos estarn en losarchivos i18n), si en el proceso de validacin (es decir en la ejecucin detodos los validadores) hubiese al menos un mensaje de error, OpenXava nograba la informacin y visualiza los mensajes al usuario.En este caso vemos como se accede a descripcionyprecioUnitario, por esola validacin se pone a nivel de mdelo y no a nivel de propiedad individual,porque abarca ms de una propiedad.Podemos definir ms de un validador por entidad usando @EntityValidators,como sigue:

    @EntityValidators({

    @EntityValidator(value=org.openxava.test.validadores.ValidadorProductoBarato.class, properties= {

    @PropertyValue(name="limite", value="100"),@PropertyValue(name="descripcion"),@PropertyValue(name="precioUnitario")

    }),

    @EntityValidator(value=org.openxava.test.validadores.ValidadorProductoCaro.class, properties= {

    @PropertyValue(name="limite", value="1000"),

  • 5/24/2018 OpenXava-Manual.pdf

    41/115

    @PropertyValue(name="descripcion"),@PropertyValue(name="precioUnitario")

    }),

    @EntityValidator(value=org.openxava.test.validadores.ValidadorPrecioProhibido.class,

    properties= {@PropertyValue(name="precioProhibido", value="555"),@PropertyValue(name="precioUnitario")

    },onlyOnCreate=true

    )

    })publicclassProduct {

    @EntityValidatorest definida como una restriccin de HibernateValidator(nuevo en v3.0.1).

    Validador al borrarEl @RemoveValidatortambin es un validador a nivel de modelo, ladiferencia es que se ejecuta antes de borrar el objeto, y tiene la posibilidadde vetar el borrado.Su sintaxis es:

    @RemoveValidator(value=clase, // 1properties={ @PropertyValue ... } // 2

    )

    1. clase(obligada): Clase que implementa la validacin. Ha de ser deltipo IRemoveValidator.

    2. properties(varios @PropertyValue, opcional): Para establecer valor a laspropiedades del calculador antes de ejecutarse.

    Un ejemplo puede ser:

    @RemoveValidator(value=ValidadorBorrarTipoAlbaran.class,properties=@PropertyValue(name="codigo")

    )publicclassTipoAlbaran {

    Y el validador:

    packageorg.openxava.test.validadores;

  • 5/24/2018 OpenXava-Manual.pdf

    42/115

    importorg.openxava.test.model.*;importorg.openxava.util.*;

    importorg.openxava.validators.*;

    /*** @author Javier Paniza*/

    publicclassValidadorBorrarTipoAlbaran implementsIRemoveValidator {// 1

    privateTipoAlbaran tipoAlbaran;privateint codigo;// Usamos esto (en vez de obtenerlo de tipoAlbaran)

    // para probar @PropertyValue con propiedades simples

    publicvoid setEntity(Objectentidad) throwsException{

    // 2this.tipoAlbaran = (TipoAlbaran) entidad;

    }

    publicvoid validate(Messages errores) throwsException{

    if (!tipoAlbaran.getAlbaranes().isEmpty()) {errores.add("no_borrar_tipo_albaran_si_albaranes", new

    Integer(getCodigo())); // 3

    }}

    publicint getCodigo() {returncodigo;

    }

    publicvoid setCodigo(int codigo) {this.codigo = codigo;

    }

    }

    Como se ve tiene que implementar IRemoveValidator(1) lo que le obliga atener un mtodo setEntity()(2) con el recibir el objeto que va a serborrado. Si hay algn error de validacin se aade al objeto detipo Messagesenviado a validate()(3). Si despus de ejecutar todas lasvalidaciones OpenXava detecta al menos 1 error de validacin no realizar elborrado del objeto y enviar la lista de mensajes al usuario.En este caso si se comprueba si hay albaranes que usen este tipo de albarnantes de poder borrarlo.

    Tal y como ocurre con @EntityValidatorpodemos usar

  • 5/24/2018 OpenXava-Manual.pdf

    43/115

    varios @RemoveValidatorpor entidad usando laanotacin@RemoveValidators.@RemoveValidatorse ejecuta cuando borramos entidades desde OpenXava(usando MapFacadeo las acciones estndar de OX), pero no cuando usamosdirectamente JPA. Si queremos crear una restriccin al borrar que seareconocida por JPA, podemos usar un mtodo de retrollamada de JPA,como @PreRemove.

    Mtodos de retrollamada de JPACon @PrePersistpodemos indicar que se ejecute cierta lgica justo antes decrear el objeto como persistente.Como sigue:

    @PrePersistprivatevoid antesDeCrear() {setDescripcion(getDescripcion() + " CREADO");

    }

    En este caso cada vez que se graba por primera vez un TipoAlbaranseaade un sufijo a su descripcin.Como se ve es exactamente igual que cualquier otro mtodo solo que estese ejecuta automticamente antes de crear.Con @PreUpdatepodemos indicar que se ejecute cierta lgica justo despusde modificar un objeto y justo antes de actualizar su contenido en la base de

    dato, esto es justo antes de hacer el UPDATE.Como sigue:

    @PreUpdateprivatevoid antesDeModificar() {

    setDescripcion(getDescripcion() + " MODIFICADO");}

    En este caso cada vez que se modifica un TipoAlbaranse aade un sufijo asu descripcin.Como se ve es exactamente igual que cualquier otro mtodo solo que estese ejecuta automticamente antes de modificar.Podemos usar todas las anotaciones JPA deretrollamada: @PrePersist, @PostPersist, @PreRemove, @PostRemove,@PreUpdate, @PostUpdatey @PostLoad.

    Clases incrustables (Embeddable)Tal y como indica la especificacin JPA:"Una entidad puede usar otras clases finamente granuladas para representarsu estado. Instancias de estas clases, no como en el caso de las entidades,no tiene identidad persistente. En vez de eso, existen solo como objetosincrustados de una entidad a la que pertenecen. Estos objetos incrustados

    son propiedad exclusiva de sus entidades dueas, y no se comparten entre

  • 5/24/2018 OpenXava-Manual.pdf

    44/115

    entidades persistentes."La sintaxis para una clase incrustada es:

    @Embeddable // 1publicclassNombreIncrustada { // 2// Propiedades // 3// Referencias // 4// Metodos // 5}

    1. @Embeddable(JPA, una, requerido): Indica que esta clase es una claseincrustada de JPA, en otras palabras, sus instancias sern parte de objetos

    persistente.2. Declaracin de la clase: Como una clase Java convencional. Podemos

    uar extendsy implements.3. Properties: Propiedades Java convencionales.4. References: Referencias a entidades. Esto no esta soportado en JPA 1.0

    (EJB 3.0), pero la implementacin de Hibernate lo soporta.5. Mtodos: Mtodos Java con lgica de negocio.

    Referencias incrustadasEste ejemplo es una Direccionincrustada (anotada con @Embedded) que es

    referenciada desde la entidad principal.En la entidad principal podemos escribir:

    @EmbeddedprivateDireccion direccion;

    Y hemos de definir la clase Direccioncomo incrustable:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    importorg.openxava.annotations.*;

    /**** @author Javier Paniza*/

    @EmbeddablepublicclassDireccion implementsIConPoblacion {

    @Required @Column(length=30)

  • 5/24/2018 OpenXava-Manual.pdf

    45/115

    privateStringcalle;

    @Required @Column(length=5)privateint codigoPostal;

    @Required @Column(length=20)privateStringpoblacion;

    // ManyToOne dentro de un Embeddable no est soportado en JPA 1.0(ver en 9.1.34),

    // pero la implementacin de Hibernate lo soporta.@ManyToOne(fetch=FetchType.LAZY, optional=false)

    @JoinColumn(name="STATE")privateProvincia provincia;

    publicStringgetPoblacion() {

    returnpoblacion;}

    publicvoid setPoblacion(Stringpoblacion) {

    this.poblacion = poblacion;}

    publicStringgetCalle() {

    returncalle;}

    publicvoid setCalle(Stringcalle) {

    this.calle = calle;}

    publicint getCodigoPostal() {returncodigoPostal;

    }publicvoid setCodigoPostal(int codigoPostal) {

    this.codigoPostal = codigoPostal;}

    publicProvincia getProvincia() {returnprovincia;

    }

    publicvoid setProvincia(Provincia provincia) {

  • 5/24/2018 OpenXava-Manual.pdf

    46/115

    this.provincia = provincia;}

    }

    Como se ve una clase incrustable puede implementar una interfaz (1) ycontener referencias (2), entre otras cosas, pero no puede tener coleccionespersistentes ni usar mtodos de retrollamada de JPA.Este cdigo se puede usar as, para leer:

    Cliente cliente = ...Direccion direccion = cliente.getDireccion();direccion.getCalle();// para obtener el valor

    O as para establecer una nueva direccin

    // para establecer una nueva direccinDireccion direccion = newDireccion();direccion.setCalle(Mi calle);direccion.setCodigoPostal(46001);direccion.setMunicipio(Valencia);direccion.setProvincia(provincia);cliente.setDireccion(direccion);

    En este caso que tenemos una referencia simple, el cdigo generado es un

    simple JavaBean, cuyo ciclo de vida esta asociado a su objeto contenedor,es decir, la Direccionse borrar y crear junto al Cliente, jamas tendr vidapropia ni podr ser compartida por otro Cliente.

    Colecciones incrustadasLas colecciones incrustadas no se soportan en JPA 1.0. Pero podemossimularlas usando colecciones a entidades con tipo de cascada REMOVE oALL. OpenXava trata estas colecciones de una manera especial, como sifueran colecciones incrustadas.Ahora un ejemplo de una coleccin incrustada. En la entidad principal (por

    ejemplo de Factura) podemos poner:@OneToMany (mappedBy="factura", cascade=CascadeType.REMOVE)privateCollection lineas;

    Es de notar que usamos CascadeType.REMOVEy LineaFacturaes unaentidad y no una clase incrustable:

    packageorg.openxava.test.model;

    importjava.math.*;

    importjavax.persistence.*;

  • 5/24/2018 OpenXava-Manual.pdf

    47/115

    importorg.hibernate.annotations.Columns;

    importorg.hibernate.annotations.Type;

    importorg.hibernate.annotations.Parameter;importorg.hibernate.annotations.GenericGenerator;importorg.openxava.annotations.*;importorg.openxava.calculators.*;importorg.openxava.test.validators.*;

    /**** @author Javier Paniza

    */

    @Entity

    @EntityValidator(value=ValidadorLineaFactura.class,properties= {

    @PropertyValue(name="factura"),@PropertyValue(name="oid"),@PropertyValue(name="producto"),@PropertyValue(name="precioUnitario")

    })publicclassLineaFactura {

    @ManyToOne// 'Lazy fetching' produce un falla al borrar una linea desdela factura

    privateFactura factura;

    @Id @GeneratedValue(generator="system-uuid") @Hidden@GenericGenerator(name="system-uuid", strategy = "uuid")privateStringoid;

    privateTipoServicio tipoServicio;publicenumTipoServicio { ESPECIAL, URGENTE }

    @Column(length=4) @Requiredprivateint cantidad;

    @Stereotype("DINERO") @RequiredprivateBigDecimalprecioUnitario;

    @ManyToOne(fetch=FetchType.LAZY, optional=false)privateProducto producto;

  • 5/24/2018 OpenXava-Manual.pdf

    48/115

    @DefaultValueCalculator(CurrentDateCalculator.class)

    privatejava.util.DatefechaEntrega;

    @ManyToOne(fetch=FetchType.LAZY)privateComercial vendidoPor;

    @Stereotype("MEMO")privateStringobservaciones;

    @Stereotype("DINERO") @Depends("precioUnitario, cantidad")publicBigDecimalgetImporte() {

    returngetPrecioUnitario().multiply(newBigDecimal(getCantidad()));

    }

    publicboolean isGratis() {returngetImporte().compareTo(newBigDecimal("0"))

  • 5/24/2018 OpenXava-Manual.pdf

    49/115

    returnprecioUnitario==null?BigDecimal.ZERO:precioUnitario;

    }

    publicvoid setPrecioUnitario(BigDecimalprecioUnitario) {

    this.precioUnitario = precioUnitario;}

    publicProduct getProducto() {returnproducto;

    }

    publicvoid setProducto(Producto producto) {this.producto = producto;

    }publicjava.util.DategetFechaEntrega() {

    returnfechaEntrega;}

    publicvoid setFechaEntrega(java.util.DatefechaEntrega) {this.fechaEntrega = fechaEntrega;

    }

    publicSeller getVendidoPor() {returnvendidoPor;

    }

    publicvoid setVendidoPor(Comercial vendidoPor) {this.vendidoPor = vendidoPor;

    }

    publicStringgetObservaciones() {

    returnobservaciones;}

    publicvoid setObservaciones(Stringobservaciones) {

    this.observaciones = observaciones;}

    publicInvoice getFactura() {returnfactura;

    }

    publicvoid setFactura(Factura factura) {this.factura = factura;

  • 5/24/2018 OpenXava-Manual.pdf

    50/115

    }

    }Como se ve esto es una entidad compleja, con calculadores, validadores,referencias y as por el estilo. Tambin hemos de definir una referencia a suclase contenedora (factura). En este caso cuando una factura se borre todassus lneas se borrarn tambin. Adems hay diferencias a nivel de interfacegrfica (podemos aprender ms en el captulo de la vista).

    HerenciaOpenXava soporta la herencia de herencia de JPAy Java.Por ejemplo podemos definer una superclase mapeada

    (@MappedSuperclass) de esta manera:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    importorg.hibernate.annotations.*;importorg.openxava.annotations.*;

    /*** Clase base para definir entidades con un oid UUID.

    ** @author Javier Paniza*/

    @MappedSuperclasspublicclassIdentificable {

    @Id @GeneratedValue(generator="system-uuid") @Hidden@GenericGenerator(name="system-uuid", strategy = "uuid")privateStringoid;

    publicStringgetOid() {

    returnoid;}

    publicvoid setOid(Stringoid) {

    this.oid = oid;}

    }

  • 5/24/2018 OpenXava-Manual.pdf

    51/115

    Podemos definir otra @MappedSuperclassque extienda de esta, porejemplo:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    importorg.openxava.annotations.*;

    /*** Clase base para entidades con una propiedad 'nombre'.

    ** @author Javier Paniza

    */@MappedSuperclasspublicclassConNombre extendsIdentifiable {

    @Column(length=50) @RequiredprivateStringnombre;

    publicStringgetNombre() {

    returnnombre;}

    publicvoid setNombre(Stringnombre) {

    this.nombre = nombre;}

    }

    Ahora podemos usar Identificabley ConNombrepara definir nuestraentidades, como sigue:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    /**** @author Javier Paniza*/

    @Entity

    @DiscriminatorColumn(name="TYPE")@DiscriminatorValue("HUM")

  • 5/24/2018 OpenXava-Manual.pdf

    52/115

    @Table(name="PERSONA")@AttributeOverrides(

    @AttributeOverride(name="name",column=@Column(name="PNOMBRE")))publicclassHumano extendsConNombre {

    @Enumerated(EnumType.STRING)privateSexo sexo;publicenumSexo { MASCULINO, FEMENINO };

    publicSexo getSexo() {

    returnsexo;}publicvoid setSexo(Sexo sexo) {

    this.sexo = sexo;}

    }

    Y ahora, la autntica herencia de entidades, una entidad que extiende deotra entidad:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    /**** @author Javier Paniza*/

    @Entity

    @DiscriminatorValue("PRO")publicclassProgramador extendsHumano {

    @Column(length=20)privateStringlenguajePrincipal;

    publicStringgetLenguajePrincipal() {

    returnlenguajePrincipal;}

    publicvoid setLenguajePrincipal(StringlenguajePrincipal) {

  • 5/24/2018 OpenXava-Manual.pdf

    53/115

    this.lenguajePrincipal = lenguajePrincipal;}

    }

    Podemo crear un mdulo OpenXavapara Humanoy Programador(nopara Identificableni ConNombredirectamente). En el mdulode Programadorel usuario puede acceder solo a programadores, por otraparte usando el mdulo de Humanoel usuario puede acceder a objetos detipo Humanoy Programador. Adems cuando el usuario trata de visualizar eldetalle de unProgramadordesde el mdulo de Humanose mostrar la vistade Programador. Polimorfismo puro.

    Sobre el mapeo, se soporta @AttributeOverrides, pero, de momento, solo laestrategia una nica tabla por jerarqua de clases funciona.

    Clave mltipleLa forma preferida para definir la clave de una entidad es una clave nicaautogenerada (anotada con @Idy@GeneratedValue), pero a veces, porejemplo cuando vamos contra bases de datos legadas, necesitamos teneruna entidad mapeada a una tabla que usa varias columnas como clave. Estecaso se pude resolver con JPA (y por tanto con OpenXava) de dos formas,usando @IdClasso usando @EmbeddedId

    Clase idEn este caso usamos @IdClassen nuestra entidad para indicar una claseclave, y marcamos las propiedades clave como@Iden nuestra entidad:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    importorg.openxava.annotations.*;importorg.openxava.jpa.*;

    /**** @author Javier Paniza*/

    @Entity

    @IdClass(AlmacenKey.class)publicclassAlmacen {

    @Id

  • 5/24/2018 OpenXava-Manual.pdf

    54/115

    // Column tambin se especifica en AlmacenKey por un bug en Hibernate,ver

    // http://opensource.atlassian.com/projects/hibernate/browse/ANN-361@Column(length=3, name="ZONA")privateint codigoZona;

    @Id @Column(length=3)privateint codigo;

    @Column(length=40) @RequiredprivateStringnombre;

    publicStringgetNombre() {

    returnnombre;}

    publicvoid setNombre(Stringnombre) {

    this.nombre = nombre;}

    publicint getCodigo() {returncodigo;

    }

    publicvoid setCodigo(int codigo) {this.codigo = codigo;

    }

    publicint getCodigoZona() {returncodigoZona;

    }

    publicvoid setCodigoZona(int codigoZona) {this.codigoZona = codigoZona;}

    }

    Tambin necesitamos declarar una clase id, una clase serializable normal ycorriente con todas las propiedades clave de la entidad:

    packageorg.openxava.test.model;

  • 5/24/2018 OpenXava-Manual.pdf

    55/115

    importjava.io.*;importjavax.persistence.*;

    /**** @author Javier Paniza*/

    publicclassAlmacenKey implementsSerializable{

    @Column(name="ZONE")privateint codigoZona;

    privateint codigo;@Overridepublicboolean equals(Objectobj) {

    if (obj == null) returnfalse;returnobj.toString().equals(this.toString());

    }

    @Overridepublicint hashCode() {

    returntoString().hashCode();

    }

    @OverridepublicStringtoString() {

    return"AlmacenKey::" + codigoZona + ":" + codigo;}

    publicint getCodigo() {returncodigo;

    }

    publicvoid setCodigo(int codigo) {this.codigo = codigo;

    }

    publicint getCodigoZona() {returncodigoZona;

    }

    publicvoid setCodigoZona(int codigoZona) {this.codigoZona = codigoZona;

  • 5/24/2018 OpenXava-Manual.pdf

    56/115

    }

    }

    Id inscrustadoEn este case tenemos una referencia a un objeto incrustado (@Embeddable)marcada como @EmbeddedId:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    importorg.openxava.annotations.*;

    /**** @author Javier Paniza*/

    @Entity

    publicclassAlmacen {

    @EmbeddedIdprivateAlmacenKey clave;

    @Column(length=40) @RequiredprivateStringnombre;

    publicAlmacenKey getClave() {returnclave;

    }

    publicvoid setClave(AlmacenKey clave) {

    this.clave = clave;}

    publicStringgetNombre() {

    returnnombre;}

    publicvoid setNombre(Stringnombre) {

    this.nombre = nombre;}

  • 5/24/2018 OpenXava-Manual.pdf

    57/115

    }

    Y nuestra clave es una clase incrustable que contiene las propiedades clave:

    packageorg.openxava.test.model;

    importjavax.persistence.*;

    /**** @author Javier Paniza*/

    @EmbeddablepublicclassAlmacenKey implementsjava.io.Serializable{

    @Column(length=3, name="ZONA")privateint codigoZona;

    @Column(length=3)privateint codigo;

    publicint getCodigo() {returncodigo;

    }

    publicvoid setCodigo(int codigo) {this.codigo = codigo;

    }

    publicint getCodigoZona() {returncodigoZona;

    }

    publicvoid setCodigoZona(int codigoZona) {this.codigoZona = codigoZona;

    }

    }

    Hibernate Validator (nuevo en v3.0.1)OpenXava tiene soporte completo de Hibernate Validator. Podemos definir

    nuestras propias restricciones en nuestras entidades como se explica en

  • 5/24/2018 OpenXava-Manual.pdf

    58/115

    la documentacin de Hibernate Validator, y OpenXava las reconocer,mostrando los mensajes de error correspondientes al usuario.Adems, las anotaciones deOpenXava @Required, @PropertyValidator y @EntityValidator estndefinidas como restricciones de Hibernate Validator, esto significa quecuando grabamos una entidad usando directamente JPA estas validacionesse aplicarn.Por otraparte, @RemoveValidator, @PropertyValidator(onlyOnCreate=true), EntityValidator(onlyOnCreate=true)y lacaracterstica de validor por defecto deOpenXava no son reconocidas ni por Hibernate Validator ni por JPA, sinosolo por OpenXava.

    Captulo 5: Datos tabularesDatos tabulares son aquellos que se visualizan en formato de tabla. Cuando creamosun mdulo de OpenXava convencional el usuario puede gestionar la informacin sobreese componente con una lista como sta:

    Esta lista permite al usuario:

    Filtrar por cualquier columna o combinacin de ellas. Ordenar por cualquier columna con un simple click.

  • 5/24/2018 OpenXava-Manual.pdf

    59/115

    Visualizar los datos paginados, y as podemos leer eficientemente tablas de millonesde registros.

    Personalizar la lista: aadir, quitar y cambiar de orden las columnas (con el lapicito quehay en la parte superior izquierdas). Las personalizaciones se recuerdan por cadausuario.

    Acciones genricas para procesar la lista: Como la de generar un informe en PDF,exportar a Excel o borrar los registros seleccionados.

    La lista por defecto suele ir bien, y adems el usuario puede personalizarsela. Sinembargo, a veces conviene modificar el comportamiento de la lista. Esto se hacemediante la anotacin @Tabdentro de la definicin de la entidad.La sintaxis de @Tabes:

    @Tab(

    name="nombre", // 1filter=clase del filtro, // 2

    rowStyles=array de @RowStyle, // 3properties="propiedades", // 4

    baseCondition="condicin base", // 5

    defaultOrder="orden por defecto" // 6

    )

    publicclassMyEntity {

    1. name(opcional): Podemos definir varios tabs para una entidad (mediante la

    anotacin @Tabs), y ponerle un nombre a cada uno. Este nombre se usar despuspara indicar que tab queremos usar (normalmente en aplicacin.xmlal definir unmdulo).

    2. filter(opcional): Permite definir programticamente un filtro a realizar sobre los valoresque introduce el usuario cuando quiere filtrar.

    3. rowStyles(varios, opcional): Una forma sencilla de especificar una estilo devisualizacin diferente para ciertas filas. Normalmente para resaltar filas que cumplencierta condicin. Especificamos un array de @RowStyle, as podemos usar varios estilopor tab.

    4. properties(opcional): La lista de propiedades a visualizar inicialmente. Pueden sercalificadas.

    5. baseCondition(opcional): Es una condicin que aplicar siempre a los datosvisualizados aadiendose a las que pueda poner el usuario.

    6. defaultOrder(opcional): Para especificar el orden en que aparece los datos en la listainici