Hola Mundo con OSGI

De ChuWiki

Veamos un Hola Mundo con OSGI


El IDE[editar]

Dentro de las diversas distribuciones de eclipse, la adecuada para OSGI es la Eclipse RCP and RAP developers, pero también podemos usar el Eclipse IDE for Java EE developers, y seguramente muchos más de los otros. Así que si el que tenemos instalado lo soporta bien, si no, nos lo descargamos https://www.eclipse.org/downloads/


Crear el proyecto Plug-in[editar]

Creamos un proyecto nuevo de tipo Plug-in Project. Aparece una ventana en la que rellenaremos el nombre del proyecto, OSGIHelloWorld en nuestro ejemplo, y el framework en el que vamos a querer correr nuestro plugin (eclipse, equinox o estándar). Elegimos equinox para poder correrlo luego fuera de eclipse. El resto de opciones las dejamos por defecto o las cambiamos si queremos. Pulsamos Siguiente.

En la siguiente ventana aparecen unos datos para rellenar de nuestro plug-in, como se ve en la siguiente imagen

Algunos campos vienen rellenos, como el id, la versión y el nombre, que podemos dejar como están o cambiar. Rellenamos el vendor (proveedor) con nuestro nombre/marca si queremos. El plug-in (o bundle si usamos el vocabulario de OSGI) tiene una clase principal, que se denomina Activator. En esta ventana ponemos cual será esa clase, con su paquete y nombre de clase. En nuestro ejemplo será com.chuidiang.ejemplos.osgi.Activator. Aunque Activator es el nombre estándar, podemos poner el nombre que queramos a esta clase. Dejamos el resto de opciones como está y pulsamos Siguiente.

Aparece una nueva ventana en la que elegimos el tipo de plug-in/bundle que queremos crear. Para evitar escribir código, elegimos la opción Hello OSGI Bundle. Pulsamos Siguiente.

El bundle Hola Mundo mostrará dos mensajes, uno de bienvenida cuando arranque, otro de despedida cuando pare. La ventana nos pide ambos mensajes. Dejamos por defecto lo que pone o cambiamos los textos por otros de nuestra eleción y pulsamos Finish.


Ver qué tiene el proyecto Plug-in[editar]

Veamos las partes importantes que se han creado.


El Activator[editar]

Se ha creado la clase java que es la que habíamos indicado en la creación que queríamos que fuera nuestro Activator. Es la siguiente

package com.chuidiang.ejemplos.osgi;

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

public class Activator implements BundleActivator {

   /*
    * (non-Javadoc)
    * 
    * @see
    * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
    */
   public void start(BundleContext context) throws Exception {
      System.out.println("Hello World!!");
   }

   /*
    * (non-Javadoc)
    * 
    * @see
    * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
    */
   public void stop(BundleContext context) throws Exception {
      System.out.println("Goodbye World!!");
   }

}

Es una clase que implementa la interface BundleActivator, que sólo tiene dos métodos, start() y stop(), a los que se llamará cuando el framework arranque o pare nuestro bundle. Ahí es donde se escriben los textos de bienvenida y despedida que habíamos puesto en las ventanas de creación del proyecto.

Los métodos reciben como parámetro un BundleContext, con el que nuestro Activator podría interactuar con el framework OSGI y a través de él con otros bundles. Pero esto va fuera del alcance de nuestro Hola Mundo.


El fichero de manifiesto[editar]

El fichero de manifiesto es un fichero manifiesto normal de un jar de java, pero para el caso de bundle, tiene algunas propiedades especiales que el framework OSGI es capaz de interpretar. El fichero generado es el siguiente

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: OSGIHelloWorld
Bundle-SymbolicName: OSGIHelloWorld
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.chuidiang.ejemplos.osgi.Activator
Bundle-Vendor: com.chuidiang
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: org.osgi.framework;version="1.3.0"
Bundle-ActivationPolicy: lazy

