Posts tagged ‘Felix’

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

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

Older Posts


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