Bundles OSGI con dependencias

De ChuWiki

Veamos aquí un ejemplo sencillo de cómo un bundle osgi puede usar otros jar y como un bundle osgi puede exportar paquetes a otros bundles o importarlos.


Bundle con dependencia de jar[editar]

Creamos un proyecto osgi con nuestro IDE favorito, algo sencillo estilo "Hola Mundo" para nuestra prueba. En él, en un paquete específico, creamos una clase Saludo que será la que se exporte para otros bundles y que use algún jar externo, como por ejemplo, log4j. La clase puede ser esta

package com.chuidiang.ejemplos.osgi_export.util;

import org.apache.log4j.Logger;

public class Saludo {
	private static final Logger log = Logger.getLogger(Saludo.class);
	private String saludo = "";

	public String getSaludo() {
		return saludo;
	}

	public void setSaludo(String saludo) {
		this.saludo = saludo;
	}

	public void saluda() {
		log.info(saludo);
	}
}

Fíjate que esté en el paquete com.chuidiang.ejemplos.osgi_export.util y que usa log4j. La clase Activator de este bundle y que simplemente ponemos para ver que funciona, puede ser esta

package com.chuidiang.ejemplos.osgi_export;

import org.apache.log4j.BasicConfigurator;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import com.chuidiang.ejemplos.osgi_export.util.Saludo;

public class Activator implements BundleActivator {

	@Override
	public void start(BundleContext context) throws Exception {
		BasicConfigurator.configure();
		Saludo saludo = new Saludo();
		saludo.setSaludo("Hola");
		saludo.saluda();
	}

	@Override
	public void stop(BundleContext context) throws Exception {
		// TODO Auto-generated method stub

	}

}

Fíjate que este Activator esta en otro paquete, en com.chuidiang.ejemplos.osgi_export, sin el subpaquete util al final. Es importante separar en paquetes distintos aquellas clasae que realmente queremos exportar, de aquellas otras que son internas del bundle.

Bien, vamos a añadir la dependencia de log4j. Para ello, dentro de nuestro proyecto, creamos un directorio cualquiera (lib en nuestro ejemplo) y metemos ahí la libreía log4j-1.2.17.jar (en nuestro ejemplo). El árbol de directorios de nuestro proyecto eclipse puede quedar con esta pinta

Ahora, en el fichero META-INF/MANIFEST.MF debemos añadir la siguiente línea

...
Bundle-ClassPath: .,
 lib/log4j-1.2.17.jar

En Bundle-Classpath le indicamos al bundle dónde buscar clases de forma interna al bundle y estamos limitados a directorios o jars dentro del bundle. Estos directorios/jars van separados por comas. Es importante poner el directorio punto para que el bundle sea capaz de encontrar sus propias clases. Separado por una coma, ponemos la ubicación del log4j.jar, en lib/og4j-1.2.17.jar.

Listo, podemoe ejecutar el bundle y deberíamos ver el saludo en pantalla

0 [Start Level Event Dispatcher] INFO com.chuidiang.ejemplos.osgi_export.util.Saludo  - Hola

En el fichero build.properties debemos añadir el directorio lib/ para que nuestro bundle contenga el log4j.jar

source.. = src/
output.. = bin/
bin.includes = META-INF/,\
               .,\
               lib/


Exportar un paquete[editar]

Para que este bundle exporte la clase Saludo que está en el paquete com.chuidiang.ejemplos.osgi_export.util, debemos añadir en el fichero MANIFEST.MF la siguiente línea

Export-Package: com.chuidiang.ejemplos.osgi_export.util

indicando que exportamos el paquete. Podemos añadir con un ; la versión que queramos, así

Export-Package: com.chuidiang.ejemplos.osgi_export.util;version="1.0.0.FINAL"

Si ponemos versión, podríamos exportar el mismo paquete en diferentes versiones desde diferentes bundles, de forma que otros bundles puedan importar la versión concreta que les interese.

Listo, con esto el paquete queda exportado y se puede usar desde otros bundles. Vamos ahora a crear un bundle que use este paquete.


Bundle que importa paquetes externos[editar]

Creamos un nuevo proyecto de la forma habitual y en el Activator usamos la clase Saludo del bundle anterior.

package com.chuidiang.ejemplos.osgi_import;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import com.chuidiang.ejemplos.osgi_export.util.Saludo;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
	 * )
	 */
	public void start(BundleContext bundleContext) throws Exception {
		Saludo saludo = new Saludo();
		saludo.setSaludo("Hola desde plugin externo");
		saludo.saluda();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
	}

}

Esto, en eclipse, dará error, puesto que no tenemos visible el paquete ni la clase Saludo. Para hacerlo visible, en el fichero MANIFEST.MF, añadimos la siguiente línea

Import-Package: com.chuidiang.ejemplos.osgi_export.util,
 org.osgi.framework;version="1.3.0"

El paquete org.osgi.framework;version="1.3.0" lo añade eclipse por defecto al crear un Activator. El com.chuidiang.ejemplos.osgi_export.util lo hemos añadido a mano, separando con una coma ambos.

Con esto está listo. Si arrancamos ambos bundles simultáneamente, veremos el log de ambos.

0 [Start Level Event Dispatcher] INFO com.chuidiang.ejemplos.osgi_export.util.Saludo  - Hola
0 [Start Level Event Dispatcher] INFO com.chuidiang.ejemplos.osgi_export.util.Saludo  - Hola desde plugin externo