Ahí vemos, como cosas interesantes:

  • Bundle-Name es el nombre de nuestro bundle
  • Bundle-SymbolicName es un identificador para nuestro Bundle, que debe ser único.
  • Bundle-Version La versión de nuestro Bundle.
  • Bundle-Activator El paquete y clase del Activator de nuestro bundle.
  • Bundle-Vendor El proveedor del bundle.
  • Bundle-RequiredExecutionEnvironment Entorno java requerido.
  • Import-Package Paquetes externos requeridos, bien del entorno OSGI, bien de otros bundles. Nuestro bundle necesita el paquete org.osgi.framework, en su versión 1.3.0, porque es en ese paquete donde está el BundleContext que recibimos en nuestros métodos start() y stop().
  • Bundle-ActivationPolicy Debemos poner esta línea y el único valor que admite es lazy. Si no la ponemos, el bundle no se arrancará de ninguna manera y necesitaremos hacerlo a mano desde alguna consola de comandos que nos ofrezca el framework OSGI (lo veremos más adelante).

Pudes ver todas estas propiedades en http://wiki.osgi.org/wiki/Category:Manifest_Header


build.properties[editar]

Si queremos exportar nuestro proyecto en un jar para poder correrlo fuera de eclipse, en este fichero están las indicaciones para eclipse sobre dónde están las cosas y qué se debe exportar.

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

Para generar el jar, en File -> export -> Deployable Plugin And Fragments, marcamos nuestro plug-in OSGIHelloWorld y Finish. Ya veremos más adelante cómo ejecutarlo.


Ejectuar desde Eclipse[editar]

Para ejecutar desde eclipse, debería bastar con darle al botón derecho del ratón sobre el proyecto para sacar el menú y Run As -> OSGI Framework. Pero esto, aunque arranca y funciona, da un montón de errores que posiblemente se deben a que el arranque que configura por defecto eclipse no es válido. Así que tendremos que configurar a mano nuestra propia configuración.

Para no partir de cero, ejecutamos como acabamos de indicar y podemos parar la ejecución, lo único que nos iteresa es que se cree una configuración de arranque, que se llamará automáticamente OSGI Framework. Ahora, con el menú de eclipse Run -> Run Configurations..., podemos editar y arreglar esta configuración.

En la ventana Bundles, aparece marcado nuestro Bundel OSGIHelloWorld y otro montón de Bundles en la parte inferior. Dejamos OSGIHelloWorld y desmarcamos temporalmente todos los demás. Se puede hacer fácilmente desmarcando la casilla Target Platform. Ahora, debajo de Target Platform, marcamos solo los siguientes

  • org.apache.felix.gogo.command
  • org.apache.felix.gogo.runtime
  • org.apache.felix.gogo.shell
  • org.eclipse.equinox.console

Usando la caja type filter text podemos encontrar estos bundles fácilmente para marcarlos. Nos debería quedar como la siguiente imagen

Ahora sí, podemos arrancar nuestro proyecto como OSGI Framework usando esta configuración y ya no tendremos errores. Al arrancar, saldrá la bienvenida de nuestro bundle OSGIHelloWorld, y un cursor de la consola de OSGI que nos permite arrancar o parar bundles.

Hello World!!
osgi>

Si escribimos stop OSGIHelloWorld, veremos la despedida al pararse nuestro bundle y nuevamente el cursor

Hello World!!
osgi> stop OSGIHelloWorld
Goodbye World!!
osgi>

Finalemente, escribiendo start OSGIHelloWorld, veremos nuevamente la bienvenida al ser arrancado de nuevo nuestro bundle.

Hello World!!
osgi> stop OSGIHelloWorld
Goodbye World!!
osgi> start OSGIHelloWorld
Hello World!!
osgi> 

Si no queremos esta consola, sino que nos interesa sólo arrancar nuestro bundle, sin posiblidad de pararlo o arrancarlo en caliente, podemos quitar los cuatro bundles que añadimos en la configuracion, pero en la pestaña de argumentos de la ventana de configuración, aparece la siguiente lista de argumentos

-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console

Debemos eliminar el -console que aparece, que es el que provoca el arranque de la consola de comandos. Si lo hacemos, al arrancar veremos nuestro Hello World!! y ninguna posibilidad de arrancar o parar nuestro bundle, salvo parando todo el framework OSGI.


