Posts tagged ‘OSGi’

Apache Felix Web Console

En este blog ya ha aparecido Apache Felix en varias de las entradas relacionadas con OSGi. Hemos visto varios de sus comandos e instalado y arrancado módulos. Siempre con su interfaz de línea de comandos que es la que se utiliza normalmente.

Pero dando una vuelta por la web de Felix, he visto el subproyecto Apache Felix Web Console, que como su nombre indica pretende ser una interfaz web para Felix. En esta entrada os cuento cómo la he hecho funcionar. Para abrir boca os muestro el resultado final.

felixwebconsole_1_640x470

En la página del subproyecto aparece casi toda la información necesaria. Se nos indica que la única dependencia obligatoria es tener un Http Service instalado y nos muestra algunas alternativas. El Http Service de Felix todavía no tiene una versión publicada por lo que yo me decidí por OPS4J Pax Web (por cierto, curioso e interesante el proyecto OPS4J en su conjunto).

Tras descargar pax-web-service-0.5.2.jar (como se explica en su sitio web, el pax-web-service incluye ya el jetty y todo lo necesario), lo instalé en Felix (install file:////d:/felix-1.4.0/bundle/pax-web-service-0.5.2.jar) y lo intenté arrancar, pero me apareció el siguiente error:

org.osgi.framework.BundleException: Unresolved constraint in bundle 22: package; (package=javax.servlet)

Esto se soluciona si descargamos e instalamos el módulo org.osgi.compendium-1.2.0.jar desde la web de Felix. Este módulo es sólo una agrupación de clases de OSGi. De hecho es casi lo mismo que contiene el módulo osgi.cmpn.jar descargable desde la web de OSGi (requiere registro). Tras instalarlo tendremos esa dependencia cumplida y podremos arrancar el OPS4J Pax Web.

Ahora podemos descargar el módulo con la consola web (org.apache.felix.webconsole-1.2.2.jar), instalarlo y arrancarlo. Un apunte respecto a la configuración del módulo. En el archivo config.properties de nuestra instalación de Felix, aparece una propiedad (org.osgi.service.http.port) que realmente es configuración del servicio de Http. En ella se indica el puerto a escuchar (el 8080 por defecto).

Yo no he dado valor a ninguna otra de las propiedades de configuración, ni de Pax Web Service ni de We Console.

Ahora apuntamos nuestro navegador a http://localhost:8080/system/console (la ruta se podría modificar mediante configuración) y entramos con admin/admin (también modificable por configuración) y ya vemos el aspecto de nuestra consola web.

En la pestaña de módulos (“bundles”) vemos que podemos parar, arrancar, instalar actualizar o desinstalar módulos. También podemos ver información detallada sobre cada módulo (versión, paquetes exportados e importados, etc.). En otras pestañas podemos ver el estado de la configuración (“Configuration Status”), ver la licencia de los módulos instalados (“Licenses”), tener acceso a una línea de comandos en la página (“Shell”) o ver información y controlar el sistema en sí (“System Information”).

También tenemos una pestaña para la gestión de repositorios de módulos. En el mismo archivo config.properties que hemos comentado con anterioridad se añade el repositorio de Felix (propiedad obr.repository.url). Yo para que se pudiera conectar al servidor he tenido que añadir durante el arranque las propiedades del proxy tras el que estoy (-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080 -Dhttp.proxyAut=user:pass), tal como se explica en la página del OSGi Bundle Repository de Felix. Desde esta pestaña se pueden añadir nuevos repositorios o instalar módulos desde los repositorios instalados.

felixwebconsole_2_640x472

Por último, señalar que tenemos otras pestañas (“Configuration”, “Deployment Packages” o “Event Admin”) cuya funcionalidad se ve limitada si no tenemos el servicio correspondiente instalado. Pero para hablar de esos servicios ya habrá otras entradas.

16 marzo 2009 at 9:49 pm Deja un comentario

Desarrollo OSGi en Eclipse

En todos los ejemplo de OSGi que he estado publicando en este blog he utilizado como contenedor OSGi Apache Felix. Pero también comentamos que Eclipse estaba basado en OSGi y por tanto funciona sobre su motor OSGi Equinox.

Como mi IDE actualmente es Eclipse, voy a tratar el tema de desarrollo OSGi utilizando este magnífico entorno libre. Para ello trasladaré lo hecho en el ejemplo de gestión de dependencias con OSGi y lo probaré sobre Equinox.

Para desarrollar OSGi con eclipse, lo más cómodo es utilizar el PDE (Plugin Development Extension) de Eclipse, ya que realmente los plugins de Eclipse son módulos OSGi. Si no bajamos nuestro eclipse con PDE integrado deberemos instalarlo.

Creamos un nuevo proyecto. En la ventana de selección de wizard seleccionamos dentro de “Plug-in Development” la opción “Plug-in Project”. Le damos un nombre al proyecto de forma habitual y selecciono como “Target platform” un framework OSGi standar.

osgi_eclipse1

En la siguiente ventana le damos los datos que van a formar parte del MANIFEST.MF: id, nombre, proveedor, versión. Relleno los campos para que mantenga los valores que en su día teníamos. Dejamos sin marcar la casilla de generar un Activator, ya que tenemos uno ya creado. Con esto podemos dar por concluido el wizard de creación del proyecto.

osgi_eclipse2

Se nos abre el editor especial para el MANIFEST.MF en el que tenemos distintas pestañas como por ejemplo la vista general (“overview”) o la de ver el MANIFEST en texto:

osgi_eclipse3_640x650 osgi_eclipse4_640x650

Copio o añado los fuentes que tenía en el módulo de logs que utilizamos para ver la gestión de dependencias en OSGi. Podremos ver un error en la compilación debido a que no reconoce las clases OSGi. Sin embargo Eclipse nos sugiere la solución: Añadir como dependencia el paquete org.osgi.framework. Lo podemos añadir mediante la sugerencia de Eclipse, o en la pestaña dependencias de nuestro MANIFEST.MF, en la que podemos ver todos los paquetes exportados.

osgi_eclipse5

Ahora en la pestaña “runtime” podemos añadir los paquetes que exporta nuestro módulo. Seleccionamos el mismo paquete que exportábamos entonces (org.tcymu.osgi.log.logger) y luego en las propiedades de lo exportado ponemos la versión (1.0.1). por último en la pestaña de visión general podemos declarar el activador (LogBundle).

En la misma pestaña de visión general también tenemos un enlace para lanzar el framework. Si lo ejecutamos veremos la traza que sacaba nuestro módulo al arrancar:

osgi> 18-02-2009 18:28:16.47: Arrancando LogBundle

Podemos utilizar el comando ss (similar al ps que vimos en Felix) para ver el estado de los módulos:

osgi_eclipse6

Si tecleamos help veremos la lista completa de comandos, en la que descubrimos que el comando stop seguido por el identificador del módulo detiene ese módulo, y que el comando exit nos sirve para detener completamente la ejecución.

Por último voy a crear un nuevo proyecto de tipo plugin para el módulo de nuestra aplicación. En él copiamos el código fuente del módulo de aplicación tal como lo teníamos en los anteriores ejemplos. Nos aparecerán los errores de dependencias tanto de las clases OSGi como de las clases del módulo de logs. Y vemos que podemos importar tanto los de OSGi como los de nuestro módulo de logs. Tras definir la clase de activación ejecutamos el módulo y todo funciona correctamente, arrancándose también el módulo de logs.

osgi_eclipse7_640x243

Y esto es todo por hoy.

23 febrero 2009 at 8:39 pm 2 comentarios

Gestión de servicios en OSGi

Anteriormente hemos visto en este blog la gestión de dependencias en OSGi. En esta entrada vamos a ver OSGi desde el punto de vista de un servicio.

Un servicio lo podemos declarar como un interface que debe implementar el proveedor de ese servicio y que utilizarán los consumidores del servicio. Lógicamente, ese interface debe ser accesible tanto al proveedor como al consumidor. Aquí lo voy a poner en el módulo proveedor del servicio y dicho módulo lo exportará, pero podría estar en un módulo aparte para separarlo de la implementación.

Para esta entrada utilizaré un teórico servicio proveedor de mensajería SMS, cuyo interface será:


package org.tcymu.osgi.sms.interfaces;

public interface ISmsProvider {
    public void sendMessage(String number, String text);
}

Los servicios en OSGi se registran manualmente, es decir, no se resuelven automáticamente como las dependencias. Para registrar un servicio nos valemos del interface BundleActivator ya visto en entradas anteriores. De esta forma, al iniciarse el proveedor de un servicio lo registraremos y al pararse desharemos el registro. Vamos a ver el código:


package org.tcymu.osgi.sms;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.tcymu.osgi.sms.interfaces.ISmsProvider;

public class SmsBundleActivator implements BundleActivator {
    private SmsProvider smsProvider;
    private ServiceRegistration serviceRegistration;

    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("Starting SmsProvider");
        smsProvider = new SmsProvider();
        serviceRegistration = bundleContext.registerService(ISmsProvider.class.getName(), smsProvider,null);
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("Stopping SmsProvider");
        serviceRegistration.unregister();
    }

}

