Openxava 3.1.4 XML Classic Components - Es
Openxava 3.1.4 XML Classic Components - Es
VERSIÓN 3.1.4
OpenXava 3.1.4 1
Contenido
° ° ° ° °
Contenido
OpenXava 3.1.4 2
Contenido
° ° ° ° °
OpenXava 3.1.4 3
° ° ° ° °
OpenXava 3.1.4 4
Capítulo 1: Introducción a los componentes XML clásicos
° ° ° ° °
OpenXava 3.1.4 5
° ° ° ° °
Implementación en Java
Actualmente OpenXava genera código para las siguiente 4 alternativas:
1. Clases de Java convencionales (los famosos POJOs) para el modelo
usando Hibernate para la persistencia (nuevo en v2.1).
2. Clases de Java convencionales para el modelo usando EJB3 JPA (Java
Persistence API) para la persistencia.
3. Los clásicos EntityBeans de EJB2 para el modelo y la persistencia.
4. POJOs + Hibernate dentro de un contenedor EJB.
La opción 2 es la opción por defecto (nuevo en v3.0) y la más adecuada para
la mayoría de los casos. La opción 1 es también buena, especialmente si
necesitamos usar Java 1.4. La opción 3 es para soportar todas las
aplicaciones OpenXava escritas con EJB2 (EJB2 era la única opción en
OpenXava 1.x). La opción 4 puede ser útil en ciertas circunstancias. Podemos
ver como configurar esto en OpenXavaTest/properties/xava.properties.
Componente de negocio
Como bien hemos visto la unidad básica para crear una aplicación OpenXava
es el componente de negocio. Un componente de negocio se define en un
archivo XML. La estructura de un componente de negocio en OpenXava es:
<?xml version="1.0" encoding="ISO-8859-1"?>
OpenXava 3.1.4 6
Capítulo 2: Modelo XML (clásico)
<componente nombre="NombreComponente">
</component>
Entidad y agregados
La definición de la entidad y de los agregados es prácticamente idéntica. La
entidad es el objeto principal que representa al concepto de negocio,
mientras que los agregados son objetos adicionales necesarios para definir el
concepto de negocio pero que por sí solos no pueden tener vida propia. Por
ejemplo, al definir un componente Factura, los datos de cabecera de la
factura estarían en la entidad, mientras que para las líneas podríamos poner
un agregado LineaFactura; podemos notar como el ciclo de vida de un línea
de factura está ligado a la factura, esto es una línea de factura sin factura
no tiene sentido, y compartir una línea entre varias facturas no es posible,
por eso lo modelamos como un agregado.
OpenXava 3.1.4 7
Capítulo 2: Modelo XML (clásico)
Entidad
La sintaxis de la entidad es como sigue:
<entidad>
<bean ... /> <!-- 1 -->
<ejb ... /> <!-- 2 -->
<implementa .../> <!-- 3 -->
<propiedad .../> <!-- 4 -->
<referencia .../> <!-- 5 -->
<coleccion .../> <!-- 6 -->
<metodo .../> <!-- 7 -->
<buscador .../> <!-- 8 -->
<calculador-poscrear .../> <!-- 9 -->
<calculador-poscargar .../> <!-- 10 -->
<calculador-posmodificar .../> <!-- 11 -->
<calculador-preborrar .../> <!-- 12 -->
<validador .../> <!-- 13 -->
<validador-borrar .../> <!-- 14 -->
</entidad>
OpenXava 3.1.4 8
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 9
Capítulo 2: Modelo XML (clásico)
Bean (1)
Con <bean/> podemos especificar que deseamos usar nuestra propia clase
Java.
Por ejemplo:
<entidad>
<bean clase="org.openxava.test.modelo.Familia"/>
...
De esta forma tan simple podemos escribir nuestro propio código Java en vez
de dejar que OpenXava lo genere.
Por ejemplo podemos escribir la clase Familia como sigue:
package org.openxava.test.modelo;
import java.io.*;
/**
* @author Javier Paniza
*/
public class Familia implements Serializable {
OpenXava 3.1.4 10
Capítulo 2: Modelo XML (clásico)
<!DOCTYPE hibernate-mapping
SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.openxava.test.modelo">
<class
name="Familia"
table="XAVATEST@separator@FAMILIA">
</class>
</hibernate-mapping>
EJB (2)
Con <ejb/> podemos especificar que queremos usar un EJB propio.
Por ejemplo:
OpenXava 3.1.4 11
Capítulo 2: Modelo XML (clásico)
<entidad>
<ejb remote="org.openxava.test.ejb.Family"
home="org.openxava.test.ejb.FamilyHome"
primaryKey="org.openxava.test.ejb.FamilyKey"
jndi="ejb/openxava.test/Family"/>
...
De esta forma tan sencilla podemos escribir nuestro código EJB a mano, en
vez de usar el código que OpenXava genera.
El código EJB lo podemos escribir manualmente de forma íntegra (pero eso
solo si somos hombre de verdad), si somos programadores al uso(quiero decir
vagos) preferiremos usar los asistentes de un IDE, o mejor aún XDoclet. Si
optamos por usar XDoclet, podemos poner nuestras clases XDoclet en el
paquete modelo (o cualquier otro paquete, depende del valor que demos a la
variable model.package en nuestro build.xml) de la carpeta src de nuestro
proyecto; y nuestro código XDoclet se generará junto con el resto de código
OpenXava.
Para nuestro ejemplo podriamos escribir una clase FamiliaBean como sigue:
package org.openxava.test.ejb.xejb;
import java.util.*;
import javax.ejb.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @ejb:bean name="Familia" type="CMP" view-type="remote"
* jndi-name="OpenXavaTest/ejb/openxava.test/Familia"
* @ejb:interface extends="org.openxava.ejbx.EJBReplicable"
* @ejb:data-object extends="java.lang.Object"
* @ejb:home extends="javax.ejb.EJBHome"
* @ejb:pk extends="java.lang.Object"
*
* @jboss:table-name "XAVATEST@separator@FAMILIA"
*
* @author Javier Paniza
*/
abstract public class FamiliaBean
extends org.openxava.ejbx.EJBReplicableBase // 1
implements javax.ejb.EntityBean {
/**
* @ejb:interface-method
* @ejb:pk-field
* @ejb:persistent-field
*
OpenXava 3.1.4 12
Capítulo 2: Modelo XML (clásico)
* @jboss:column-name "OID"
*/
public abstract String getOid();
public abstract void setOid(String nuevoOid);
/**
* @ejb:interface-method
* @ejb:persistent-field
*
* @jboss:column-name "CODIGO"
*/
public abstract int getCodigo();
/**
* @ejb:interface-method
*/
public abstract void setCodigo(int newCodigo);
/**
* @ejb:interface-method
* @ejb:persistent-field
*
* @jboss:column-name "DESCRIPCION"
*/
public abstract String getDescripcion();
/**
* @ejb:interface-method
*/
public abstract void setDescripcion(String newDescripcion);
/**
* @ejb:create-method
*/
public FamilyKey ejbCreate(Map propiedades) // 2
throws
javax.ejb.CreateException,
org.openxava.validators.ValidationException,
java.rmi.RemoteException {
executeSets(propiedades);
try {
setOid((String)calculadorOid.calculate());
}
catch (Exception ex) {
ex.printStackTrace();
throw new EJBException(
"Imposible crear Familia por:\n" +
ex.getLocalizedMessage()
);
}
return null;
}
OpenXava 3.1.4 13
Capítulo 2: Modelo XML (clásico)
Implementa (3)
Con <implementa/> especificamos una interfaz Java que será implementada
por el código generado. Como sigue:
<entidad>
<implementa interfaz="org.openxava.test.modelo.IConNombre"/>
...
<propiedad nombre="nombre" tipo="String" requerido="true"/>
...
import java.rmi.*;
/**
* @author Javier Paniza
*/
public interface IConNombre {
OpenXava 3.1.4 14
Capítulo 2: Modelo XML (clásico)
Propiedad (4)
Una propiedad OpenXava corresponde exactamente a una propiedad Java.
Representa parte del estado de un objeto que se puede consultar y en
algunos casos cambiar. El objeto no tiene la obligación de guardar
físicamente la información de la propiedad, solo de devolverla cuando se le
pregunte.
La sintaxis para definir una propiedad es:
<propiedad
nombre="nombrePropiedad" <!-- 1 -->
etiqueta="etiqueta" <!-- 2 -->
tipo="tipo" <!-- 3 -->
estereotipo="ESTEREOTIPO" <!-- 4 -->
longitud="longitud" <!-- 5 -->
escala="longitud" <!-- 6 nuevo en v2.0.4 -->
requerido="true|false" <!-- 7 -->
OpenXava 3.1.4 15
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 16
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 17
Capítulo 2: Modelo XML (clásico)
Estereotipo
Un estereotipo es la forma de determinar un comportamiento especifico
dentro de un tipo. Por ejemplo, un nombre, un comentario, una descripción,
etc. todos corresponden al tipo Java java.lang.String pero si queremos que los
validadores, logitud por defecto, editores visuales, etc. sean diferente en cada
caso y necesitamos afinar más; lo podemos hacer asignando un esterotipo a
cada uno de estos casos. Es decir, podemos tener los estereotipos NOMBRE,
TEXTO_GRANDE o DESCRIPCION y asignarlos a nuestras 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 nuevo en v2.0
• RELLENADO_CON_CEROS, ZEROS_FILLED nuevo en v2.0.2
• TEXTO_HTML, HTML_TEXT (texto con formato editable) nuevo en v2.0.3
• ETIQUETA_IMAGEN, IMAGE_LABEL (imagen que depende del contenido
de la propiedad) nuevo en v2.1.5
• EMAIL nuevo en 2.2.3
• TELEFONO, TELEPHONE nuevo en 2.2.3
• WEBURL nuevo en 2.2.3
• IP nuevo en 2.2.4
• ISBN nuevo en 2.2.4
• TARJETA_CREDITO, CREDIT_CARD nuevo en 2.2.4
• LISTA_EMAIL, EMAIL_LIST nuevo en 2.2.4
Vamos a ver como definiríamos un estereotipo propio. Crearemos uno
llamado NOMBRE_PERSONA para representar nombres de persona.
Editamos (o creamos) el archivo editors.xml o editores.xml en nuestra carpeta
xava. Y añadimos
<editor url="editorNombrePersona.jsp">
<para-estereotipo estereotipo="NOMBRE_PERSONA"/>
</editor>
OpenXava 3.1.4 18
Capítulo 2: Modelo XML (clásico)
En este caso asume 40 longitud y tipo String, así como ejecutar el validador
NotBlankCharacterValidator para comprobar que es requerido.
OpenXava 3.1.4 19
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 20
Capítulo 2: Modelo XML (clásico)
Valores posibles
El elemento <valores-posibles/> permite definir una propiedad que solo
puede contener los valores indicados. Digamos que es algo así como el enum
de C (o Java 5).
Es fácil de usar, veamos un ejemplo:
<propiedad nombre="distancia">
<valores-posibles>
<valor-posible valor="local"/>
<valor-posible valor="nacional"/>
<valor-posible valor="internacional"/>
</valores-posibles>
</propiedad>
Calculador
Un calculador indica que lógica hay que usar cuando se llame al método
getter de la propiedad. Las propiedades que definen un calculador son de
solo lectura (solo tienen getter) y no son persistentes (no tienen
OpenXava 3.1.4 21
Capítulo 2: Modelo XML (clásico)
import java.math.*;
import org.openxava.calculators.*;
/**
* @author Javier Paniza
*/
public class CalculadorEurosAPesetas implements ICalculator { // 1
OpenXava 3.1.4 22
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 23
Capítulo 2: Modelo XML (clásico)
</calculador>
</propiedad>
Y el calculador:
package org.openxava.test.calculators;
import java.math.*;
import java.rmi.*;
import java.util.*;
import javax.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
OpenXava 3.1.4 24
Capítulo 2: Modelo XML (clásico)
import java.sql.*;
import org.openxava.calculators.*;
import org.openxava.util.*;
/**
* @author Javier Paniza
*/
public class CalculadorCantidadLineas implements IJDBCCalculator { // 1
OpenXava 3.1.4 25
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 26
Capítulo 2: Modelo XML (clásico)
En este caso cuando el usuario intente crear una factura nueva (por ejemplo)
se encontrará que el campo año ya tiene un valor, que el usuario puede
cambiar si desea.
Podemos indicar que calcule el valor justo antes de crear (insertar en la base
datos) el objeto por primera vez; eso se hace así:
<propiedad nombre="oid" tipo="String" clave="true" oculta="true">
<calculador-valor-defecto
clase="org.openxava.calculators.UUIDCalculator"
al-crear="true"/>
</propiedad>
O quizás queramos usar una columna identity (auto incremento) como clave:
<propiedad nombre="id" clave="true" tipo="int" oculta="true">
<calculador-valor-defecto
OpenXava 3.1.4 27
Capítulo 2: Modelo XML (clásico)
clase="org.openxava.calculators.IdentityCalculator" al-crear="true"/>
</propiedad>
Validador
El validador ejecuta la lógica de validación sobre el valor que se vaya a
asignar a esa propiedad antes de grabar. Una propiedad puede tener varios
validadores.
<propiedad nombre="description" tipo="String" longitud="40" requerido="true">
<validador clase="org.openxava.test.validadores.ValidadorExcluirCadena">
<poner propiedad="cadena" valor="MOTO"/>
</validador>
<validador clase="org.openxava.test.validadores.ValidadorExcluirCadena"
solo-al-crear="true">
<poner propiedad="cadena" valor="COCHE"/>
</validador>
</propiedad>
import org.openxava.util.*;
import org.openxava.validators.*;
/**
* @author Javier Paniza
*/
OpenXava 3.1.4 28
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 29
Capítulo 2: Modelo XML (clásico)
archivo de mensajes.
La validación es satisfactoria si no se añaden mensajes y se supone fallida si
se añaden. El sistema recolecta todos los mensajes de todos los validadores
antes de grabar y si encuentra los visualiza al usuario y no graba.
El paquete org.openxava.validators contiene algunos validadores de uso
común.
OpenXava 3.1.4 30
Capítulo 2: Modelo XML (clásico)
Referencia (5)
Una referencia hace que desde una entidad o agregado se pueda acceder
otra entidad o agregado. Una referencia se traduce a código Java como una
propiedad (con su getter y su setter) cuyo tipo es el del modelo al que se
referencia. Por ejemplo un Cliente puede tener una referencia a su Comercial,
y así podemos escribir código Java como éste:
ICliente cliente = ...
cliente.getComercial().getNombre();
OpenXava 3.1.4 31
Capítulo 2: Modelo XML (clásico)
OpenXava 3.1.4 32
Capítulo 2: Modelo XML (clásico)
Como se puede ver se devuelve un entero, es decir, el valor para familia por
defecto es la familia cuyo código es el 2.
En el caso de clave compuesta sería así:
<referencia nombre="almacen" modelo="Almacen">
<calculador-valor-defecto
clase="org.openxava.test.calculadores.CalculadorDefectoAlmacen"/>
</referencia>
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
public class CalculadorDefectoAlmacen implements ICalculator {
OpenXava 3.1.4 33
Capítulo 2: Modelo XML (clásico)
Colección (6)
Con <coleccion/> definimos una colección de referencias a entidades o
agregados. Esto se traduce en una propiedad Java que devuelve
java.util.Collection.
Aquí la sintaxis para definir una colección:
<coleccion
nombre="nombre" <!-- 1 -->
etiqueta="etiqueta" <!-- 2 -->
minimo="N" <!-- 3 -->
maximo="N" <!-- 4 nuevo en v2.0.3 -->
>
<referencia ... /> <!-- 5 -->
<condicion ... /> <!-- 6 -->
<orden ... /> <!-- 7 -->
<calculador ... /> <!-- 8 -->
<calculador-posborrar ... /> <!-- 9 -->
</coleccion>
OpenXava 3.1.4 34
Capítulo 2: Modelo XML (clásico)
<coleccion nombre="albaranes">
<referencia modelo="Albaran"/>
</coleccion>
Para hacer algo con todos los albaranes asociados a una factura.
Vamos a ver otro ejemplo más complejo, también dentro de Factura:
<coleccion nombre="lineas" minimo="1"> <!-- 1 -->
<referencia modelo="LineaFactura"/>
<orden>${tipoServicio} desc</orden> <!-- 2 -->
<calculador-posborrar <!-- 3 -->
clase="org.openxava.test.calculadores.CalculadorPosborrarLineaFactura"/>
</coleccion>
En este caso tenemos una colección de agregados, las líneas de las facturas.
La diferencia entre una colección de agregados y una de referencia, es que
cuando se borrar la entidad principal los elementos de las colecciones de
agregados también se borran. Esto es al borrar una factura sus líneas se
borran automáticamente.
1. La restricción de minimo="1" hace que sea obligado que haya al
menos una línea para que la factura sea válida.
2. Con orden obligamos a que las lineas se devuelvan ordenadas por
tipoServicio.
3. Con calculador-posborrar indicamos un calculador a ejecutar justo
después de borrar un elemento de la colección.
Veamos el código de este calculador:
package org.openxava.test.calculadores;
import java.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
OpenXava 3.1.4 35
Capítulo 2: Modelo XML (clásico)
*/
public class CalculadorPosborrarLineaFactura implements IModelCalculator {
OpenXava 3.1.4 36
Capítulo 2: Modelo XML (clásico)
<referencia modelo="Transportista"/>
<calculador
clase="org.openxava.test.calculadores.CalculadorCompañerosTransportista"/>
</coleccion>
import java.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
public class CalculadorCompañerosTransportista implements IModelCalculator {
/* Usando EJB2
return TransportistaUtil.getHome().findCompañerosOfTransportista(
transportista.getAlmacenKey().getCodigoZona(),
transportista.getAlmacenKey().get_Codigo(),
new Integer(transportista.getCodigo())
);
*/
OpenXava 3.1.4 37
Capítulo 2: Modelo XML (clásico)
Método (7)
Con <metodo/> podemos definir un método qué será incluido en el código
generado.
La sintaxis para definir un método es:
<metodo
nombre="nombre" <!-- 1 -->
tipo="tipo" <!-- 2 -->
argumentos="argumentos" <!-- 3 -->
excepciones="excepciones" <!-- 4 -->
>
<calculador ... /> <!-- 5 -->
</metodo>
OpenXava 3.1.4 38
Capítulo 2: Modelo XML (clásico)
import java.math.*;
import java.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.modelo.*;
/**
* @author Javier Paniza
*/
public class CalculadorIncrementarPrecio implements IModelCalculator {
Todo lo que se dijo para los calculadores cuando se habló de las propiedades
aplica a los métodos también, con los siguientes matices:
OpenXava 3.1.4 39
Capítulo 2: Modelo XML (clásico)
import java.math.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
OpenXava 3.1.4 40
Capítulo 2: Modelo XML (clásico)
Los métodos son la salsa de los objetos, sin ellos solo serían caparazones
tontos alrededor de los datos. Cuando sea posible es mejor poner la lógica
de negocio en los métodos (capa del modelo) que en las acciones (capa del
controlador).
Buscador (8)
Un buscador es un método especial que nos permite encontrar un objeto o
una colección de objetos que cumplen un solo criterio. En la versión POJO un
buscador es un método estático generado en la clase POJO. En la versión
EJB2 un buscador corresponde con un finder del home.
La sintaxis para definir buscadores es:
OpenXava 3.1.4 41
Capítulo 2: Modelo XML (clásico)
<buscador
nombre="nombre" <!-- 1 -->
argumentos="argumentos" <!-- 2 -->
coleccion="(true|false)" <!-- 3 -->
>
<condicion ... /> <!-- 4 -->
<orden ... /> <!-- 5 -->
</buscador>
<buscador
nombre="byNombreLikeYRelacionConComercial"
argumentos="String nombre, String relacionConComercial"
coleccion="true">
<condicion>${nombre} like {0} and ${relacionConComercial} = {1}</condicion>
<orden>${nombre} desc</orden>
</buscador>
OpenXava 3.1.4 42
Capítulo 2: Modelo XML (clásico)
// EJB2
ICliente cliente = ClienteUtil.getHome().findByCodigo(8);
Collection javieres = ClienteUtil.getHome().findByNombreLike("%JAVI%");
import java.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
public class CalculadorPoscrearTipoAlbaran implements IModelCalculator {
OpenXava 3.1.4 43
Capítulo 2: Modelo XML (clásico)
En este caso cada vez que se graba por primera vez un TipoAlbaran, justo
después se añade un sufijo a su descripción.
Como se ve es exactamente igual que cualquier otro calculador (como para
propiedades calculadas o métodos) solo que este se ejecuta después de
crear.
OpenXava 3.1.4 44
Capítulo 2: Modelo XML (clásico)
import java.rmi.*;
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
/**
* @author Javier Paniza
*/
Validador (13)
Este validador permite poner una validación a nivel de modelo. Cuando
necesitamos hacer una validación sobre varias propiedades del modelo, y
esta validación no corresponde lógicamente a ninguna de ellas se puede usar
este tipo de validación.
Su sintaxis es:
OpenXava 3.1.4 45
Capítulo 2: Modelo XML (clásico)
<validador
clase="validador" <!-- 1 -->
nombre="nombre" <!-- 2 -->
solo-al-crear="true|false" <!-- 3 -->
>
<poner ... /> <!-- 4 -->
</validador>
import java.math.*;
import org.openxava.util.*;
import org.openxava.validators.*;
/**
* @author Javier Paniza
*/
public class ValidadorProductoBarato implements IValidator { // 1
OpenXava 3.1.4 46
Capítulo 2: Modelo XML (clásico)
errores.add("producto_barato", getLimiteBd()); // 3
}
}
}
OpenXava 3.1.4 47
Capítulo 2: Modelo XML (clásico)
de vetar el borrado.
Su sintaxis es:
<validador-borrar
clase="validador" <!-- 1 -->
nombre="nombre" <!-- 2 -->
>
<poner ... /> ... <!-- 3 -->
</validador-borrar>
Y el validador:
package org.openxava.test.validadores;
import java.util.*;
import org.openxava.test.ejb.*;
import org.openxava.util.*;
import org.openxava.validators.*;
/**
* @author Javier Paniza
*/
public class ValidadorBorrarTipoAlbaran implements IRemoveValidator { // 1
OpenXava 3.1.4 48
Capítulo 2: Modelo XML (clásico)
Agregado
La sintaxis de un agregado es como sigue:
<agregado nombre="agregado"> <!-- 1 -->
<bean clase="claseBean"/> <!-- 2 -->
<ejb ... /> <!-- 3 -->
<implementa .../>
<propiedad .../> ...
<referencia .../> ...
<coleccion .../> ...
<metodo .../> ...
<buscador .../> ...
<calculador-poscrear .../> ...
<calculador-posmodificar .../> ...
<validador .../> ...
<validador-borrar .../> ...
</agregado>
OpenXava 3.1.4 49
Capítulo 2: Modelo XML (clásico)
Referencia a agregado
El primer ejemplo es un agregado Direccion que es referenciado desde la
entidad principal.
En la entidad principal pondremos:
<referencia nombre="direccion" modelo="Direccion" requerido="true"/>
Colección de agregados
Ahora un ejemplo de una colección de agregados. En la entidad principal (por
ejemplo de Factura) podemos poner:
OpenXava 3.1.4 50
Capítulo 2: Modelo XML (clásico)
<validador clase="org.openxava.test.validadores.ValidadorLineaFactura">
<poner propiedad="factura"/>
<poner propiedad="oid"/>
<poner propiedad="producto"/>
<poner propiedad="precioUnitario"/>
</validador>
</agregado>
Como podemos ver un agregado es tan complejo como una entidad, con
calculadores, validadores, referencias y todo lo que queramos. En el caso de
un agregado usado en una colección, como este caso, automáticamente se
añade una referencia al contenedor, es decir, aunque no lo hayamos definido,
LineaFactura tiene una referencia a Factura.
OpenXava 3.1.4 51
Capítulo 2: Modelo XML (clásico)
En este caso usamos factura en el atributo desde (1) aunque factura no está
declarada en LineaFactura. Nuevo en v2.1.1: usar referencia a propiedades
clave del modelo padre en el atributo desde (es decir, desde="factura.año")
Relaciones de muchos-a-muchos
En OpenXava no existe el concepto directo de relación muchos-a-muchos, en
lugar de eso en OpenXava solo existen colecciones. Aun así modelar una
relación muchos-a-muchos con OpenXava is fácil. Solo necesitamos definir
colecciones en ambas partes de la relación.
Por ejemplo, si tenemos clientes y provincias, y un cliente puede trabajar en
varias provincias, y, obviamente, en una provincia pueden trabajar varios
clientes, tenemos un caso de relación muchos-a-muchos (usando la
nomenclatura relacional). Suponiendo que tenemos una tabla CLIENTE (sin
referencia a provincia), una tabla PROVINCIA (sin referencia a clientes) y una
tabla CLIENTE_PROVINCIA (para vincular ambas tablas), este caso podemos
modelarlo así:
OpenXava 3.1.4 52
Capítulo 2: Modelo XML (clásico)
<componente nombre="Cliente">
<entidad>
...
<coleccion nombre="provincias"> <!-- 1 -->
<referencia modelo="ClienteProvincia"/>
</coleccion>
...
</entidad>
OpenXava 3.1.4 53
Capítulo 2: Modelo XML (clásico)
<propiedades-lista>
provincia.id, provincia.nombre <!-- 1 -->
</list-properties>
</vista-coleccion>
<miembros>
...
provincias
...
</miembros>
</vista>
<vista modelo="ClienteProvincia">
<vista-referencia referencia="provincia" marco="false"/> <!-- 2 -->
</vista>
...
</componente>
En esta vista podemos ver como definimos explicitamente (1) las propiedades
a mostrar en la lista de la colección provincias. Esto es necesario porque
tenemos que mostrar las propiedades de Provincia, no las de ClienteProvincia.
Adicionalmente, definimos que la referencia a Provincia en ClienteProvincia se
muestre sin marcos (2), de esta forma evitamos dos feos marcos anidados.
De esta manera podemos definir una colección que mapea a una relación de
muchos a muchos en la base de datos. Si queremos que la relación sea
bidireccional solo tenemos que crear una colección clientes en la entidad
Provincia, esta colección puede ser de tipo agregado ProvinciaCliente y tiene
que mapearse a la tabla CLIENTE_PROVINCIA. Todo exactamente igual que en
el ejemplo aquí mostrado.
OpenXava 3.1.4 54
Capítulo 2: Modelo XML (clásico)
° ° ° ° °
OpenXava 3.1.4 55
° ° ° ° °
OpenXava genera a partir del modelo una interfaz gráfica de usuario por
defecto. Para muchos casos sencillos esto es suficiente, pero muchas veces
es necesario modelar con más precisión la forma de la interfaz de usuario o
vista. En este capítulo vamos a ver cómo.
La sintaxis para definir una vista es:
<vista
nombre="nombre" <!-- 1 -->
etiqueta="etiqueta" <!-- 2 -->
modelo="modelo" <!-- 3 -->
miembros="miembros" <!-- 4 -->
hereda-de="vista" <!-- 5 Nuevo en v3.1.2 -->
>
<propiedad ... /> ... <!-- 6 -->
<vista-propiedad ... /> ... <!-- 7 -->
<vista-referencia ... /> ... <!-- 8 -->
<vista-coleccion ... /> ... <!-- 9 -->
<miembros ... /> ... <!-- 10 -->
</vista>
OpenXava 3.1.4 56
Capítulo 3: Vista XML (clásico)
Disposición
Por defecto (es decir si no definimos ni siquiera el elemento <view/> en
nuestro componente) se visualizan todos los miembros del objeto en el orden
en que están en el modelo, y se disponen uno debajo del otro.
Por ejemplo, un modelo así:
<entidad>
<propiedad nombre="codigoZona" clave="true"
longitud="3" requerido="true" tipo="int"/>
<propiedad nombre="codigoOficina" clave="true"
longitud="3" requerido="true" tipo="int"/>
<propiedad nombre="codigo" clave="true"
longitud="3" requerido="true" tipo="int"/>
<propiedad nombre="nombre" tipo="String"
longitud="40" requerido="true"/>
</entidad>
OpenXava 3.1.4 57
Capítulo 3: Vista XML (clásico)
Grupos
Con los grupos podemos agrupar un conjunto de propiedades relacionadas, y
esto tiene un efecto visual:
<vista>
<miembros>
<grupo nombre="id">
codigoZona, codigoOficina, codigo
</grupo>
; nombre
</miembros>
</vista>
OpenXava 3.1.4 58
Capítulo 3: Vista XML (clásico)
Si queremos que aparezca uno debajo del otro debemos poner un punto y
coma después del grupo, como sigue:
<grupo nombre="cliente">
tipo;
nombre;
</grupo>;
<grupo nombre="comercial">
comercial;
relacionConComercial;
</grupo>
OpenXava 3.1.4 59
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 60
Capítulo 3: Vista XML (clásico)
Obtendremos lo siguiente:
OpenXava 3.1.4 61
Capítulo 3: Vista XML (clásico)
Esto es feo. Sería mejor tener la información alineada por columnas. Podemos
definir el grupo de esta forma:
<vista nombre="Importes">
<miembros>
año, numero;
<grupo nombre="importes" alineado-por-columnas="true"> <!-- 1 -->
descuentoCliente, descuentoTipoCliente, descuentoAño;
sumaImportes, porcentajeIVA, iva;
</grupo>
</miembros>
</vista>
Secciones
Además de en grupo los miembros se pueden organizar en secciones,
veamos un ejemplo en el componente Factura:
<vista>
<miembros>
año, numero, fecha, pagada;
descuentoCliente, descuentoTipoCliente, descuentoAño;
comentario;
<seccion nombre="cliente">cliente</seccion>
<seccion nombre="lineas">lineas</seccion>
<seccion nombre="importes">sumaImportes; porcentajeIVA; iva</seccion>
<seccion nombre="albaranes">albaranes</seccion>
</miembros>
</vista>
OpenXava 3.1.4 62
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 63
Capítulo 3: Vista XML (clásico)
Nuevo en v2.0.4: Al igual que en los grupos, las secciones permiten usar el
atributo alineado-por-columna, así:
<seccion nombre="importes" alineado-por-columnas="true"> ... </seccion>
Si ahora queremos crear una nueva vista que extienda de esta simplemente
hemos de escribir:
OpenXava 3.1.4 64
Capítulo 3: Vista XML (clásico)
y obtendremos lo siguiente:
OpenXava 3.1.4 65
Capítulo 3: Vista XML (clásico)
Vista propiedad
Con <vista-propiedad/> podemos refinar la forma de visualización y
comportamiento de una propiedad en la vista:
Tiene esta sintaxis:
<vista-propiedad
propiedad="nombrePropiedad" <!-- 1 -->
etiqueta="etiqueta" <!-- 2 -->
solo-lectura="true|false" <!-- 3 -->
formato-etiqueta="NORMAL|PEQUENA|SIN_ETIQUETA" <!-- 4 -->
editor="nombreEditor" <!-- 5 nuevo en v2.1.3 -->
longitud-visual="longitud" <!-- 6 nuevo en v2.2.1 -->
>
<al-cambiar ... /> <!-- 7 -->
<accion ... /> ... <!-- 8 -->
</vista-propiedad>
OpenXava 3.1.4 66
Capítulo 3: Vista XML (clásico)
Formato de etiqueta
Un ejemplo sencillo para cambiar el formato de la etiqueta:
<vista modelo="Direccion">
<vista-propiedad propiedad="codigoPostal" formato-etiqueta="PEQUENA"/>
</vista>
import org.openxava.actions.*;
/**
* @author Javier Paniza
*/
public class AlCambiarTransportistaEnAlbaran
extends OnChangePropertyBaseAction { // 1
OpenXava 3.1.4 67
Capítulo 3: Vista XML (clásico)
getView().setValue("observaciones", // 3
"El transportista es " + getNewValue());
addMessage("transportista_cambiado");
}
Acciones de la propiedad
También podemos especificar acciones que el usuario puede pulsar
directamente:
<vista-propiedad propiedad="numero">
<accion accion="Albaranes.generarNumero"/>
</vista-propiedad>
OpenXava 3.1.4 68
Capítulo 3: Vista XML (clásico)
import org.openxava.actions.*;
/**
* @author Javier Paniza
*/
public class GenerarNumeroAlbaran extends ViewBaseAction {
import org.openxava.actions.*;
import org.openxava.view.*;
/**
* @author Javier Paniza
*/
public class GenerarNumeroAlbaran
extends BaseAction
implements IPropertyAction { // 1
private View view;
private String property;
OpenXava 3.1.4 69
Capítulo 3: Vista XML (clásico)
}
public void setView(View view) { // 4
this.view = view;
}
}
Esta acción implementa IPropertyAction (1), esto requiere que la clase tenga
los métodos setProperty() (3) y setView() (4), estos valores serán inyectados
en la acción antes de llamar al método execute(), donde pueden ser usados
(2). En este caso no necesitas inyectar el objeto xava_view al definir la acción
en controladores.xml. La vista inyectada por setView() (4) es la vista más
interna que contiene la propiedad, por ejemplo, si la propiedad está dentro
de un agregado es la vista de ese agregado, no la vista principal del módulo.
De esta manera podemos escribir acciones más reutilizables.
Este editor está incluido con OpenXava, pero nosotros podemos crear nuestro
propios editores con nuestro propios JSPs y declararlos en el archivo xava/
editores.xml de nuestro proyecto.
Esta característica es para cambiar el editor solo en una vista. Si lo que se
pretende es cambiar el editor para un estereotipo, tipo o una propiedad de
OpenXava 3.1.4 70
Capítulo 3: Vista XML (clásico)
Vista referencia
Con <vista-referencia/> modificamos la forma en que se visualiza una
referencia.
Su sintaxis es:
<vista-referencia
referencia="referencia" <!-- 1 -->
vista="vista" <!-- 2 -->
solo-lectura="true|false" <!-- 3 -->
marco="true|false" <!-- 4 -->
crear="true|false" <!-- 5 -->
modificar="true|false" <!-- 6 nuevo en v2.0.4 -->
buscar="true|false" <!-- 7 -->
como-agregado="true|false" <!-- 8 nuevo en v2.0.3 -->
editor="nombreEditor" <!-- 9 nuevo en v3.1.3 -->
>
<busqueda-al-cambiar ... /> <!-- 10 nuevo en v2.2.5 -->
<accion-buscar ... /> <!-- 11 -->
<lista-descriptiones ... /> <!-- 12 -->
<accion ... /> ... <!-- 13 nuevo en v2.0.1 -->
</vista-referencia>
OpenXava 3.1.4 71
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 72
Capítulo 3: Vista XML (clásico)
Escoger vista
La modificación más sencilla sería especificar que vista del objeto
referenciado queremos usar:
<vista-referencia referencia="factura" vista="Simple"/>
Para esto en el componente Factura tenemos que tener una vista llamada
simple:
<componente nombre="Factura">
...
<vista nombre="Simple">
<miembros>
año, numero, fecha, descuentoAño;
</miembros>
</vista>
...
</componente>
Personalizar el enmarcado
Si combinamos marco="false" con un grupo podemos agrupar visualmente
una propiedad que no forma parte de la referencia, por ejemplo:
OpenXava 3.1.4 73
Capítulo 3: Vista XML (clásico)
Así obtendríamos:
Ahora al pulsar la linternita ejecuta nuestra acción, la cual tenemos que tener
definida en controladores.xml:
<controlador nombre="MiReferencia">
<accion nombre="buscar" oculta="true"
clase="org.openxava.test.acciones.MiAccionBuscar"
imagen="images/search.gif">
<usa-objeto nombre="xava_view"/>
OpenXava 3.1.4 74
Capítulo 3: Vista XML (clásico)
<usa-objeto nombre="xava_referenceSubview"/>
<usa-objeto nombre="xava_tab"/>
<usa-objeto nombre="xava_currentReferenceLabel"/>
</accion>
...
</controlador>
import org.openxava.actions.*;
/**
* @author Javier Paniza
*/
OpenXava 3.1.4 75
Capítulo 3: Vista XML (clásico)
<hereda-de controlador="NewCreation"/>
<accion nombre="new" oculta="true"
clase="org.openxava.test.actions.CrearNuevoAlmacenDesdeReferencia">
<usa-objeto nombre="xava_view"/>
</accion>
</controlador>
OpenXava 3.1.4 76
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 77
Capítulo 3: Vista XML (clásico)
<vista-referencia referencia="almacen">
<lista-descripciones/>
</vista-referencia>
OpenXava 3.1.4 78
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 79
Capítulo 3: Vista XML (clásico)
<vista-referencia referencia="subfamilia">
<busqueda-al-cambiar clase="org.openxava.test.acciones.BuscarAlCambiarSubfamilia"/>
</vista-referencia>
import org.openxava.actions.*;
/**
*
* @author Javier Paniza
*/
public class BuscarAlCambiarSubfamilia
extends OnChangeSearchAction { // 1
OpenXava 3.1.4 80
Capítulo 3: Vista XML (clásico)
Vista colección
Sirve para refinar la presentación de una colección. Aquí su sintaxis:
<vista-coleccion
coleccion="coleccion" <!-- 1 -->
vista="vista" <!-- 2 -->
solo-lectura="true|false" <!-- 3 -->
solo-edicion="true|false" <!-- 4 -->
crear-referencia="true|false" <!-- 5 -->
modificar-referencia="true|false" <!-- 6 nuevo en v2.0.4 -->
como-agregado="true|false" <!-- 7 nuevo en v2.0.2 -->
editor="nombreEditor" <!-- 8 nuevo en v3.1.3 -->
>
<propiedades-lista ... /> <!-- 9 -->
<estilo-fila ... /> <!-- 10 nuevo en v2.2.2 -->
<accion-editar ... /> <!-- 11 -->
<accion-ver ... /> <!-- 12 -->
<accion-nuevo ... /> <!-- 13 nuevo en v2.0.2 -->
<accion-grabar ... /> <!-- 14 nuevo en v2.0.2 -->
<accion-ocultar-detalle ... /> <!-- 15 nuevo en v2.0.2 -->
<accion-quitar ... /> <!-- 16 nuevo en v2.0.2 -->
<accion-quitar-seleccionados ... /> <!-- 17 nuevo en v2.1 -->
<accion-lista ... /> ... <!-- 18 -->
<accion-detalle ... /> ... <!-- 19 -->
<accion-al-seleccionar-elemento ... /> <!-- 20 nuevo en v3.1.2 -->
</vista-coleccion>
OpenXava 3.1.4 81
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 82
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 83
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 84
Capítulo 3: Vista XML (clásico)
OpenXava 3.1.4 85
Capítulo 3: Vista XML (clásico)
package org.openxava.test.acciones;
import java.text.*;
import org.openxava.actions.*;
/**
* @author Javier Paniza
*/
public class EditarLineaFactura extends EditElementInCollectionAction { // 1
En este caso queremos solamente refinar y por eso nuestra acción desciende
de (1) EditElementInCollectionAction. Nos limitamos a poner un valor por
defecto en la propiedad observaciones. Es de notar que para acceder a la
vista que visualiza el detalle podemos usar el método
getCollectionElementView() (2).
También es posible eliminar la acción para editar de la interfaz de usuario
(nuevo en v2.2.1), de esta manera:
<vista-coleccion coleccion="lineas">
<accion-editar accion=""/>
</vista-coleccion>
Sólo necesitamos poner una cadena vacía como valor para la acción. Aunque
en la mayoría de los casos es suficiente declarar la colección como de
solo-lectura.
La técnica para refinar una acción 'ver' (la acción para cada fila cuando la
colección es de solo lectura) es la misma pero usando <accion-ver/> en vez
de <accion-editar/>.
OpenXava 3.1.4 86
Capítulo 3: Vista XML (clásico)
Vemos además como ahora hay una casilla de chequeo en cada línea (desde
v2.1.4 la casilla de chequeo está siempre presente en todas las colecciones).
Falta definir la acción en controladores.xml:
<controlador nombre="Transportistas">
<accion nombre="traducirNombre"
clase="org.openxava.test.acciones.TraducirNombreTransportista">
</accion>
</controlador>
import java.util.*;
import org.openxava.actions.*;
import org.openxava.test.modelo.*;
/**
* @author Javier Paniza
*/
public class TraducirNombreTransportista extends CollectionBaseAction { // 1
OpenXava 3.1.4 87
Capítulo 3: Vista XML (clásico)
De esta forma todas las colecciones tendrán las acciones del controlador Print
(para exportar a Excel y generar informes PDF) y nuestra propia acción
ExportarComoXML. Esto tiene el mismo efecto que el elemento accion-lista
pero aplica a todas las colecciones a la vez.
Esta característica no aplica a las colecciones calculadas (nuevo en v2.2.1).
OpenXava 3.1.4 88
Capítulo 3: Vista XML (clásico)
import java.util.*;
import javax.ejb.*;
import org.openxava.actions.*;
/**
* @author Javier Paniza
*/
public class VerProductoDesdeLineaFactura
extends CollectionElementViewBaseAction // 1
implements INavigationAction {
OpenXava 3.1.4 89
Capítulo 3: Vista XML (clásico)
}
catch (Exception ex) {
ex.printStackTrace();
addError("system_error");
}
}
OpenXava 3.1.4 90
Capítulo 3: Vista XML (clásico)
import org.openxava.actions.*;
/**
*
* @author Javier Paniza
*/
OpenXava 3.1.4 91
Capítulo 3: Vista XML (clásico)
De esta manera tan sencilla (1) estamos diciendo que cuando el usuario haga
click en la casilla de chequeo (checkbox) de la fila, la acción
Formula.alSeleccionarIngrediente se ejecutará. Esta acción se declara en
controladores.xml, de esta manera:
<controlador nombre="Formula">
...
<accion nombre="alSeleccionarIngredientes" oculta="true"
clase="org.openxava.test.acciones.AlSeleccionarIngrediente">
<usa-objeto nombre="xava_view"/>
</accion>
...
OpenXava 3.1.4 92
Capítulo 3: Vista XML (clásico)
</controlador>
OpenXava 3.1.4 93
Capítulo 3: Vista XML (clásico)
Propiedad de vista
Poniendo <propiedad/> dentro de una vista podemos usar una propiedad que
no existe en el modelo, pero que sí nos interesa que se visualice al usuario.
Podemos usarlas para proporcionar controles al usuario para manejar la
interfaz gráfica.
Un ejemplo:
<vista>
<propiedad nombre="entregadoPor">
<valores-posibles>
<valor-posible valor="empleado"/>
<valor-posible valor="transportista"/>
</valores-posibles>
<calculador-valor-defecto
clase="org.openxava.calculators.IntegerCalculator">
<poner propiedad="value" valor="0"/>
</calculador-valor-defecto>
</propiedad>
<vista-propiedad propiedad="entregadoPor">
<al-cambiar clase="org.openxava.test.actiones.AlCambiarEntregadoPor"/>
</vista-propiedad>
...
</vista>
OpenXava 3.1.4 94
Capítulo 3: Vista XML (clásico)
<miembros>
codigo;
tipo;
nombre, <accion accion="Clientes.cambiarEtiquetaDeNombre"/>;
...
</miembros>
OpenXava 3.1.4 95
Capítulo 3: Vista XML (clásico)
<!--
Ejemplo de componente OpenXava transitorio (no persistente).
<componente nombre="FiltrarPorSubfamilia">
<entidad>
<referencia nombre="subfamilia" modelo="Subfamilia2" requerido="true"/>
</entidad>
<vista nombre="Familia1">
<vista-referencia referencia="subfamilia" crear="false">
<lista-descripciones condicion="${familia.codigo} = 1"/>
</vista-referencia>
</vista>
<vista nombre="Familia2">
<vista-referencia referencia="subfamilia" crear="false">
<lista-descripciones condicion="${familia.codigo} = 2"/>
</vista-referencia>
</vista>
<vista nombre="ConFormularioDeSubfamilia">
<vista-referencia referencia="subfamily" buscar="false"/>
</vista>
</componente>
OpenXava 3.1.4 96
Capítulo 3: Vista XML (clásico)
° ° ° ° °
OpenXava 3.1.4 97
° ° ° ° °
OpenXava 3.1.4 98
Capítulo 4: Datos tabulares XML (clásico)
OpenXava 3.1.4 99
Capítulo 4: Datos tabulares XML (clásico)
</propiedades>
</tab>
import java.util.*;
import org.openxava.filters.*;
/**
* @author Javier Paniza
*/
return r;
}
Un filtro recoge los argumentos que el usuario teclea para filtrar la lista y los
procesa devolviendo lo que al final se envía a OpenXava para que haga la
consulta. Como se ve ha de implementar IFilter (1) lo que lo obliga a tener
un método llamado filter (2) que recibe un objeto que el valor de los
argumentos y devuelve los argumentos que al final serán usados. Estos
argumentos pueden ser nulo (3), si el usuario no ha metidos valores, un
objeto simple (5), si el usuario a introducido solo un valor o un array de
objetos (4), si el usuario a introducidos varios valores. El filtro ha de
contemplar bien todos los casos. En el ejemplo lo que hacemos es añadir
delante el año actual, y así se usa como argumento a la condición que
hemos puesto en nuestro tab.
Resumiendo el tab que vemos arriba solo sacará las facturas
import java.util.*;
import org.openxava.filters.*;
/**
* @author Javier Paniza
*/
getAñoDefecto() (2) que a su vez llama a getInteger() (3) el cual (al igual que
getString(), getLong() o el más genérico get()) nos permite acceder al valor
del objeto xavatest_añoDefecto. Esto objeto lo definimos en nuestro archivo
controladores.xml de esta forma:
<objeto nombre="xavatest_añoDefecto" clase="java.lang.Integer" valor="1999"/>
Las acciones lo pueden modificar y tiene como vida la sesión del usuario y
es privado para cada módulo. De esto se habla más profundamente en el
capítulo sobre controladores.
Esto es una buena técnica para que en modo lista aparezcan unos datos u
otros según el usuario o la configuración que éste haya escogido.
También es posible acceder a variables de entorno dentro de un filtro (nuevo
en v2.0) de tipo BaseContextFilter, usando el método getEnvironment(), de
esta forma:
new Integer(getEnvironment().getValue("XAVATEST_AÑO_DEFECTO"));
Select íntegro
Tenemos la opción de poner el select completo para obtener los datos del
tab:
<tab nombre="SelectIntegro">
<propiedades>codigo, descripcion, familia</propiedades>
<condicion-base>
select ${codigo}, ${descripcion}, XAVATEST@[email protected]
from XAVATEST@separator@SUBFAMILIA, XAVATEST@separator@FAMILIA
where XAVATEST@[email protected] =
XAVATEST@[email protected]
</condicion-base>
</tab>
<tab nombre="Simple">
<propiedades>año, numero, fecha</properties>
<orden-defecto>${año} desc, ${numero} desc</orden-defecto>
</tab>
Este orden es solo el inicial, el usuario puede escoger otro con solo pulsar la
cabecera de una columna.
° ° ° ° °
Mapeo de entidad
La sintaxis para mapear la entidad principal es:
<mapeo-entidad tabla="tabla"> <!-- 1 -->
<mapeo-propiedad ... /> ... <!-- 2 -->
<mapeo-referencia ... /> ... <!-- 3 -->
<mapeo-propiedad-multiple ... /> ... <!-- 4 -->
</mapeo-entidad>
Mapeo propiedad
La sintaxis para mapear una propiedad es:
<mapeo-propiedad
propiedad-modelo="propiedad" <!-- 1 -->
columna-tabla="columna" <!-- 2 -->
tipo-cmp="tipo" <!-- 3 -->
formula="formula"> <!-- 4 New in v3.1.4 -->
<conversor ... /> <!-- 5 -->
</mapeo-propiedad>
/**
* In java an int and in database a String.
*
* @author Javier Paniza
*/
public class IntegerStringConverter implements IConverter { // 1
Al poner 'LNI' como valor para letters, hace corresponder la L con 1, la N con
2 y la I con 3. Vemos como el que se puedan configurar propiedades del
conversor (como se hacía con los calculadores, validadores, etc) nos permite
hacer conversores reutilizables.
Mapeo referencia
La sintaxis para mapear una referencia es:
<mapeo-referencia
referencia-modelo="referencia" <!-- 1 -->
>
<detalle-mapeo-referencia ... /> ... <!-- 2 -->
</mapeo-referencia>
<mapeo-entidad tabla="XAVATEST@separator@ALBARAN">
<mapeo-referencia referencia-modelo="factura">
<detalle-mapeo-referencia
columna-tabla="FACTURA_AÃ?O"
propiedad-modelo-referenciado="año"/>
<detalle-mapeo-referencia
columna-tabla="FACTURA_NUMERO"
propiedad-modelo-referenciado="numero"/>
</mapeo-referencia>
...
</mapeo-entidad>
<mapeo-referencia referencia="permisoConducir">
<detalle-mapeo-referencia
columna-tabla="PERMISOCONDUCIR_TIPO"
propiedad-modelo-referenciado="tipo"
tipo-cmp="String"> <!-- 1 En esta caso esta linea puede ser omitida -->
<conversor clase="org.openxava.converters.NotNullStringConverter"/> <!-- 2 -->
</detalle-mapeo-referencia>
<detalle-mapeo-referencia
columna-tabla="PERMISOCONDUCIR_NIVEL"
propiedad-modelo-referenciado="nivel"/>
</mapeo-referencia>
Podemos usar el conversor igual que en el caso de una propiedad simple (1).
La diferencia en el caso de las referencias es que si no asignamos conversor
no se usa ningún conversor por defecto, esto es porque aplicar de forma
indiscriminada conversores sobre información que se usa para buscar puede
ser problemático. Podemos usar tipo-cmp (1) (nuevo en v2.0) para indicar que
tipo para el atributo es usado internamente en nuestro objeto para almacenar
el valor. Esto nos permite usar un tipo Java más cercano al de la base de
datos; tipo-cmp no es necesario si el tipo de la base de datos es compatible
con el tipo Java.
import java.util.*;
import org.openxava.util.*;
/**
* In java a <tt>java.util.Date</tt> and in database 3 columns of
* integer type. <p>
*
* @author Javier Paniza
*/
public class Date3Converter implements IMultipleConverter { // 1
}
java.util.Date fecha = (java.util.Date) objetoJava;
Calendar cal = Calendar.getInstance();
cal.setTime(fecha);
setDay(cal.get(Calendar.DAY_OF_MONTH));
setMonth(cal.get(Calendar.MONTH) + 1);
setYear(cal.get(Calendar.YEAR));
}
dirección se guardan en la misma tabla que los del cliente. ¿Cómo se expresa
eso en OpenXava? Es muy sencillo. En el modelo nos encontramos:
<entidad>
...
<referencia nombre="direccion" modelo="Direccion" requerido="true"/>
...
</entidad>
<agregado nombre="Direccion">
<implementa interfaz="org.openxava.test.ejb.IConMunicipio"/>
<propiedad nombre="calle" tipo="String" longitud="30" requerido="true"/>
<propiedad nombre="codigoPostal" tipo="int" longitud="5" requerido="true"/>
<propiedad nombre="municipio" tipo="String" longitud="20" requerido="true"/>
<referencia nombre="provincia" requerido="true"/>
</agregado>
<agregado nombre="LineaFactura">
<propiedad nombre="oid" tipo="String" clave="true" oculta="true">
<calculador-valor-defecto
clase="org.openxava.test.calculadores.CalculadorOidLineaFactura"
al-crear="true"/>
</propiedad>
<propiedad nombre="tipoServicio">
<valores-posibles>
<valor-posible valor="especial"/>
<valor-posible valor="urgente"/>
</valores-posibles>
</propiedad>
<propiedad nombre="cantidad" tipo="int" longitud="4" requerido="true"/>
<propiedad nombre"precioUnitario" estereotipo="DINERO" requerido="true"/>
<propiedad nombre="importe" estereotipo="DINERO">
<calculador clase="org.openxava.test.calculadores.CalculadorImporteLinea">
<poner propiedad="precioUnitario"/>
<poner propiedad="cantidad"/>
</calculador>
</propiedad>
<referencia modelo="Producto" requerido="true"/>
<propiedad nombre="fechaEntrega" tipo="java.util.Date">
<calculador-valor-defecto
clase="org.openxava.calculators.CurrentDateCalculator"/>
</propiedad>
<referencia nombre="vendidoPor" modelo="Comercial"/>
<propiedad nombre="observaciones" estereotipo="MEMO"/>
</agregado>
<!--
In your project use the name 'converters.xml' or 'conversores.xml'
-->
<converters>
<for-type type="java.lang.String"
converter-class="org.openxava.converters.TrimStringConverter"
cmp-type="java.lang.String"/>
<for-type type="int"
converter-class="org.openxava.converters.IntegerNumberConverter"
cmp-type="java.lang.Integer"/>
<for-type type="java.lang.Integer"
converter-class="org.openxava.converters.IntegerNumberConverter"
cmp-type="java.lang.Integer"/>
<for-type type="boolean"
converter-class="org.openxava.converters.Boolean01Converter"
cmp-type="java.lang.Integer"/>
<for-type type="java.lang.Boolean"
converter-class="org.openxava.converters.Boolean01Converter"
cmp-type="java.lang.Integer"/>
<for-type type="long"
converter-class="org.openxava.converters.LongNumberConverter"
cmp-type="java.lang.Long"/>
<for-type type="java.lang.Long"
converter-class="org.openxava.converters.LongNumberConverter"
cmp-type="java.lang.Long"/>
<for-type type="java.math.BigDecimal"
converter-class="org.openxava.converters.BigDecimalNumberConverter"
cmp-type="java.math.BigDecimal"/>
<for-type type="java.util.Date"
converter-class="org.openxava.converters.DateUtilSQLConverter"
cmp-type="java.sql.Date"/>
</converters>
<componente nombre="Alumno">
<entidad>
<propiedad nombre="numero" tipo="int" clave="true"
longitud="2" requerido="true"/>
<propiedad nombre="nombre" tipo="String"
longitud="40" requerido="true"/>
<referencia nombre="profesor"/>
</entidad>
</componente>
° ° ° ° °
Introducción a AOP
AOP (Programación Orientada a Aspectos) introduce una nueva forma de
reutilizar código. Realmente complementa algunas deficiencias de la
programación orientada a objetos tradicional.
¿Qué problema resuelve AOP? A veces tenemos funcionalidad que es común
a un grupo de clases pero usar herencia no es práctico (en Java solo
contamos con herencia simple) ni ético (porque se rompe la relación es-un).
Además el sistema puede esta ya escrito, o quizá necesitamos poder incluir o
no la funcionalidad bajo demanda. AOP es una manera fácil de resolver estos
problemas.
¿Qué es un aspecto? Un aspecto es un puñado de código que puede ser
esparcido a nuestro gusto por la aplicación.
El lenguaje Java ofrece un soporte completo de AOP mediante el proyecto
AspectJ.
OpenXava añade algún soporte para el concepto de aspectos desde la
versión 1.2.1. El soporte de aspectos para los componentes XML es pequeño,
pero si usamos POJOs + anotaciones (desde la versión 3.0) podemos usar
AspectJ y disfrutar de toda la fuerza de los aspectos.
Definición de aspectos
El archivo aspectos.xml dentro de la carpeta xava de nuestro proyecto se usa
para definir los aspectos.
Su sintaxis es:
<aspectos>
<aspecto ... /> ... <!-- 1 -->
<aplicar ... /> ... <!-- 2 -->
</aspectos>
1. nombre (obligado): Nombre para este aspecto. Tiene que ser único.
2. calculador-poscrear (varios, opcional): Todos los modelos con este
aspecto tendrán este calculador-poscrear implícitamente.
3. calculador-poscargar (varios, opcional): Todos los modelos con este
aspecto tendrán este calculador-poscargar implícitamente.
4. calculador-posmodificar (varios, opcional): Todos los modelos con
este aspecto tendrán este calculador-posmodificar implícitamente.
5. calculador-preborrar (varios, opcional): Todos los modelos con este
aspecto tendrán este calculador-preborrar implícitamente.
Además, tenemos que asignar el aspecto que hemos definido a nuestros
modelos. La sintaxis para eso es:
<aplicar
aspecto="aspecto" <!-- 1 -->
para-modelos="modelos" <!-- 2 -->
excepto-para-modelos="modelos" <!-- 3 -->
/>
De esta forma tan sencilla podemos hacer que cuando un nuevo objeto se
cree (se grabe en la base de datos por primera vez) la lógica en
MiCalculador sea ejecutada. Y esto para todos los modelos.
Como se ve, solo unos pocos calculadores son soportados de momento.
Esperamos extender las posibilidades de los aspectos en OpenXava en el
futuro. De todas formas, estos calculadores ahora ofrecen posibilidades
interesantes. Veamos un ejemplo en la siguientes sección.
<aspects>
<aspect name="AccessTracking">
<postcreate-calculator
class="org.openxava.tracking.AccessTrackingCalculator">
<set property="accessType" value="Create"/>
</postcreate-calculator>
<postload-calculator
class="org.openxava.tracking.AccessTrackingCalculator">
<set property="accessType" value="Read"/>
</postload-calculator>
<postmodify-calculator
class="org.openxava.tracking.AccessTrackingCalculator">
<set property="accessType" value="Update"/>
</postmodify-calculator>
<preremove-calculator
class="org.openxava.tracking.AccessTrackingCalculator">
<set property="accessType" value="Delete"/>
</preremove-calculator>
</aspect>
</aspects>
<aspectos>
</aspectos>
Configurar AccessTracking
Si queremos usar el aspecto AccessTracking en nuestro proyecto hemos de
seguir los siguientes pasos de configuración:
• Añadir AccessTracking como proyecto referenciado: Dentro de Eclipse
ponerse encima del proyecto, pulsar el botón derecho e ir a
Properties > Java Build Path > Projects.
• Crear la tabla en nuestra base de datos para almacenar el registro de
los accesos. Podemos encontrar los CREATE TABLEs en el archivo
AccessTracking/data/access-tracking-db.script.
<aspectos>
<aplicar aspecto="AccessTracking"/>
</aspectos>
Ahora solo nos queda desplegar el war para nuestro proyecto (nuevo en v2.0).
En el caso de que usemos EJB2 CMP tenemos que regenerar código,
desplegar EJB y desplegar el war para nuestro proyecto.
Los accesos son registrados en una tabla con el nombre TRACKING.ACCESS.
Si lo deseamos podemos desplegar el módulo web o el portlet del proyecto
AccessTracking para tener una aplicación web para examinar los accesos.
Para más detalle podemos echar un vistazo al proyecto OpenXavaTest.