Ejecutar sin eclipse[editar]

Para poder ejecutar nuestro bundle fuera de eclipse, debemos realizar un pequeño montaje. Puedes ver cómo queda todo en OSGI Stand Alone, fijándote en los ficheros txt para ver qué jars debería haber en cada directorio. Vamos a crear todo eso pasao a paso. Creamos un directorio en algún sitio para poner todo lo necesario, en nuestro ejemplo, lo llamaremos OSGIStandAlone. Dentro metemos el jar principal de osgi, que puede llamarse algo así como

org.eclipse.osgi_3.9.1.v20130814-1242.jar

y podemos buscarlo para copiarlo dentro del directorio plugins de donde tengamos instalado eclipse. El resto de jars necesarios, excepto el de nuestro bundle, también lo sacaremos de ahí. Por supuesto, los números de versión (__3.9.1.v20130814-1242) pueden ser distintos.


Ejecutar sin consola[editar]

En el directorio OSGIStandAlone, creamos dos subdirectorios más, uno llamado plugins donde meteremos todos los jar necesarios y el de nuestro bundle, y otro configuration donde meteremos el fichero de configuración de osgi.

Dentro de plugins, si sólo queremos ejecutar nuestro nuestro bundle y no queremos consola, sólo necesitaremos meter el jar de nuestro bundle, que obtenemos desde eclipse con el botón derecho del ratón del proyecto y Export... -> Deployable Plug-in and Fragments. A la hora de exportar elegimos un directorio, eclipse creará en ese directorio un subdirectorio plugins y meterá dentro nuestro jar. Por ello, a la hora de elegir el directorio, nos bastará elegir el directorio OSGIStandAlone.

Ahora vamos al directorio configuration, ahí debemos crear un fichero config.ini con el siguiente contenido

osgi.bundles=plugins/OSGIHelloWorld_1.0.0.201402161321.jar@start
eclipse.application.launchDefault=false

Son dos propiedades, osgi.bundles en la que ponemos la ubicación del jar de nuestro bundle, con su path relativo plugins/ y terminado en @start para que sea arrancado.

La otra propiedad, eclipse.application.launchDefault, la ponemos a false para que osgi no intente buscar una aplicación por defecto para arrancar. Nuestro bundle es un bundle muy simple y no se registra como aplicación, así que no hay aplicación por defecto y obtendríamos error si no pusieramos esta propiedad a false (su valor por defecto es true).

Para arrancar esto, desde una ventana de comandos y en el directorio OSGIStandAlone escribimos

E:\PROYECTOS\OSGI\OSGIStandAlone>java -jar org.eclipse.osgi_3.9.1.v20130814-1242.jar -consoleLog
Hello World!!

La opción -consoleLog es para que se muestre la salida de nuestro programa por pantalla. Si no lo ponemos, no habrá salida estándar y no veremos nuestro Hello World!!

Con Ctrl-C paramos la aplicación.

Arrancar con consola[editar]

Si queremos la consola que nos permita arrancar y parar nuestro bundle, debemos meter todos los jar de la consola que metimos en eclipse

org.apache.felix.gogo.command_0.10.0.v201209301215.jar
org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar
org.apache.felix.gogo.shell_0.10.0.v201212101605.jar
org.eclipse.equinox.console_1.0.100.v20130429-0953.jar

y debemos añadir además los siguientes, de los que dependen los cuatro anteriores y que antes no poníamos porque eclipse ya los suministraba.

org.eclipse.core.contenttype_3.4.200.v20130326-1255.jar
org.eclipse.core.jobs_3.5.300.v20130429-1813.jar
org.eclipse.equinox.app_1.3.100.v20130327-1442.jar
org.eclipse.equinox.common_3.6.200.v20130402-1505.jar
org.eclipse.equinox.preferences_3.5.100.v20130422-1538.jar
org.eclipse.equinox.registry_3.5.301.v20130717-1549.jar