La parte importante es el registro mediante el BundleContext que se nos pasa en el start de nuestro servicio. Para ello llamamos al método registerService (guardando el ServiceRegistration que nos devuelve) con los siguientes parámetros:

  1. String que representa el nombre de la clase que representa el servicio.
  2. Proveedor del servicio. En este caso una simple implementación que sólo hace un System.out (esta implementación va también en este módulo).
  3. Instancia de java.util.Dictionary (básicamente una Hashtable) que representa unas propiedades del servicio. En este caso no pasamos nada, pero se podría pasar una versión o cualquier otro dato que pudiera ser necesario.

También podemos apreciar que en el stop, deshacemos el registro mediante el método unregister del ServideRegistration que hemos guardado.

Como hemos visto en entradas anteriores, necesitamos declarar las propiedades del módulo en el MANIFEST.MF. No hay novedades respecto a lo ya visto en otras entradas. Las líneas más interesantes son:


Bundle-Activator: org.tcymu.osgi.sms.SmsBundleActivator
Export-Package: org.tcymu.osgi.sms.interfaces;version="1.0.0"

Si creamos el jar y lo instalamos en Felix (en este caso la versión 1.4.0) recibimos el mensaje esperado.

La parte interesante viene con el comando de Felix services, que nos lista los servicios disponibles en el contenedor. En su salida podemos ver entre algunos servicios propios de Felix, el nuestro:

