Las principales características de OSGi se pueden resumir en:
• Modularización.
• Tiempo de ejecución dinámico.
• Servicio de orientación.
OSGi tiene varias implementaciones (Knopflerfish OSGi, Apache Felix, Eclipse Equinox). Eclipse Equinox es actualmente la implementación de referencia de la especificación de OSGi. Es el entorno de ejecución en el cual están basados las aplicaciones de Eclipse IDE y RCP. En Eclipse la unidad más pequela de modularización en el plug-in El témino paquete y plug-in son casi intercambiables, es decir, un pug-in de Eclipse es también un paquete de OSGi y viceversa.
OSGi Bundles:
OSGi define un registro que los paquetes pueden usar para publicar servicios o registrarse en otros servicios. Los paquetes de OSGi son la unidad de modularización más pequeña. Es una unidad autónoma que define explícitamente sus dependencias con otros módulos/servicios y define su API externa. Pueden exportar servicios o ejecutar procesos, y tienen su gestión de dependencias, de tal manera que un paquete puede ser esperado para tener sus necesidades gestionadas por el contenedor.
Cada paquete puede tambien tener sus propias clases internas, por lo que puede servir como una unidad independiente, debería ser conveniente.
Todo esto está estandarizado de tal forma que cualquier paquete de OSGi válido puede, teoricamente, ser instalado en cualquier contenedor válido de OSGi.
Estos paquetes son ficheros “.jar” con meta información adicional. Esta meta información es almacenada en la carpeta “META-INF” en el “MANIFEST.MF”. “MANIFEST.MF” es parte de la especificación estándar del jar. Cada paquete tiene un nombre simbólico el cual es definido a través de la propiedad “Bundle-SymbolicName” en el “MANIFEST.MF”. Cada paquete tambien tiene un numero de versión en la propiedad “Bundle-Version”. Esto y el nombre únicamente identifican al paquete en OSGi. La ejecución de OSGi puede cargar el mismo paquete con diferentes números de versiones.
A través del “MANIFEST.MF” un paquete puede definir sus dependencias con otros paquetes y servicios. También se pueden definir dependencias respecto de una versión de un paquete. Lo que no es posible es que una clase de un paquete use otras clases definidas a través de dependencias; esto se tiene que aplicar a través de un “cargador de clases” específico de OSGi. “MANIFEST.MF” también define las clases Java que deberían estar disponibles para otros paquetes. Esta restricción está basada en los nombres de los paquetes y se aplica en OSGi a través de un cargador de clases especial de Java.
OSGi Services:
Los paquetes pueden registrar y usar servicios en OSGi. OSGi proporciona un registro central para esta finalidad. Un servicio está definido por una interface de Java.
Acceder a un servicio registrado se realiza a través de la clase “BundleContext”. OSGi mete el “BundleContext” en cada paquete durante su comienzo. Un paquete también puede registrarse a si mismo al “BundleContext ServiceEvents” los cuales son, por ejemplo funcionar si un nuevo servicio es instalado o desinstalado.
Gestión de la dependencia de OSGi:
OSGi es responsable de la gestión de la dependencia entre paquetes. Esta dependencia puede ser dividida en:
• Dependencias de paquetes (bundle/package).
• Dependencias de servicios.
OSGi lee el fichero “MANIFEST.MF” de un paquete durante la instalación del plug-in y asegura que todas los paquetes dependientes son también cargados si el paquete es activado. Si no se conocen las dependencias entonces el paquete no está cargado.
Un servicio en OSGi puede comenzar y para dinámicamente, por tanto los paquetes deben gestionar estas dependencias. Pueden usar servicios de escucha para obtener información si un servicio ha comenzado o se ha parado.
Ciclo de Vida:
Cuando se instala un paquete en el tiempo de ejecución de OSGi, éste se guarda en un paquete de caché local. Entonces OSGi resuelve todas las dependencias del paquete. Si todas las dependencias requeridas son resueltas el paquete pasa a estado “RESUELTO (RESOLVED)”, de los contrario pasa a estado “INSTALADO (INSTALLED)”. Si existen varios paquetes que satisfagan la dependencia, entonces se tomará el paquete con la versión más alta. Si tienes la misma versión será el que tenga la ID más baja. Si el paquete comienza, su estado pasa a ser “COMENZANDO (STARTING)”. Más tarde pasará a ser “ACTIVADO (ACTIVE)”.
OSGi Console:
La consola la usaremos más adelante. Es como la de MS-DOS. Se podrá escribir comandos para realizar ciertas acciones OSGi. A continuación se muestran algunos de estos comandos:
| Comando | Descripción |
| help | Proporciona una lista con los comandos disponibles. |
| ss | Da una descripción general de los paquetes instalados y su estado. |
| ss name | Da una descripción general de los paquetes y su estado si tienen “name” en el nombre. |
| start id | Inicia el paquete con ese id. |
| stop id | Para el paquete con ese id. |
| install URL | Instala un paquete desde la URL. |
| uninstall id | Desinstala el paquete con ese id. |
Crear un paquete en OSGi:
Vamos a crear paquetes. Para ello empezaremos con un sencillo y lo ejecutaremos con Eclipse.
Primero hay que crear un Proyecto plug-in que llamaremos: primerpaquete.osgi. Para ello tenemos que hacer lo siguiente: File -> New -> Project -> Plug-in Project, ponemos el nombre y cambiamos a la opción an OSGi framework: Equinox. Continuamos y elegimos una plantilla para crearlo, en este caso será: Hello OSGi Bundle.
Una vez creado ya el plug-in, ahora hay que introducir código. Para ello vamos a crear la siguiente clase hilo:
_____________________________________________________________________
package primerpaquete.osgi.interno;
public class MyThread extends Thread {
private volatile boolean active = true;
public void run() {
while (active) {
System.out.println("Hello OSGI console");
try {
Thread.sleep(5000);
} catch (Exception e) {
System.out.println("Thread interrupted " + e.getMessage());
}
}
}
public void stopThread() {
active = false;
}
}
_____________________________________________________________________
Vamos a tener que crear dentro de la carpeta src, el paquete primerpaquete.osgi.interno; y dentro de este la clase MyThread.
A continuación vamos a cambiar la clase Activator.java:
_____________________________________________________________________
package de.vogella.osgi.firstbundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import primerpaquete.osgi.interno.MyThread;
public class Activator implements BundleActivator {
private BundleContext context;
private MyThread myThread;
public void start(BundleContext context) throws Exception {
System.out.println("Iniciando primerpaquete.osgi");
this.context = context;
myThread = new MyThread();
myThread.start();
}
public void stop(BundleContext context) throws Exception {
System.out.println("Parando primerpaquete.osgi");
myThread.stopThread();
myThread.join();
this.context = null;
}
}
_____________________________________________________________________
Ahora vamos a ejecutarlo, pero primero tendremos que realizar algunos cambios en la configuración de la ejecución. Para ello seleccionamos nuestro MANIFEST.MF, hacemos click con el botón derecho y seleccionamos: Run As -> Run Configurations. Una vez dentro, seleccionaremos el paquete primerpaquete.osgi, y ejecutaremos la aplicación.
Lo que debemos obtener es una salida como la siguiente cada 5 segundos:
Hello OSGi console
Exportar paquetes:
Ahora vamos a exportar el paquete. Esto sirve para poder instalarlo en un entorno de ejecución de OSGi separado. Para ello seleccionaremos el paquete y seleecionaremos: File -> Export -> Deployable plug-ins and fragments y luego seleccionaremos el destino donde queramos que se exporte.
Iniciar el sevidor OSGi independientemente:
Ya hemos aprendido a crear un paquete y sabemos exportarlo para poder usarlo más adelante en un servidor OSGi independiente.
Para poder ejecutar los paquetes fuera de Eclipse, lo que hay que hacer es copiar en otra carpeta el org.eclipse.osgi*.jar.
Para ejecutar OSGi hay que ejecutar la siguiente consulta desde la consola de Windows (primeramente hay que meterse en la ruta donde lo hayamos metido):
java -jar org.eclipse.osgi*.jar -console
A continuacion nos aparecerá:
osgi>
Ya estamos dentro de la consola de OSGi. Desde aqui es desde donde se podrán instalar todos los paquetes (bundles), iniciarlos, pararlos, desinstalarlos, comprobar sus dependencias, comprobar los servicios registrados, y muchas cosas mas.
Ahora ya podremos instalar el paquete que hemos creado antes:
Install file:c:\*\primerpaquete.osgi.jar
A continuación nos proporcionará el identificador del paquete (por ejemplo: Bundle id is 1) y para poder ejecutarlo tendremos que escribir:
Start 1
Y en la consola aparecerá: Hello OSGi console; al igual que si se hubiera ejecutado en el Eclipse.
Como definir un Servicio y un consumo de servicio:
Como ya sabemos, OSGi permite explicitamente el modelado de dependencias. Esto es muy potente. La plataforma OSGi además proporciona una mayor funcionalidad a través de los servicios. Ahora vamos a definir y consumir un servicio.
• Primeramente se va a definir la interfaz del servicio:
Creamos un proyecto plug-in solicitar.osgi. Esta vez no hay que usar ninguna plantilla. Seleccionamos el “MANIFEST.MF” y nos metemos en la pestaña Runtime. Añadimos este paquete a los paquetes exportados.
Ahora creamos, dentro de este paquete, una interfaz ServicioI con lo siguiente:
______________________________________________________________________
package solicitar.osgi;
public interface ServicioI {
String getQuote();
}
______________________________________________________________________
• Creamos el servicio:
Para ello creamos otro proyecto plug-in servicio.osgi sin usar plantillas. Nos metemos en el “MANIFEST.MF” y en la pestaña dependencias. Añadimos solicitar.osgi a los plug-ins requeridos.
Creamos un nuevo paquete servicio.ogi.interno y creamos la clase Servicio:
______________________________________________________________________
package servicio.osgi.interno;
import java.util.Random;
import solicitar.osgi.ServicioI;
public class Servicio implements ServicioI {
@Override
public String getQuote() {
Random random = new Random();
// Create a number between 0 and 2
int nextInt = random.nextInt(3);
switch (nextInt) {
case 0:
return "Diles que he dicho algo";
case 1:
return "Ya me siento mejor";
default:
return "Hubba Bubba, Baby!";
}
}
}
______________________________________________________________________
Ahora necesitamos registrar el servicio en la clase Activator:
______________________________________________________________________
package servicio.osgi;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import solicitar.osgi.ServicioI;
import servicio.osgi.interno.Servicio;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
ServicioI service = new Servicio();
context.registerService(ServicioI.class.getName(), service, new Hashtable());
System.out.println("ServicioI es registrado");
}
public void stop(BundleContext context) throws Exception {
}
}
______________________________________________________________________
Ya tendremos creado nuestro servicio. Ahora instalaremos estos dos paquetes en nuestro OSGi independiente, de la misma manera que antes. Si iniciamos este último, nos tendrá que aparecer:
ServicioI es registrado
• Uso del Servicio:
Crearemos un nuevo plug-in consumidor.osgi sin plantilla. Nos metemos en el “MANIFEST.MF” y en la pestaña dependencias. Añadimos en plug-ins requeridos org.eclipse.osgi en los paquetes importados solicitar.osgi.
Ahora vamos a registrar el servicio y usarlo:
______________________________________________________________________
package consumidor.osgi;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import solicitar.osgi.ServicioI;
public class Activator implements BundleActivator {
private BundleContext context;
private ServicioI service;
public void start(BundleContext context) throws Exception {
this.context = context;
// Register directly with the service
ServiceReference reference = context.getServiceReference(ServicioI.class.getName());
service = (ServicioI) context.getService(reference);
System.out.println(service.getQuote());
}
public void stop(BundleContext context) throws Exception {
System.out.println(service.getQuote());
}
}
______________________________________________________________________
Exportamos el paquete y lo instalamos. Si lo iniciamos, veremos que funciona, pero si paramos el paquete servicio entonces obtendremos un error. La razón es que OSGi es un entorno muy dinámico y el servicio puede ser registrado y cancelado en cualquier momento. Para que no ocurran estas cosas se usarán servicios de seguimiento (se explicará más adelante).
0 comentarios:
Publicar un comentario