Table of Contents

Aplicaciones multiesquema
Aplicaciones multiesquema
Un ejemplo
Cómo funciona

Aplicaciones multiesquema

Este documento explica como crear aplicaciones multiesquema con OpenXava.
Las aplicaciones multiesquema funcionan con Hibernate y EJB3 JPA como mecanismos de persistencia. EJB3 CMP no soporta multiesquema.

Aplicaciones multiesquema

Una aplicación multiesquema permite replicar toda la estructura de tabla de nuestra base de datos en varios esquemas de base de datos. Entonces cada usuario (o en cada sesión) puede trabajar con un esquema diferente, o sea contra diferentes datos.
Por ejemplo, podemos tener los datos de 3 empresas diferentes en el mismo servidor de base de datos. Nuestra aplicación OpenXava, que está desplegadas solo una vez en un servidor de aplicaciones, puede ser usada por los usuarios de estas tres empresas, pero cada empleado solo puede acceder a los datos de su compañia. Una aplicación multiesquema permite implementar esto.
Usar varios esquemas en la base de datos no es solo por seguridad, sino también para evitar tener tablas de base de datos inmensas; porque podemos separar la información por empresas, años, departamentos, municipios, etc.

Un ejemplo

Veamos un ejemplo de un módulo OpenXava que usa multiesquema.
Primero, necesitamos una clase entidad, como esta:
@Entity
public class Incidencia {
 
    @Id @Column(length=5) @Required
    private String id;
 
    @Column(length=40) @Required
    private String descripcion;
 
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
 
    public String getDescripcion() {
        return descripcion;
    }
    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }
 
}
O, si estamos usando los components XML clásicos de OpenXava:
<componente nombre="Incidencia">
    <entidad>
        <propiedad nombre="id" tipo="String" clave="true"
            longitud="5" requerido="true"/>
        <propiedad nombre="descripcion" tipo="String"
            longitud="40" requerido="true"/>
    </entidad>
    <mapeo-entidad tabla="**INCIDENCIA**">
        <mapeo-propiedad
            propiedad-modelo="id" columna-tabla="ID"/>
        <mapeo-propiedad
            propiedad-modelo="descripcion" columna-tabla="DESCRIPCION"/>
    </mapeo-propiedad>
 </componente>
Se puede ver como mapeamos el componente contra la tabla INCIDENCIA, pero no indicamos el esquema.

Ahora, podemos definir el módulo en aplicacion.xml, como sigue:
 <modulo nombre="Incidencias">
    <modelo nombre="Incidencia"/>
    <controlador nombre="Typical"/>
    <controlador nombre="Incidencias"/>
</modulo>
Entonces, definimos nuestro propio controlador Incidencias, en controladores.xml, de esta forma:
<controlador nombre="Incidencias">
    <hereda-de controlador="DefaultSchema"/>
    <accion nombre="cambiarAEmpresa1" al-iniciar="true"
        clase="org.openxava.actions.SetDefaultSchemaAction">
        <poner propiedad="newDefaultSchema" value="EMPRESA1"/>
        <usa-objeto nombre="xava_defaultSchema"/>
    </accion>
    <accion nombre="cambiarAEmpresa2"
        clase="org.openxava.actions.SetDefaultSchemaAction">
        <poner propiedad="newDefaultSchema" value="EMPRESA2"/>
        <usa-objeto nombre="xava_defaultSchema"/>
    </accion>
</controlador>
Y ahora tenemos un modulo que puede trabajar contra el esquema 'EMPRESA1' o contra el esquema 'EMPRESA2'. El usuario solo ha de pulsa en el botón correspondiente para cambiar en caliente el origen de los datos.

Eso es todo.

Cómo funciona

Podemos usar estos controladores y acciones que están listos para usar, pero si además sabemos como funcionan, podemos hacerlo nosotros mismos y así podemos adaptarnos más a nuestras necesidades específicas. La clave está en la clase XPersistence, usando esta clase es posible cambiar el esquema por defecto en tiempo de ejecución:
XPersistence.setDefaultSchema("EMPRESA1");
Esto cambia el esquema por defecto a 'EMPRESA1', pero solo para el hilo de ejecución actual.
Ahora, si usamos un objeto de sesión (ver la sección 7.2 de la guía de referencia) y usamos una acción con en-cada-peticion="true" para establecer el esquema asociado al usuario actual como el esquema por defecto para el hilo de la petición, tendremos el problema resuelto.

Intentemos hacerlo.
Define un objeto de sesión para almacenar el esquema actual por usuario:
<object name="xava_defaultSchema" class="java.lang.String" scope="global"/>
Esto está en OpenXava/xava/default-controllers.xml, por lo tanto está disponible para tí; aunque puedes crearte tu propio objeto de sesión en tu propio controladores.xml si así lo prefieres.

Define una acción (en tu propio controlador) que se ejecute antes de cada petición, en controladores.xml:
<controlador ... >
    <accion nombre="ponerEsquemaPorDefecto" antes-de-cada-peticion="true" oculta="true"
        clase="org.openxava.actions.SetDefaultSchemaAction">
        <use-objeto nombre="xava_defaultSchema"/>
    </accion>
    ...
</controlador>
(El controlador DefaultSchema de OpenXava tiene esta acción incluida)
En esta acción solo necesitas tener el objeto de sesión (en este caso xava_defaultSchema) y ponerlo como esquema por defecto usando XPersistence:
public class SetDefaultSchemaAction extends BaseAction {
 
    private String defaultSchema;
    private String newDefaultSchema;
 
    public void execute() throws Exception {
        if (newDefaultSchema != null)    defaultSchema = newDefaultSchema;
        XPersistence.setDefaultSchema(defaultSchema);
    }
 
    /**
     * The current default schema used by OpenXava and JPA.
     */
    public String getDefaultSchema() {
        return defaultSchema;
    }
 
    /**
     * The current default schema used by OpenXava and JPA.
     */
    public void setDefaultSchema(String company) {
        this.defaultSchema = company;
    }
 
    /**
     * The new default schema for OpenXava and JPA. <P>
     *
     * This value update the property 'defaultSchema'.
     */
    public String getNewDefaultSchema() {
        return newDefaultSchema;
    }
 
    /**
     * The new default schema for OpenXava and JPA. <P>
     *
     * This value update the property 'defaultSchema'.
     */
    public void setNewDefaultSchema(String newCompany) {
        this.newDefaultSchema = newCompany;
    }
}
Ya que defaultSchema es inyectado usando <usa-objeto /> cuando cambiamos la propiedad defaultSchema también estamos cambiando el objeto de sesión xava_defaultSchema.
Esta acción forma parte del nucleo de OpenXava (en org.openxava.actions), puedes usarla tal cual, o crearte la tuya propia usando una técnica similar.

Este técnica se puede usar también con XHibernate.

Ahora puedes llamar a esta acción (u otra parecida) cuando quieras cambiar el esquema actual para el usuario.