7. Cómo se crea un plugin paso a paso
This content is not available in your language yet.
Este tutorial arma, paso a paso, un plugin mínimo para iDempiere 13 siguiendo exactamente el patrón
que usa FINORA LVE: un bundle OSGi compilado con javac (sin Tycho), que no toca ni una línea del
core. Usamos como referencia el bundle real más simple del proyecto,
com.finora.lve.base, y el precedente que ya está en la versión instalada,
com.finora.erp.dashboard (finora-lve/docs/ARCHITECTURE.md, ADR-LVE-006).
El esqueleto de carpetas
Sección titulada «El esqueleto de carpetas»com.finora.lve.miplugin/├── META-INF/│ └── MANIFEST.MF├── OSGI-INF/│ └── com.finora.lve.miplugin.MiComponente.xml├── build.properties└── src/ └── com/finora/lve/miplugin/ ├── Activator.java └── MiComponente.javaEste layout es idéntico al de cualquier bundle del core y compatible con Tycho el día que el
proyecto lo adopte (finora-lve/docs/ARCHITECTURE.md, §8) — no hay nada “simplificado” en la
estructura, solo en la forma de compilarla.
-
Escribe el
Sección titulada «Escribe el MANIFEST.MF»MANIFEST.MFManifest-Version: 1.0Bundle-ManifestVersion: 2Bundle-Name: FINORA LVE Mi PluginBundle-SymbolicName: com.finora.lve.miplugin;singleton:=trueBundle-Version: 1.0.0.qualifierBundle-Vendor: DC GEEKS, C.A.Bundle-License: GPL-2.0-onlyBundle-RequiredExecutionEnvironment: JavaSE-17Bundle-Activator: com.finora.lve.miplugin.ActivatorBundle-ClassPath: .Require-Bundle: org.adempiere.base;bundle-version="[13.0.0,14.0.0)"Service-Component: OSGI-INF/*.xmlEl nombre simbólico (
Bundle-SymbolicName) debe ser único en todo el servidor — por convención,com.finora.lve.<módulo>(finora-lve/docs/ARCHITECTURE.md, §2.2).Require-Bundlefija el rango de iDempiere soportado; nunca se deja abierto hacia arriba. -
Escribe el
Sección titulada «Escribe el Activator»ActivatorTodo bundle necesita una clase que el contenedor pueda llamar al arrancar. Si el plugin no trae diccionario propio, puede ser tan simple como:
package com.finora.lve.miplugin;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {@Overridepublic void start(BundleContext context) {// nada que hacer al arrancar: la lógica vive en componentes DS (paso 3)}@Overridepublic void stop(BundleContext context) {}}Si el plugin sí trae 2Pack (diccionario propio), el
ActivatorextiendeIncremental2PackActivatordel core en vez de implementarBundleActivatordirectamente — así lo hacecom.finora.lve.base.Activator(ver Tutorial 6 y Tutorial 8). -
Registra un componente con Declarative Services
Sección titulada «Registra un componente con Declarative Services»Cualquier lógica real (un event handler, un proceso, un servicio) se registra como componente DS, no dentro del
Activator. Primero la clase:package com.finora.lve.miplugin;public class MiComponente {public void activate() {// se ejecuta cuando OSGi resuelve las dependencias de abajo}}Y el XML que lo declara:
<?xml version="1.0" encoding="UTF-8"?><scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"name="com.finora.lve.miplugin.MiComponente" activate="activate"><implementation class="com.finora.lve.miplugin.MiComponente"/></scr:component>Si el componente necesita un servicio de iDempiere (por ejemplo
IEventManagerpara un event handler), se agrega como<reference>— exactamente como en el ejemplo decom.finora.lve.base.event.BPartnerTaxIdHandler.xmldel tutorial anterior. -
Compila y empaqueta
Sección titulada «Compila y empaqueta»FINORA LVE no invoca
javaca mano por bundle: un único script,tools/build.sh, hace todo el pipeline por cada bundle en orden de dependencias:Ventana de terminal tools/build-sdk.sh --from-dir <idempiere>/plugins # fija los jars del SDK por sha256tools/build.sh # lint de manifest + javac --release 17# + JUnit 5 + empaquetado + distribución(
finora-lve/docs/ARCHITECTURE.md, §8). El resultado es un directorio o jarcom.finora.lve.miplugin_1.0.0.<qualifier>/listo para copiar aplugins/del servidor y agregar abundles.info(ver Tutorial 2).
Qué NO hace falta para este esqueleto
Sección titulada «Qué NO hace falta para este esqueleto»- No hay
pom.xmlni Tycho. El build esjavac --release 17contra un SDK de jars fijados por sha256 (tools/build-sdk.lock) — segundos, no minutos, y sin depender de un repositorio p2 que el equipo no controla (finora-lve/docs/ARCHITECTURE.md, ADR-LVE-006). - No hay resolución OSGi en tiempo de build. Un
Import-Packagefaltante no se detecta hasta que el bundle intenta arrancar en un servidor real — el build lo compensa con lint de manifiesto (nombre simbólico = carpeta, versión consistente, clases de los componentes DS realmente compiladas) y una prueba de humo en DEV. - No hay cambios al core. Ni un archivo de
org.adempiere.*se toca; todo lo que este plugin necesita del core lo obtiene porRequire-Bundle/Import-Packagey por los mecanismos de extensión que el core ya expone (event handlers, fábricas — ver Tutorial 9).
Cómo confirmar que arrancó, sin adivinar
Sección titulada «Cómo confirmar que arrancó, sin adivinar»Copiar la carpeta a plugins/, editar bundles.info y reiniciar el servicio no garantiza que el
bundle haya arrancado bien — un Import-Package faltante o un XML de componente mal formado falla en
silencio si no se revisa. La consola de Equinox (accesible por telnet al puerto configurado, o desde
la salida estándar del proceso si corre en primer plano) resuelve la duda en tres comandos:
osgi> ss com.finora.lve.miplugin id State Bundle 87 ACTIVE com.finora.lve.miplugin_1.0.0.qualifier
osgi> diag 87com.finora.lve.miplugin_1.0.0.qualifier [87] has no unresolved dependencies
osgi> start 87ss (short status) muestra el estado del bundle: ACTIVE es lo esperado; INSTALLED o RESOLVED sin
llegar a ACTIVE casi siempre significa un componente DS que no pudo activarse. diag explica por
qué un bundle no resuelve — normalmente un Require-Bundle/Import-Package que no encuentra su
proveedor en el servidor, el error más común al mover un plugin de un ambiente a otro. Revisar esto
antes de asumir que “no aparece en el menú” es un bug de la ventana es el primer paso de cualquier
diagnóstico de plugin nuevo.
Fuentes
Sección titulada «Fuentes»finora-lve/plugins/com.finora.lve.base/(MANIFEST.MF, Activator.java, OSGI-INF/*.xml reales)finora-lve/docs/ARCHITECTURE.md, §2.2, §2.3 y §8 (convenciones de nombres, capas de un bundle, ADR-LVE-006)finora-erp-experience/idempiere/plugins/com.finora.erp.dashboard/(precedente ya en la versión instalada, compilado con el mismo enfoque)