osgiservices1_640x340

Ahora es el turno de crear el cliente para nuestro servicio.  Lo pongo todo en una sencilla clase:


package org.tcymu.osgi.smsclient;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.tcymu.osgi.sms.interfaces.ISmsProvider;

public class SmsClient implements BundleActivator {

    public void start(BundleContext bundleContext) throws Exception {
        System.out.println("Starting SmsClient");
        ServiceReference smsServiceRef = bundleContext.getServiceReference(ISmsProvider.class.getName());
        ISmsProvider smsProvider = (ISmsProvider)bundleContext.getService(smsServiceRef);
        smsProvider.sendMessage("555555555", "Tus ceros y mis unos");
    }

    public void stop(BundleContext bundleContext) throws Exception {
        System.out.println("Stopping SmsClient");
    }
}

Como podemos ver, primero se obtiene el ServiceReference a través del contexto de módulos (BundleContext). Y con esa referencia ya obtenemos la implementación del servicio también a través del contexto.

Si lo empaquetamos y arrancamos vemos que efectivamente se está utilizando el servicio.

osgiservices2_640x214

Esta no será la última entrada dedicada a OSGi en este blog, o sea que todos los interesados… ¡a suscribirse!.

22 diciembre 2008 at 9:47 pm Deja un comentario

