Skip to content
FINORA Academy
SistemaFINORA ERP

6. Qué es OSGi

Intermediate15 minVerified on Sep 25, 2026

This content is not available in your language yet.

OSGi (Open Services Gateway initiative) es la especificación de modularidad para Java que iDempiere adoptó al pasar de ADempiere a iDempiere en 2012 (ver Tutorial 1). En vez de un único classpath gigante con todo el código del ERP, el servidor es un conjunto de bundles — jars (o directorios) con su propio manifiesto de dependencias — que un contenedor OSGi (iDempiere usa Equinox, la implementación de Eclipse) resuelve, arranca y conecta entre sí en tiempo de ejecución. Todo plugin de FINORA LVE es, técnicamente, un bundle OSGi más.

El manifiesto: la identidad y las dependencias de un bundle

Sección titulada «El manifiesto: la identidad y las dependencias de un bundle»

Cada bundle declara en META-INF/MANIFEST.MF quién es y qué necesita. Este es el manifiesto real de com.finora.lve.base:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: FINORA LVE Base
Bundle-SymbolicName: com.finora.lve.base;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: DC GEEKS, C.A.
Bundle-License: GPL-2.0-only
Bundle-RequiredExecutionEnvironment: JavaSE-17
Bundle-Activator: com.finora.lve.base.Activator
Bundle-ClassPath: .
Require-Bundle: org.adempiere.base;bundle-version="[13.0.0,14.0.0)",
org.adempiere.plugin.utils;bundle-version="[13.0.0,14.0.0)"
Import-Package: org.osgi.framework;version="1.9.0",
org.osgi.service.event;version="1.4.0"
Export-Package: com.finora.lve.base;version="1.0.0",
com.finora.lve.base.model;version="1.0.0",
com.finora.lve.base.process.setup;version="1.0.0"
Service-Component: OSGI-INF/*.xml

(finora-lve/plugins/com.finora.lve.base/META-INF/MANIFEST.MF)

Punto por punto:

  • Bundle-SymbolicName es el identificador único del bundle en todo el servidor — com.finora.lve.base, no un nombre de clase. singleton:=true significa que solo puede haber una versión de este bundle activa a la vez (el patrón normal para bundles de aplicación, a diferencia de librerías que pueden convivir en varias versiones).
  • Require-Bundle declara una dependencia de otro bundle completo, con un rango de versión: [13.0.0,14.0.0) significa “cualquier 13.x, nunca un 14”. Esto es lo que impide que FINORA LVE 1.x arranque por accidente sobre un iDempiere 14 sin haber sido probado (finora-lve/docs/ARCHITECTURE.md, §2.4).
  • Import-Package declara una dependencia de paquetes específicos, más fino que un bundle entero — útil para depender solo de las interfaces del framework OSGi mismo (org.osgi.framework), sin acoplarse a todo un bundle.
  • Export-Package es lo contrario: qué paquetes de este bundle pueden importar otros bundles. Un paquete que no se exporta es privado, aunque esté en un jar público.
  • Bundle-Activator es la clase que el contenedor llama al arrancar y detener el bundle (más abajo).
  • Service-Component: OSGI-INF/*.xml le dice a OSGi dónde buscar los componentes de Declarative Services (siguiente sección) — el comodín permite que cada paquete de trabajo agregue su propio XML sin tener que editar el manifiesto compartido cada vez (finora-lve/docs/ARCHITECTURE.md, §4.1).
stateDiagram-v2
    [*] --> INSTALLED: se copia a plugins/ y se agrega a bundles.info
    INSTALLED --> RESOLVED: Require-Bundle e Import-Package satisfechos
    RESOLVED --> STARTING: el contenedor lo arranca
    STARTING --> ACTIVE: Activator.start() termina sin error
    ACTIVE --> STOPPING: se detiene o se actualiza
    STOPPING --> RESOLVED: Activator.stop() termina
    RESOLVED --> UNINSTALLED: se retira

Un bundle que declara una dependencia que no existe en el servidor se queda en INSTALLED (nunca resuelve) — es el error más común al desplegar un plugin nuevo, y casi siempre significa una versión de Require-Bundle que no coincide con lo instalado.

Activator: código que corre al arrancar el bundle

Sección titulada «Activator: código que corre al arrancar el bundle»
finora-lve/plugins/com.finora.lve.base/src/com/finora/lve/base/Activator.java
public class Activator extends LvePackActivator {
@Override
protected String[] requiredBundles() {
return new String[0]; // base no depende de otro bundle LVE
}
}

LvePackActivator extiende a su vez Incremental2PackActivator del core, que en su método start() busca los 2Pack empaquetados dentro del propio bundle y los aplica contra la base de datos (ver Tutorial 8). Este es el patrón que usa FINORA para “instalar diccionario” sin ningún paso manual: el simple hecho de que el bundle llegue a ACTIVE dispara la actualización.

Declarative Services: registrar un componente sin tocar el Activator

Sección titulada «Declarative Services: registrar un componente sin tocar el Activator»

Escribir toda la lógica en el Activator no escala — cada nuevo event handler, proceso o modelo tendría que registrarse ahí a mano. Declarative Services (DS) resuelve esto: un archivo XML describe un componente y sus dependencias de servicios OSGi, y el contenedor lo instancia y conecta solo, sin que el Activator sepa nada de él.

finora-lve/plugins/com.finora.lve.base/OSGI-INF/com.finora.lve.base.MappedFactories.xml
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.3.0" immediate="true"
name="com.finora.lve.base.MappedFactories" activate="activate">
<implementation class="com.finora.lve.base.MappedFactories"/>
<reference cardinality="1..1" field="mappedModelFactory"
interface="org.idempiere.model.IMappedModelFactory" name="mappedModelFactory"/>
<reference cardinality="1..1" field="mappedProcessFactory"
interface="org.idempiere.process.IMappedProcessFactory" name="mappedProcessFactory"/>
</scr:component>
finora-lve/plugins/com.finora.lve.base/src/com/finora/lve/base/MappedFactories.java
public class MappedFactories {
static final String[] MODEL_PACKAGES = { "com.finora.lve.base.model" };
static final String[] PROCESS_PACKAGES = { "com.finora.lve.base.process.fx", "com.finora.lve.base.process.setup" };
private IMappedModelFactory mappedModelFactory;
private IMappedProcessFactory mappedProcessFactory;
public void activate(BundleContext context) {
mappedModelFactory.scan(context, MODEL_PACKAGES);
mappedProcessFactory.scan(context, PROCESS_PACKAGES);
}
}

El XML dice “cuando existan los servicios IMappedModelFactory e IMappedProcessFactory en el contenedor, inyéctalos en estos campos y llama a activate”. Ese componente, a su vez, le pide a esas fábricas del core que escaneen los paquetes de este bundle en busca de clases anotadas (@Model, @Process, @Callout) y las registren — el mecanismo exacto que usa FINORA LVE para dar de alta su lógica de negocio (ver Tutorial 9).

  • finora-lve/plugins/com.finora.lve.base/META-INF/MANIFEST.MF
  • finora-lve/plugins/com.finora.lve.base/src/com/finora/lve/base/Activator.java
  • finora-lve/plugins/com.finora.lve.base/OSGI-INF/com.finora.lve.base.MappedFactories.xml
  • finora-lve/docs/ARCHITECTURE.md, §2.4, §4.1 y §8 (versionado lockstep, event handlers OSGi, ADR-LVE-006)
  • OSGi Alliance — especificaciones
  • Documentación de Equinox — Eclipse Foundation