====== Ejemplo de implementación de plugin con ampliaciones en tablas/columnas en el diccionario de datos ======
===== Introducción =====
En el [[plugins:ejemploplugin|artículo anterior]] se detalló cómo implementar una serie componentes a fin de incorporar lógica de persistencia o de documentos. Sin embargo, se presenta la problemática de que para el plugin en desarrollo sea necesario incorporar nuevas tablas o columnas a una tabla existente al diccionario de datos.
Será necesario contemplar en estos casos, la utilización de la clase **GenerateModel**, a fin de crear los componentes Java correspondientes. Según la definición del campo **Version de Componente** en tabla y en columna, se crearán clases **X_** (core Libertya) o **LP_** (Libertya Plugin) con el fin de permitir el acceso a los campos desde la clase **M** del plugin (siguiendo el ejemplo anterior: ar.com.disytel.plugin.model.MInvoice).
La siguiente tabla detalla la lógica para la creación de clases utilizando el GenerateModel, en función de la especificación del campo **Versión de Componente**, tanto en definición de tabla como de columna:
| Si la tabla es de **System Core**, se genera el **X_** correspondiente, conteniendo los getters y setters correspondientes a las columnas **System Core** de la tabla. Esta clase extiende de **PO**. Esta es la generación normal de componentes **X_**. |
| Si la tabla es de **System Core**, y existen columnas de **Plugin** para dicha tabla, se genera además un **LP_** conteniendo únicamente los getters y setters correspondientes a las columnas **Plugin** de la tabla. Esta clase extiende de la clase **M** o **X_** de **System Core**, según la existencia de la primera. |
| Si la tabla es de **Plugin**, se genera el **LP_** correspondiente, conteniendo los getters y setters correspondientes a las columnas **Plugin** de la tabla. Esta clase extiende de **PO**. |
| Si la tabla es de **Plugin1**, y existen columnas de otro **Plugin2** para dicha tabla, se genera un **LP_** conteniendo únicamente los getters y setters correspondientes a las columnas del otro **Plugin2** de la tabla. Esta clase extiende de la clase **LP_** del primer plugin **Plugin1**. |
De esta manera, en función de las modificaciones creadas en el diccionario de datos para la definición del plugin, se podrá acceder desde el código a los componentes correspondientes de cada tabla/clase del plugin.
===== Ejemplo de uso de GenerateModel en cada caso =====
A continuación se detalla un ejemplo a fin de comprender el impacto en el uso de esta funcionalidad. Supongamos que para el plugin **DISY** (package (package ar.com.disytel.plugin), es necesario incorporar una nueva columna **aNewColumn** a la tabla **C_Invoice**, y crear además una nueva tabla **C_Example**. Existe además otro plugin **OTHERPLUGIN** (package ar.com.other.plugin) que extiende el previo, para el cual se requiere incorporar una columna **anotherColumn** en la tabla C_Example.
^ Componente ^ Valor ^ Versión del Componente |
| Tabla | C_Invoice | System Core |
| Columna | (columnas de C_Invoice) | System Core |
| Columna | aNewColumn | DISY |
^ Componente ^ Valor ^ Versión del Componente |
| Tabla | C_Example | DISY |
| Columna | (columnas de C_Example) | DISY |
| Columna | anotherColumn | OTHERPLUGIN |
Las clases generadas para la primer tabla serán:
* **org.openXpertya.model.X_C_Invoice**, que extiende de **org.openXpertya.model.PO**
* **ar.com.disytel.plugin.model.LP_C_Invoice**, que extiende de **org.openXpertya.model.MInvoice** si existe, o de **org.openXpertya.model.X_C_Invoice** en caso contrario.
Las clases generadas para la segunda tabla serán:
* **ar.com.disytel.plugin.model.LP_C_Example**, que extiende de **org.openXpertya.model.PO**
* **ar.com.other.plugin.model.LP_C_Example**, que extiende de **ar.com.disytel.plugin.model.LP_C_Example**.
Las clases **LP_** deberán almacenarse en el directorio **model** de la estructura de directorios especificada en el [[plugins:ejemploplugin#configuracion_en_eclipse_para_iniciar_el_desarrollo|artículo anterior]].
__**IMPORTANTE!**__ A fin de evitar sobreescrituras de archivos (notar en el ejemplo que existen dos clases LP_C_Example), las clases **LP_** generadas serán creadas con el package como parte del nombre de archivo. Es necesario quitar este prefijo luego de mover el componente al directorio **model** correspondiente.
Se puede dividir la metodología de implementación de clases de persistencia/documentos M, X, LP_ en cuatro categorías generales:
- **Tablas de Core**: El //owner// de la tabla es el **Core**, y se desea implementar lógica para dicha tabla, dentro del core de la aplicación.
- **Tablas de Plugin**: En este caso el //owner// de la tabla es un plugin, y se desea implementar lógica para dicha tabla, dentro del plugin en desarrollo.
- **Plugin para tablas de Core**: Para una tabla de core, redefinir su lógica por un plugin que incluso podría haber modificado su estructura.
- **Plugin para tablas de Plugin**: Para una tabla plugin, redefinir su lógica por un plugin que incluso podría haber modificado su estructura.
===== 1 - Uso de clases LP_ sobre tablas exclusivas de Core en lógica de persistencia y/o documentos =====
Este es el caso general de desarrollo de core, en donde se tiene la jerarquía **PO -> X_ -> M**. Obviaremos detalles en el presente documento ya que excede la finalidad del mismo.
===== 2 - Uso de clases LP_ sobre tablas exclusivas de un plugin en lógica de persistencia y/o documentos =====
Dado que es una tabla exclusiva de un plugin, la implementación de lógica de persistencia/documentos en este caso es igual al desarrollo de clases **M** de core, sin la utilización de métodos **pre** y **post**. En este caso se tiene la jerarquía **PO → LP_ → M**.
La clase **M** a implementar deberá extender de la clase **LP_** correspondiente. Siguiendo el ejemplo previo, para la tabla C_Example, tendremos las siguientes clases:
* La clase **ar.com.disytel.plugin.model.LP_C_Example**, que extiende de **org.openXpertya.model.PO**
* La clase **ar.com.disytel.plugin.model.MExample**, que extiende de **ar.com.disytel.plugin.model.LP_C_Example**
===== 3 - Uso de clases LP_ sobre tablas de Core ya existente en lógica de persistencia y/o documentos =====
Siguiendo el ejemplo anterior, supongamos una validación en el **preBeforeSave** de la tabla **C_Invoice** que requiere leer el campo exclusivo del plugin **aNewColumn**. En este caso es posible castear el **PO** recibido a **LP_C_Invoice** a fin de obtener el campo **aNewColumn**. Es posible incluso setear campos de C_Invoice pertenecientes al core, como se muestra en el siguiente ejemplo.
__**IMPORTANTE!**__ Es necesario comprender que en este caso se está recibiendo una copia del objeto a persistir, dado que el objeto instanciado inicialmente sigue siendo **org.openXpertya.model.MInvoice**. Las modificaciones realizadas en el preBeforeSave() luego serán propagadas a dicha instancia, con lo cual **NO ES CORRECTO FORZAR UN SAVE() DE LAS CLASES RECIBIDAS EN LOS METODOS Pre y Post.**
package ar.com.disytel.plugin.model;
import java.util.Properties;
import org.openXpertya.model.PO;
import org.openXpertya.plugin.MPluginPO;
import org.openXpertya.plugin.MPluginStatusPO;
public class MInvoice extends MPluginPO {
public MInvoice(PO po, Properties ctx, String trxName, String aPackage) {
super(po, ctx, trxName, aPackage);
}
public MPluginStatusPO preBeforeSave(PO po, boolean newRecord) {
LP_C_Invoice invoice = (LP_C_Invoice)po;
if (invoice.getANewColumn() == null || invoice.getANewColumn().length() == 0)
{
status_po.setContinueStatus(MPluginStatusPO.STATE_FALSE);
status_po.setErrorMessage("Campo aNewColumn es obligatorio!");
}
invoice.setDescription(invoice.getANewColumn());
return status_po;
}
}
De igual manera, es posible realizar procesamiento en lógica de documentos:
package ar.com.disytel.plugin.model;
import java.util.Properties;
import org.openXpertya.model.PO;
import org.openXpertya.plugin.MPluginDocAction;
import org.openXpertya.plugin.MPluginStatusDocAction;
import org.openXpertya.process.DocAction;
public class MInvoice extends MPluginDocAction {
public MInvoice(PO po, Properties ctx, String trxName, String aPackage) {
super(po, ctx, trxName, aPackage);
}
public MPluginStatusDocAction prePrepareIt(DocAction document) {
LP_C_Invoice invoice = (LP_C_Invoice)document;
if (invoice.getANewColumn() == null || invoice.getANewColumn().length() == 0)
{
status_docAction.setContinueStatus(MPluginStatusDocAction.STATE_FALSE);
status_docAction.setDocStatus(DocAction.STATUS_Invalid);
status_docAction.setProcessMsg("Debe completar el dato correspondiente");
}
invoice.setDescription(invoice.getANewColumn());
return status_docAction;
}
}
===== 4 - Uso de clases LP_ sobre tablas de otro plugin ya existente en lógica de persistencia y/o documentos =====
En este caso la metodología es similar a la anterior, se presenta una dependencia de plugins. La diferencia en este caso radica en que en lugar de ser dependencia **Core - Plugin**, es una dependencia **Plugin - Plugin**.
Para una tabla cuyo propietario es el plugin **Plugin1**, y dado un plugin **Plugin2** que contiene campos exclusivos, se podrá realizar el casteo correspondiente desde la invocación a métodos **pre** y **post** en el **Plugin2**.
Siguiendo el ejemplo previo sobre la tabla **C_Example**, tendremos las clases:
* Plugin1:
* La clase **ar.com.disytel.plugin.model.LP_C_Example**, que extiende de **org.openXpertya.model.PO**
* La clase **ar.com.disytel.plugin.model.MExample**, que extiende de **ar.com.disytel.plugin.model.LP_C_Example**
* Plugin2:
* La clase **ar.com.other.plugin.model.LP_C_Example**, que extiende de **ar.com.disytel.plugin.model.LP_C_Example**.
* La clase **ar.com.other.plugin.model.MExample**, que extiende de **org.openXpertya.plugin.MPluginPO**.
La clase **MExample** de **Plugin2** recibirá en sus métodos **pre** y **post**, una copia de la instancia del **Plugin1** de **MExample** o de **LP_C_Example** si la primera no fue implementada. Esta instancia puede ser casteada según sea necesario de la misma manera que en el ejemplo anterior.