Gestión de dependencias en OSGi (y 2)

En la primera parte de esta entrada vimos cómo exportar e importar paquetes, y ahora vamos a ver el funcionamiento con varias versiones de dichos paquetes.

Para empezar, es el momento de mejorar nuestro Logger:

package org.tcymu.osgi.log.logger;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Logger {
	private SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.S");
	private Date date = new Date();

	public void log(String msg) {
		date.setTime(System.currentTimeMillis());
		System.out.println(dateFormat.format(date) + ": " + msg);
	}
}

Y también actualizamos las siguientes líneas del MANIFEST para cambiar su versión:

Bundle-Version: 1.0.1
Export-Package: org.tcymu.osgi.log.logger;version="1.0.1"

Si empezamos a instalar de nuevo los módulos (hemos generado una nueva versión logbundle-1.0.1.jar) en Felix, comprobamos que podemos perfectamente tener dos versiones de una librería (en este caso nuestro Logger) instaladas, y que cada aplicación según su configuración utilizará una u otra. Si hacemos la prueba vemos que si tenemos las dos versiones del Logger va a utilizar la versión 1.0.1. ¿Por qué?. La respuesta es que version="1.0.0" se interpreta como version >= 1.0.0 y el contenedor selecciona la mayor. ¿Existe otra manera de definir las versiones?. Por supuesto. Los intervalos:

version="1.0.0" se interpreta como version >= 1.0.0
version="[1.0.0,1.1.0)" se interpreta como 1.0.0 <= version < 1.1.0
version="(1.0.0,1.1.0]" se interpreta como 1.0.0 < version <= 1.1.0

NOTA: Nótese la notación estilo matemático para definir los intervalos abiertos o cerrados.

Por lo tanto si modificamos el MANIFEST de nuestro módulo de aplicación, en concreto la siguiente línea:

Import-Package: org.osgi.framework,org.tcymu.osgi.log.logger;version="[1.0.0,1.0.0]"

comprobamos que ahora hemos forzado a que utilice la versión antigua.

También debemos conocer que en el caso de que tengamos módulos que exportan un mismo paquete con una misma versión, todavía podemos diferenciarlos y forzar la carga de uno determinado mediante la utilización de atributos. Por ejemplo, si tenemos exportado nuestro Logger de esta manera:

Export-Package: org.tcymu.osgi.log.logger;version="1.0.1";provider="tcymu"

Y existiera otro módulo que exportara el mismo paquete, se podría forzar a utilizar nuestro paquete mediante:

Import-Package: org.tcymu.osgi.log.logger;version="1.0.1";provider="tcymu"

Existen más posibilidades que dejaremos en el tintero de momento, como por ejemplo la directiva resolution, el atributo use, la fragmentación de módulos o la dependencia de módulos (Require-Bundle). Se puede ver todo esto en la especificación descargable (previo registro) en la web de OSGi.

Y esto es todo de momento. Próximamente veremos la utilización de servicios en OSGi.

3 noviembre 2008 at 7:50 pm 1 comentario

Gestión de dependencias en OSGi

Anteriormente en este blog hemos dado unos primeros pasos con OSGi, que os recomiendo leer si todavía no lo habéis hecho. Desde esas entradas he actualizado la versión de Apache Felix hasta la 1.2.1.

Ahora llega el momento de echar un vistazo a una de las características más interesantes de Osgi, como es la gestión de dependencias.

Lo primero que debemos conocer es que en OSGi permite exportar e importar paquetes de forma que es el contenedor OSGi el que se encarga de realizar y validar esas dependencias como paso previo a la ejecución de un módulo. Si no se pueden resolver dichas dependencias no se podrá ejecutar el módulo. Para jugar un poco con el tema, he creado dos pequeños módulos:

  • Uno que exporta un Logger con funcionalidad avanzada (bueno, no muy avanzada, pero es que es un ejemplo) cuyo código vemos a continuación. Este módulo también tiene un BundleActivator que saca una traza tanto en el arranque como en la parada.:

package org.tcymu.osgi.log.logger;