Pudes ver la lista completa de jars necesarios en http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fconsole_shell.htm , en ella aparecen un par más de jars, pero no han sido necesarios para arrancar este ejemplo.

En resumen, dentro de plugins, debemos tener todo esto

Directorio de E:\PROYECTOS\OSGI\OSGIStandAlone\plugins

16/02/2014  14:01    <DIR>          .
16/02/2014  14:01    <DIR>          ..
19/09/2013  09:45            57.646 org.apache.felix.gogo.command_0.10.0.v201209301215.jar
19/09/2013  09:45            80.249 org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar
19/09/2013  09:45            60.827 org.apache.felix.gogo.shell_0.10.0.v201212101605.jar
19/09/2013  09:45            93.013 org.eclipse.core.contenttype_3.4.200.v20130326-1255.jar
19/09/2013  09:45            92.479 org.eclipse.core.jobs_3.5.300.v20130429-1813.jar
19/09/2013  09:45            73.635 org.eclipse.core.runtime_3.9.0.v20130326-1255.jar
19/09/2013  09:45            86.244 org.eclipse.equinox.app_1.3.100.v20130327-1442.jar
19/09/2013  09:45           106.701 org.eclipse.equinox.common_3.6.200.v20130402-1505.jar
19/09/2013  09:45           116.277 org.eclipse.equinox.console_1.0.100.v20130429-0953.jar
19/09/2013  09:45           127.170 org.eclipse.equinox.preferences_3.5.100.v20130422-1538.jar
19/09/2013  09:45           184.147 org.eclipse.equinox.registry_3.5.301.v20130717-1549.jar
16/02/2014  13:21             1.537 OSGIHelloWorld_1.0.0.201402161321.jar

En configuration, el fichero config.ini debe tener ahora el siguiente contenido

osgi.bundles=plugins/org.apache.felix.gogo.command_0.10.0.v201209301215.jar@start,\
plugins/org.apache.felix.gogo.runtime_0.10.0.v201209301036.jar@start,\
plugins/org.apache.felix.gogo.shell_0.10.0.v201212101605.jar@start,\
plugins/org.eclipse.equinox.console_1.0.100.v20130429-0953.jar@start,\
plugins/OSGIHelloWorld_1.0.0.201402161321.jar@start,\
plugins/org.eclipse.equinox.common_3.6.200.v20130402-1505.jar@start,\
plugins/org.eclipse.core.jobs_3.5.300.v20130429-1813.jar@start,\
plugins/org.eclipse.equinox.registry_3.5.301.v20130717-1549.jar@start,\
plugins/org.eclipse.equinox.preferences_3.5.100.v20130422-1538.jar@start,\
plugins/org.eclipse.core.contenttype_3.4.200.v20130326-1255.jar@start,\
plugins/org.eclipse.equinox.app_1.3.100.v20130327-1442.jar@start
eclipse.application.launchDefault=false

En la propiedad osgi.bundles hemos metido ahora todos los jar necesarios, separados por comas. Fíjate que se ha puesto el path relativo plugins/ para indicar que están dentro del directorio plugins y todos tienen un @start al final para que se los arranque. En realidad, este @start sólo es necesario en nuestro bundle, el resto se arrancarán cuando sean necesarios. Como todos ellos deberían estar en la misma línea del fichero, se pone el \ al final, justo delante del retorno de carro.

Una vez hecho todo esto, desde una ventana de comandos situda en el directorio OSGIStandAlone, ejecutamos el mismo comando de antes, pero añadiendo la opción -console

E:\PROYECTOS\OSGI\OSGIStandAlone>java -jar org.eclipse.osgi_3.9.1.v20130814-1242.jar -consoleLog -console

La ejecución nos mostrará lo mismo que veíamos en eclipse, pero esta vez en la vetana de comandos de nuestro sistema opearativo

E:\PROYECTOS\OSGI\OSGIStandAlone>java -jar org.eclipse.osgi_3.9.1.v20130814-1242.jar -consoleLog -console
Hello World!!
osgi> stop OSGIHelloWorld
Goodbye World!!
osgi> start OSGIHelloWorld
Hello World!!
osgi>