Este documento explica como crear aplicaciones multiesquema con OpenXava.
Las aplicaciones multiesquema funcionan con Hibernate y EJB3 JPA como
mecanismos de persistencia. EJB2 CMP no soporta multiesquema.
Si quieres una aplicación multiempresa sin programar visita la sección
sobre
multitenencia.
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.
Aplicacion
contra múltiples bases de datos (new in v4.2.2)
En lugar de varios esquemas en la misma aplicación puedes optar por usar
varias bases de datos completamente diferentes. Para hacer esto sigue las
instrucciones de abajo cambiando el controlador
DefaultSchema
por
PersistenceUnit y
SetDefaultSchemaAction por
SetPersistenceUnitAction.
Además, has de definir varias unidades de persistencia en
persistence.xml,
una por cada base de datos.
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"/> <!-- No necesario desde v4m2 -->
</accion>
<accion nombre="cambiarAEmpresa2"
clase="org.openxava.actions.SetDefaultSchemaAction">
<poner propiedad="newDefaultSchema" value="EMPRESA2"/>
<usa-objeto nombre="xava_defaultSchema"/> <!-- No necesario desde v4m2 -->
</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">
<usa-objeto nombre="xava_defaultSchema"/> <!-- No necesario desde v4m2 -->
</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 {
@Inject // A partir de v4m2
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
/> (en todas las versiones) o
@Inject (desde v4m2) 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 (XHibernate se quitó
en v7.0).
Ahora puedes llamar a esta acción (u otra parecida) cuando quieras cambiar
el esquema actual para el usuario.
Cambiando
de esquema con parámetros en la URL (nuevo en v4m4)
Puede cambiar de esquema a través de parámetros en la URL, observe los
detalles en la sección de
How
to.