public class Logger {
    public void log(String msg) {
        System.out.println(System.currentTimeMillis() + ": " + msg);
    }
}

  • Otro que importa dicho Logger para hacer uso de él:

package org.tcymu.osgi.app;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.tcymu.osgi.log.logger.Logger;

public class AppBundle implements BundleActivator {
    Logger logger = new Logger();

    public void start(BundleContext arg0) throws Exception {
        logger.log("Arrancando AppBundle");
    }

    public void stop(BundleContext arg0) throws Exception {
        logger.log("Parando AppBundle");
    }
}

Tanto la exportación como la importación de los paquetes se hace a través de los descriptores. Las líneas importantes son:

Bundle-SymbolicName: org.tcymu.osgi.log.LogBundle
Bundle-Version: 1.0.0
Bundle-Activator: org.tcymu.osgi.log.LogBundle
Import-Package: org.osgi.framework
Export-Package: org.tcymu.osgi.log.logger;version="1.0.0"

y en la importación:

Bundle-SymbolicName: org.tcymu.osgi.app.AppBundle
Bundle-Version: 1.0.0
Bundle-Activator: org.tcymu.osgi.app.AppBundle
Import-Package: org.osgi.framework,org.tcymu.osgi.log.logger;version="1.0.0"

Empaquetaremos ambos módulos tal y como vimos en la anterior entrada. Ahora vamos a probar la instalación. Primero en el orden correcto. Primero instalo el módulo de log y después la aplicación:

install file:////d:/felix-1.2.1/bundle/org.tcymu.osgi.log.logbundle-1.0.0.jar Bundle ID: 16 install file:////d:/felix-1.2.1/bundle/org.tcymu.osgi.app.appbundle-1.0.0.jar Bundle ID: 17 start 16 start 17 Todo funciona correctamente. Ahora podemos hasta desinstalar el módulo de log, que una vez exportado, el contenedor mantiene una copia de esas clases para ofrecerlas a quien las necesite. Ahora vamos a parar y desinstalar nuestros módulos. También paro y reinicio Felix, ya que quiero comprobar qué ocurre si no tenemos una dependencia. Si instalo sólo el módulo de aplicación e intento arrancar, me lanza el siguiente error:

org.osgi.framework.BundleException: Unresolved constraint in bundle 24: package; (&(package=org.tcymu.osgi.log.logger)(version>=1.0.0))

Voy a dejar para una segunda parte de esta entrada el crear nuevas versiones de los módulos y comprobar cómo ser gestionan en el contenedor.

Actualización: Segunda parte

28 octubre 2008 at 8:23 pm 2 comentarios

OSGi: Primeros pasos (y 2)

Bien, continuamos avanzando en el camino que empezamos en la primera entrada. Para empezar, os quería comentar mi opinión respecto a OSGi, basada en este pequeño estudio que he hecho. Esta tecnología favorece el diseñar e implementar aplicaciones en forma de módulos, lo que ayuda de cara a la reutilización y encapsulación de servicios. Al igual que la inyección de dependencias favorece la buena práctica de utilizar interfaces, OSGi favorece la buena práctica de modularizar. Hecho este pequeño inciso, pasamos al punto donde lo dejamos. Crear nuestro primer módulo. El código de mi primer módulo será:

package org.tcymu.osgi;

import java.util.logging.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class FirstBundle implements BundleActivator {
  Logger logger = Logger.getLogger(this.getClass().getName());

  public void start(BundleContext arg0) throws Exception {
    logger.info("Arrancando FirstBundle");
  }

  public void stop(BundleContext arg0) throws Exception {
    logger.info("Parando FirstBundle");
  }
}

Como vemos basta con implementar BundleActivator, con sus métodos start y stop. En nuestro caso sacamos una traza de log en cada caso. Seguidamente necesitamos crear un descriptor para el jar de nuestro primer módulo. El contenido de nuestro MANIFEST.MF es:

