====== 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.