Manifest-Version: 1.0
Bundle-SymbolicName: org.tcymu.osgi.FirstBundle
Bundle-Version: 1.0.0
Bundle-Activator: org.tcymu.osgi.FirstBundle
Import-Package: org.osgi.framework

Le damos a nuestro módulo un nombre y una versión, le señalamos la clase activadora mediante Bundle-Activator y le indicamos los paquetes requeridos mediante Import-Package Bien, con esto ya podemos empaquetar nuestro módulo en un jar de la manera que más rabia nos dé. En mi caso lo he empaquetado mediante el export de Eclipse.

Ahora ya podemos instalar el módulo en Felix, para lo que usamos install y que nos devuelve el identificador de nuestro módulo dentro del contenedor.

Con ese identificador podemos arrancar el módulo mediante start, pararlo mediante stop o desinstalarlo mediante uninstall

.

Bien, pues ya hemos visto cómo crear un módulo. Dejaré para más adelante el crear módulos dependientes de otros módulos y otras acciones más avanzadas. Por cierto, para salir de Felix, si no lo habéis descubierto todavía, se debe ejecutar shutdown.

9 junio 2008 at 8:58 pm 3 comentarios

OSGi: Primeros pasos

Tras los anuncios de varios proyectos importantes (Eclipse, GlassFish, SpringSource Application Platform) de su paso a OSGI, parece que estas siglas están bastante de moda dentro del mundo Java. En esta entrada intento dar una visión resumida y fugaz de lo que es OSGi. Quizás la mejor definición y la más concisa es la que aparece en la cabecera de la web de OSGi: Sistema de módulos dinámicos para Java. Básicamente lo que aporta OSGi o mejor dicho OSGi Service Platform (el estándar que publica la OSGi Alliance) es un contenedor sobre el que corren distintos módulos, con sus versiones, sus paquetes exportados (utilizables por otros módulos) y sus dependencias. Existen distintas implementaciones de dicho estándar, siendo las más conocidas Equinox (de Eclipse) y Felix (de Apache). Para esta entrada voy a utilizar Felix, pero sin ninguna razón de peso para su elección. Descargamos el zip desde su sitio web y descomprimimos en el directorio de nuestra elección. Podemos encontrar una estructura bastante típica con su bin, config y doc. Para lanzarlo, necesitamos una consola situada en el directorio raíz de Felix y ejecutar java -jar bin/felix.jar.

Arranque de Felix

Lo primero que se nos pregunta es un nombre de perfil. Podemos poner cualquier cosa. Felix persiste bajo ese nombre y en nuestro directorio personal algunos datos como los módulos cargados. Esto es propio de Felix y Equinox por ejemplo no nos pedirá ningún perfil.

Si en la consola que se nos presenta introducimos help, nos mostrará un listado de los comandos disponibles, como por ejemplo ps (de qué me sonará a mí) que nos muestra el estado de los módulos en ejecución.

Ayuda y ps en Felix

Hay que destacar que tampoco esos comandos son estándares y en Equinox en lugar de ps tendremos que ejecutar ss.

De cara a implementar nuestro primer módulo, debemos conocer las características que tenemos que cumplir para que nuestro módulo pueda funcionar en Felix (o Equinox, que esto ya es parte del estándar) .

  • Tener una clase activadora. Será una clase que implemente BundleActivator (en el ejemplo veremos sus métodos que os adelanto no son demasiado complicados).
  • Definir en el MANIFEST.MF (el descriptor de un jar) algunas propiedades que serán utilizadas por nuestra plataforma OSGi para instalar el módulo.

Bueno, pues aunque pensaba incluir en esta primera entrada la realización del primer módulo, lo dejaré para una posterior (aunque pretendo que no tengáis que esperar mucho).

Actualización: Segunda parte

4 junio 2008 at 8:46 pm 1 comentario


Mi perfil

View Miguel Orbegozo's profile on LinkedIn

Feedjit

Feeds

Otros…

BlogESfera Directorio de Blogs Hispanos - Agrega tu Blog

Bitacoras.com

Add to Technorati Favorites