You are on page 1of 71

Curso: “OSGi: Open Services

Gateway Interface”

Dr. Diego Lz. de Ipiña Gz. de Artaza


http://paginaspesonales.deusto.es/dipina
http://www.morelab.deusto.es
http://www.ctme.deusto.es
dipina@eside.deusto.es

Contenido

1. Introducción
a. ¿Qué proporciona?
b. ¿Dónde se aplica?
c. Especificaciones y Herramientas OSGi 2.
2. Arquitectura OSGi
a. JVM, modularidad, gestión de ciclo de vida, seguridad
b. Registro de Servicios
c. Concepto de Bundle
d. Servicios Estándar OSGi
3. Programando OSGi con Knopplerfish
a. Instalación y configuración de plug-in para Eclipse
b. Usando Ant para compilar código OSGi
c. Desarrollando un primer bundle
d. Fichero de manifesto
e. Creación de la clase Activator
f. Compilando e instalando un bundle
g. Creando interfaces de servicio
h. Usando el registro de servicios
i. Usando los servicios avanzados de servicios: ServiceListener y ServiceTracker

2/142

1
Contenido

4. Desarrollo de un ejemplo complejo en OSGi


a. Diseño de un Servicio de Descubrimiento de Servicios
distribuidos
b. Usando el LogService
c. Implementando el servicio, bundle y activator
d. Creación de Servicios Distribuidos descubribles mediante el
Distributed Bundle Discoverer
5. Servicios Avanzados en OSGi
a. Declarative Service
b. Configuration Service
c. Event Admin Service
d. Wire Admin Service
e. R-OSGi

6. Conclusión
3/142

OSGi en Pocas Palabras

 Una framework Java para el desarrollo de aplicaciones


desplegables remotamente, que requieren:
 Robustez
 Elevada distribución
 Heterogeneidad (diferentes dispositivos)
 Colaboraciones

 Resuelve el problema de desplegar muchos programas


independientes en grandes sistemas distribuidos, proveyendo:
 Un sistema operativo para programas
 Un formato para la descarga de código ejecutable
 Un mecanismo para descubrir otros programas
 Estandarización de APIs para promocionar la reutilización
 Gestión eficiente del ciclo de vida de las aplicaciones descargadas

4/142

2
OSGi (Open Services Gateway Initiative)

 Define una Arquitectura Centralizada Orientada a


Servicios (SOA) dentro de una máquina virtual (JVM)

 ¿Por qué se creo?


 Necesidad de crear herramientas que estandaricen los aspectos de
integración del software de tal manera que la reutilización de
componentes software sea más sencilla, fiable, robusta y de bajo
coste.

 ¿Qué aporta?
 OSGi aporta modularidad dinámica a Java y permite estandarizar la
integración del software

5/142

OSGi (Open Services Gateway Initiative)

 OSGi define un entorno de ejecución estandarizado orientado a


componentes que es la base de una arquitectura SOA.
 Proporciona una pequeña capa de software que permite la cooperación
entre componentes Java en una única JVM.
 Gestiona dinámica del ciclo de vida de los componentes gestionados
(instalación, actualización o eliminación) sin reinicio del dispositivo
 Múltiples dominios de aplicación:
 Pasarelas residenciales
 Dispositivos móviles de última generación
 Industria del automóvil
 Aplicaciones de sobremesa o
 Dispositivos electrónicos (Philips iPronto, Nokia N800 y E70 o NSLU2)
 Realmente una especificación, no un producto, en R4:
 r4.core.pdf (2.01 MB) -- R4 Core Specification
 r4.cmpn.pdf (4.55 MB) -- R4 Service Compendium

6/142

3
OSGi Alliance

 OSGi es gestionado por la OSGi Alliance:


http://www.osgi.org/, actualmente más de 30 empresas:

Alpine Electronics Europe Gmbh , Aplix Corporation , BMW Group , Computer Associates ,
Deutsche Telekom AG , Echelon Corporation , Electricité de France (EDF) , Ericsson Mobile
Platforms AB , Esmertec , Espial Group, Inc. , ETRI Electronics and Telecommunications
Research Institute , France Telecom , Gatespace Telematics AB , Gemplus , Harman/Becker
Automotive Systems GmbH , Hitachi, Ltd. , IBM Corporation , Industrial Technology
Research Institute , Insignia Solutions , Intel Corporation , KDDI R&D Laboratories, Inc. ,
KT Corporation , Mitsubishi Electric Corporation , Motorola, Inc. , NEC Corporation , Nokia
Corporation , NTT , Oracle Corporation , Panasonic Technologies, Inc. , ProSyst Software
GmbH , Robert Bosch Gmbh , Samsung Electronics Co., Ltd. , SavaJe Technologies, Inc. ,
Sharp Corporation , Siemens AG , Sun Microsystems, Inc. , Telcordia Technologies, Inc. ,
Telefonica I+D , TeliaSonera , Vodafone Group Services Limited

7/142

Características Principales de OSGi

1. Gestión de componentes software


 Formato de empaquetamiento para aplicaciones (bundle)
 Instalar/Arrancar/Parar/Actualizar/Desinstalar un bundle
 Capacidad de recibir actualizaciones futuras de productos
2. Gestión de Componentes Remota
 Provee una API de gestión a utilizar por un bundle de gestión que mapea un
protocolo a un conjunto de llamadas
 Hace frente a aspectos de heterogeneidad
3. Cooperación entre Aplicaciones
 Los bundles pueden contribuir tanto con código como servicios al entorno
 Contenedor abierto donde las aplicaciones no se ejecutan aisladas, comparten
librerías
 El Registro de Servicios de OSGi ofrece modelo ligero para publicar, encontrar
y asociar servicios dentro de una JVM
 Incluye un servicio de notificación para generar eventos de ciclo de vida
4. Naturaleza Dinámica
 La actualización de componentes no requiere el reinicio
5. Otras propiedades
 Despliegue simplificado
 Separación estricta de interfaz e implementación (enfoque SOA)
 Entorno de Ejecución Seguro
 Componentes Comerciales pueden Desplegarse Fácilmente
8/142

4
¿Qué proporciona OSGi?

 Framework de componentes software estándar y abierto para


productores de dispositivos, proveedores de servicios y
desarrolladores
 Modelo de coexistencia para permitir diferentes componentes
dentro de una JVM
 Modelo cooperativo donde las aplicaciones pueden descubrir y usar
servicios provistos por otras aplicaciones en la misma instancia de
OSGi
 Arquitectura flexible de gestión remota: API de despliegue que
controla ciclo de vida de aplicaciones: bundle + ciclo de vida de
bundle
 Conjunto de servicios opcionales como HTTP, Wiring, IO o
eventos
 Entorno de ejecución seguro

9/142

Complejidad del Software

Service Oriented Programming


Productivity

Structured
Programming

Assembly

Complexity and Size

10/142

5
¿Dónde se aplica?
 Pasarelas residenciales:
 Empresas como Siemens producen dispositivos para la automatización
del hogar y sus componentes conectados por PLC o UPnP. Hace
controlables remotamente a esos dispositivos.
 Aplicaciones de dektop:
 El popular entorno de desarrollo Eclipse está basado en OSGi
(http://www.eclipse.org/osgi/)
 Dispositivos móviles de nueva generación:
 Los fabricantes de dispositivos móviles requieren una plataforma para el
despliegue continuo de servicios escalable, flexible y de pequeño tamaño
basada en OSGi y Java (JSR 232 – http://jcp.org/en/jsr/detail?id=232 y
http://gceclub.sun.com.cn/java_one_online/2006/TS-3757/TS-3757.pdf)
 Automoción:
 Series 5 y 7 BMW incorporan OSGi para su plataforma de información y
entretenimiento (AMI-C – http://www.ami-c.org/)
 Próximamente en Servidores de Aplicaciones Empresariales
 Interface21, creadores de Spring, definiendo la nueva generación de
servidor EE en OSGi (http://www.springframework.org/osgi/specification)
 Ultima versión de IBM WebSphere basada en OSGi
11/142

Ejemplo de Despliegue OSGi en el Hogar (1)

Access
from any Web Terminal Aggregation &
Management Platform

Notification
HomeControl Server

e.g. access from office Subscriber, Service and


or via PDA/WAP phone Device Management
Home Office

Security Internet
Different
Networks Secure Tunnel

Access Family
Webpad OSGi Gateway Portal
Entertainment/ Service Gateway Firewall
Gaming
Service
Offering

Internet
Services Services
Provider

12/142

6
Ejemplo de Despliegue OSGi en el Hogar (2)

13/142

Implementaciones OSGi R4 Comerciales

 Existen varias implementaciones de OSGi comerciales


certificadas para la versión 4:
 Makewave Knopflerfish Pro 2.0 (www.makewave.com) 
comercial/libre
 ProSyst Software mBedded Server 6.0 (www.prosyst.com)
 Samsung OSGi R4 Solution (www.samsung.com)
 KT OSGi Service Platform (KOSP) 1.0 (http://www.kt.co.kr/)
 HitachiSoft SuperJ Engine Framework (http://hitachisoft.jp/)

14/142

7
Implementaciones OSGi R4 Libres

 Además, las siguientes implementaciones libres de R4


OSGi también existen:
 Eclipse Equinox (http://www.eclipse.org/equinox/) – framework
OSGi usada en Eclipse
 Makewave Knopflerfish (http://www.knopflerfish.org/) – más usada
y mejor documentada (elegida para este curso)
 Apache Felix (http://felix.apache.org/site/index.html)
 OSCAR

15/142

Aplicaciones Reales usando OSGi

 X-ray measurement Systems


 BMW 7 series
 Eclipse
 Siemens Medical
 Nokia E70
 Siemens Gigaset SX765
 Espial Set-top box
 VDO on-board computer
 Prosyst mBedded Server, Remote
Manager and Builder
 Bosch and Siemens Home
Appliances
 Philips iPronto
 Telefónica ehogar
 Websphere application server

16/142

8
Características Esenciales de OSGi

 Gestión de componentes software

 Gestión remota de componentes

 Cooperación entre componentes/aplicaciones

 Provisión de entorno de ejecución seguro

17/142

Gestión de Componentes Software

 OSGi provee las siguientes funciones para la gestión del


ciclo de vida de aplicaciones:
 Bundles: formato de empaquetamiento para aplicaciones. Es un
simple JAR compatible con mecanismos de compresión ZIP.
 Gestión de ciclo de vida de bundles:
 Instalar un bundle
 Arrancar/parar un bundle
 Actualizar un bundle
 Desinstalar un bundle
Java VM

OS

CPU IO

18/142

9
Configuración Remota de Componentes

 OSGi está concebido para dispositivos que operan


desatendidos o controlados por un operador de
plataforma que requiera gestión remota

 El ciclo de vida del software no para cuando un dispositivo


abandona la fábrica
 Es conveniente poder actualizar el software instalado una vez
desplegado

 Para permitir gestión remota OSGi proporciona una API de


gestión de bundles, donde algunos bundles autorizados actúan de
puente entre cualquier protocolo y las llamadas de la API.

19/142

Cooperación entre Aplicaciones (1)

 OSGi es el único modelo de servidor de aplicaciones


Java donde éstas pueden compartir código entre ellas
y no se ejecutan aisladas unas de otras:
 A diferencia de MIDP, Java EE (librerías pero mucha replicación)

 OSGi aporta un modelo de servicios ligero que permite


publicar, encontrar y asociar servicios dentro de una JVM
a través del Registro de Servicios
 Servicio OSGi = objeto de un bundle disponible para su uso
por otros bundles

20/142

10
Cooperación entre Aplicaciones (2)

 Arquitectura Orientada a
Servicios (SOA):
 Separa el contrato de la
implementación
 Permite implementaciones Service Contract
alternativas provides
Component
 Descubre y asocia dinámicamente
las aplicaciones uses

 Asociación basada en contratos


(definiciones de interfaz)
 Reutilización de componentes
 Componentes desligados a los
detalles de implementación de otros
componentes, solamente sus
interfaces tienen que conocerse

21/142

Entorno de Ejecución Seguro

 OSGi ofrece un modelo de seguridad dividido en 4


niveles:
 Mecanismo de seguridad de la JVM: previene operaciones
peligrosas como manipulación de punteros o acceso no
restringido a arrays
 Seguridad del lenguaje Java: modificadores de acceso (“public”,
“private”, “protected”)
 Seguridad proporcionada por la plataforma Java SE
(http://java.sun.com/javase/technologies/security/ y
java.security.permission.*)
 OSGi separa unos bundles de otros y comprueba que un bundle
tiene permisos para interactuar con otro

22/142

11
Arquitectura OSGi (1)

 OSGi proporciona un entorno de computación para


bundles que se ejecutan conjuntamente en una JVM.

23/142

Arquitectura OSGi (2)

24/142

12
Arquitectura OSGi (3)

 Permite a las aplicaciones compartir una única JVM.


 Gestiona la carga de clases en una manera mejor
definida y eficiente que el estándar Java
 Soporta incluso versiones
 Provee aislamiento/seguridad entre aplicaciones
 Media permitiendo comunicación y colaboración
entre aplicaciones
 Provee gestión del ciclo de vida (instalar, empezar,
parar, actualizar)
 Libre de políticas
 Éstas son impuestas por los bundles

25/142

Capas de la Framework OSGi (1)

Services
Security
Applications

Life Cycle

Module

Execution Environment

26/142

13
Capas de la Framework OSGi (2)

 Entorno de ejecución
 Provee un contexto de ejecución bien definido a las aplicaciones, tal como J2SE, CDC, CLDC,
MIDP

 Módulos
 Provee capacidades de carga y empaquetamiento de clases
 Facilita el lincado entre módulos

 Ciclo de Vida:
 Instalación, comienzo, parada, actualización y desinstalación dinámica de Bundles
 Mecanismos de dependencia para asegurar operación correcta del entorno

 Servicios:
 Modelo de cooperación entre bundles que tiene en cuenta el dinamismo
 Completo modelo para compartir objetos entre bundles.
 Provisión de un mecanismo de eventos para gestionar el dinamismo

 Seguridad
 Imbuida en todas las capas basada en Java y en el modelo de seguridad de Java 2
 Añade gestión dinámica de permisos

27/142

Capas de la Framework OSGi: Entorno de


Ejecución

 OSGi requiere un entorno de computación seguro,


abierto, robusto, bien documentado, maduro, rico y
portable
 Inspirado en Java porque en 1999 cuando se creó OSGi, Java ya
contaba con uno
 Podrían realizarse implementaciones alternativas de OSGi en
.NET
 Las APIs de OSGi utilizan un subconjunto de las clases
definidas por Java SE o Java ME CDC/CLDC
CLDC/
MIDP

OSGi
Min.

J2SE
CDC/FP 28/142

14
Capas de la Framework OSGi: Modularidad (1)

 Un bundle es la unidad de ejecución en OSGi


 Compuesto principalmente de clases Java, librerías, recursos y
manifest.mf
 Mejora la modularidad de las aplicaciones Java:
 Elimina dependencias en Classpath
 Protege quién accede a qué
 Soporta versiones

29/142

Capas de la Framework OSGi: Modularidad (2)

 Características:
 Compartición: OSGi promueve compartir las clases entre bundles
 Un bundle puede proveer librerías utilizadas por otros bundles  reducción en
necesidades de memoria
 Cada bundle puede exportar e importar paquetes (conjuntos de clases):
 Si múltiples bundles exportan el mismo paquete (con una versión diferente), la
framework ha de seleccionar una versión apropiada por cada bundle
 Tras desinstalar un bundle los importadores son reiniciados para que se asocien a
otro nuevo exportador de paquetes
 Gestión de interdependencias: los bundles pueden depender de
funcionalidad ya alojada en un entorno
 Lazy loading: un bundle puede tener dependencias en bundles todavía
no instalados
 Versionamiento: Diferentes bundles pueden utilizar diferentes versiones
de la misma clase

30/142

15
Capas de la Framework OSGi: Modularidad (3)

31/142

Capas de la Framework OSGi: Ciclo de Vida (1)

 El bundle del sistema representa a la framework OSGi.


 Ofrece una API para gestionar bundles: State (active or not)

Manages
 Instalarlos
 Resolverlos
 Arrancar
 Parar System
bundle
Bundle
M
 Refrescar
 Actualizar
 Desinstalar Bundle
X-v2
X

Bundle
Bundle B
A

32/142

16
Capas de la Framework OSGi: Ciclo de Vida (2)

 Un bundle es iniciado por la


clase BundleActivator
 Una cabecera en el fichero JAR
que define un bundle hace
referencia a esta clase
INSTALLED STARTING
 La interfaz BundleActivator
tiene dos métodos:
 () inicializa y retorna
Start()
Start(): start
inmediatamente
 Stop(): limpia el bundle RESOLVED ACTIVE

 El BundleActivator recibe un
stop
BundleContext que provee
acceso a las funciones de la
framework OSGi UNINSTALLED STOPPING

 La Framework provee el servicio


Start Level que controla el
inicio/parada de grupos de
aplicaciones

33/142

Capas de la Framework OSGi: Servicios(1)

 Provee un modelo de servicios dentro de una JVM


 Descubrimiento (y notificación) de servicios basada en interfaces y
propiedades, no requiere ningún protocolo
 Asociación a uno o varios servicios mediante:
 Control de programa
 Siguiendo ciertas reglas de la framework
 Configuración de despliegue
 Aclaración sobre Service Oriented Architectures (SOA)
 Los Servicios Web se asocian y descubren en la red
 En la plataforma OSGi lo hacen dentro de una Java VM
 La OSGi Alliance define un gran conjunto de servicios

34/142

17
Capas de la Framework OSGi: Servicios(2)

35/142

Capas de la Framework OSGi: Seguridad

 Basado en Seguridad de Java 2


 Permisos
 Firma de bundles

36/142

18
Beneficios de la Plataforma OSGi

 Los componentes son pequeños


 Fáciles de hacer
 Los componentes están totalmente desacoplados unos
de otros
 Aporta reusabilidad
 Modelo colaborativo
 Permite la reutilización de componentes para diferentes
aplicaciones
 Gran aceptación
 Mercado grande, muchos componentes existentes
 Modelo dinámico para las personalización y variación
continua de aplicaciones en los dispositivos actuales

37/142

Bundles: Infraestructura de Despliegue en


OSGi

 Un bundle es una aplicación autocontenida ejecutable en


diferentes implementaciones de OSGi
 Como si fuera un fichero EXE en Windows
 Contiene programas y recursos
 Registra cero o más servicios
 Un servicio se especifica como una interfaz Java y puede ser
implementado por varios bundles
 Un mecanismo de búsqueda puede ser utilizado para encontrar
servicios registrados por otros bundles
 Lenguaje de consultas (filtros)

 Recordemos que:
 La propia framework es un bundle (System Bundle)
 La especificación de OSGi define un conjunto de servicios estándar
que las aplicaciones pueden cargar y utilizar
 Bundle Repository – http://www2.osgi.org/Repository/HomePage
 Oscar Bundel Repository: http://oscar-osgi.sourceforge.net/

38/142

19
Bundles: Contenido interno

 Un bundle es un fichero JAR que contiene:


 El fichero manifest.mf con los metadatos del bundle: Bundle A
 Algunas cabeceras predefinidas por el formato JAR {…}
 Otras definidas por la OSGi Alliance
 Código (las clases en paquetes)
 Recursos (otros ficheros dentro del .JAR)
 Durante la instalación, la framework:
 Lee el manifesto del fichero
 Instala el código y los recursos
 Resuelve las dependencias
 Inicia el control del ciclo de vida del bundle
 Durante la ejecución, la framework:
 Invoca BundleActivator para iniciar gestión del ciclo de vida
 Gestiona el CLASSPATH del bundle como una red de classloaders
 Gestiona las dependencias entre servicios
 Invoca a BundleActivator para parar el bundle
 Elimina los recursos utilizados por el bundle cuando acaba

39/142

Modelo de Colaboración en OSGi

 OSGi es más que un entorno de ejecución de Applet,


MIDlet o Xlet
 Los bundles, unidades de ejecución en OSGi, colaboran
mediante:
 Objetos de servicios
 Compartiendo paquetes
 Un Registro de Servicios dinámico permite a un bundle
encontrar y seguir el rastro de otros objetos de servicio
 La framework efectúa una gestión eficiente de esta colaboración
 Dependencias, seguridad

40/142

20
Modelo de Colaboración en OSGi: Servicios

= service, defined by
OSGi Framework java interface

= bundle
Bundle A
{…}
Bundle B
{…}

Bundle C
{…}

41/142

Modelo de Colaboración en OSGi:


Dependencias

 La especificacion OSGi soporta la


declaración de dependencias mediante
Import-Package
las cabeceras: Require-
Require-Bundle e p
Import-
Import-Package q
 Require-Bundle crea una r r
dependencia en un bundle completo
s
 Muy fácil de usar
 Importa paquetes que no son utilizados
 Import-Package crea una Require-Bundle

dependencia en un único paquete


 Los bundles solamente importan lo que
necesitan
r
 Se recomienda usar Import-Package
porque facilita el despliegue y la gestión
de versiones

42/142

21
Modelo de Colaboración en OSGi: Servicios

 OSGi define una plataforma orientada a servicios con


tres actores:
 Proveedores de Servicios, publican descripciones de servicios
 Consumidores de Servicios, descubren los servicios y se
asocian a sus proveedores
 Pueden recibir notificaciones sobre cambios en el estado de servicios
 Registro de Servicios, permite a los consumidores de servicios
descubrir otros servicios mediante consultas en sintaxis LDAP:
 "(&(" + Constants.OBJECTCLASS +
"=Person)(|(sn=Jensen)(cn=Babs J*)))"
 En OSGi, un servicio está compuesto de:
 Interfaz de Servicio, una clase o interfaz Java
 Propiedades del servicio, pares nombre-valor
 Los servicios se implementan como objetos dentro del
bundle
43/142

Modelo de Colaboración en OSGi: Servicios

44/142

22
Modelo de Colaboración en OSGi: Servicios

45/142

Modelo de Colaboración en OSGi: Servicios

Java Application Manager

No management bundles

Service
Midlet, registry Midlet, No collaboration
Xlet, Xlet,
or or
Applet packages Applet
packages No package management
(versions!)

JAVA

Operating System No native code

Hardware

46/142

23
Ciclo de Vida de un Bundle en Detalle (1)

 Antes de poder arrancar un bundle instalado es necesario


resolver sus dependencias
 Todo bundle arrancable debe implementar la interfaz BundleActivator
con los métodos: a) start(BundleContext) y b)
stop(BundleContext)
 La cabecera del manifesto Bundle-Activator indica la clase que habrá que
instanciar para arrancar o parar un bundle
 Durante la vida de un bundle varios eventos pueden ocurrir en la
framework:
 Otros bundles son parados, actualizados, desinstalados, instalados,
empezados, etc.
 Si se desinstala un bundle en el que otro tiene dependencias, el
último accederá a los paquetes exportados anteriormente mientras no
haya alternativas a esos paquetes exportados adoptados mediante un
refresco del bundle
 El comienzo y fin de un bundle es grabado permanentemente,
además existen start-levels que indican el orden de arranque de los
bundles en la framework

47/142

Ciclo de Vida de un Bundle en Detalle (2)

 El objeto BundleContext provee una API para la


instalación de bundles y su registro

48/142

24
Registro de Servicios en Detalle (1)

 La característica diferencial de OSGi frente a otros


entornos Java es su naturaleza dinámica:
 Teléfono móvil es asociado a un nuevo dispositivo
 Pasarela residencial detecta nueva electrodoméstico conectado
 Coche detecta la presencia de un teléfono móvil a su alrededor

 El Registro de Servicios permite a los desarrolladores


de aplicaciones construir pequeños y desacoplados
componentes que pueden adaptarse al entorno cambiante
en tiempo real
 Estos componentes pueden ser combinados para crear complejas
aplicaciones

49/142

Registro de Servicios en Detalle (2)

 Un servicio se registra bajo un nombre de interfaz y un conjunto de


propiedades
 Un lenguaje de filtrado sencillo basado en LDAP es utilizado para
seleccionar los servicios necesarios.
 (&(sn=Ipiña)(cn=Diego))
 La interfaz ServiceListener y la clase ServiceTracker
permiten recibir notificaciones de eventos de ciclo de vida de servicios
de interés
 La interfaz BundleContext permite la interacción con el Registro de
Servicios:
 Registrar objetos (BundleContext.registerService())
 Buscar otros objetos en el registro
(BundleContext.getServiceReference())
 Recibir notificaciones cuando servicios de interés son registrados o
eliminados (BundleContext.addServiceListener())

50/142

25
Detalles sobre Servicios
listen

 Un servicio es un objeto registrado


bind
con el Framework por un bundle register
para su uso por otros bundles
 La semántica de un servicio es
dada por su interfaz Java
 Un bundle puede registrar un service
servicio
 Un bundle puede usar un servicio package org.osgi.service.log;
import org.osgi.framework.ServiceReference;
(bind) con cierta cardinalidad public interface LogService {
 1..1, 0..1, 0..n static final intLOG_ERROR= 1;
static final intLOG_WARNING= 2;
 Un servicio puede ser descubierto static final intLOG_INFO= 3;
dinámicamente static final intLOG_DEBUG= 4;
 Búsqueda activa con filtro de void log(int level, String message);
consulta void log(int level, String message,
Throwable exception);
 Interfaz listener void log(ServiceReference sr,int level,
 ¡Los servicios pueden acabar en String message);
void log(ServiceReference sr, int level,
cualquier momento! ¡Todo es String message, Throwable exception);
muy dinámico! }

51/142

Manipulación de Servicios

 La interfaz BundleContext
facilita los métodos para manipular
el registro de servicios
ServiceRegistration registerService(
 Los registros de servicio son String clss,
gestionados por objetos de tipo Object srvc,
ServiceRegistration Dictionary prprts)

 Pueden utilizarse para desregistrar ServiceReference[]


un servicio o modificar sus getServiceReferences(
propiedades String clss,
String fltr)
 Los objetos ServiceReference
dan acceso al servicio así como a Object getService(
sus propiedades ServiceReference reference)
 El acceso a un servicio es boolean ungetService(
mediante el método getService ServiceReference rfrnc);
 Los servicios se devuelven con el
método ungetService.
ungetService

52/142

26
Seguridad en Detalle

 OSGi ejecuta aplicaciones de una variedad de fuentes


bajo control estricto de un sistema de gestión:
 Seguridad de Código de Java 2: java.security.Permission
y sus subclases (FilePermission, SocketPermission)
protegen el acceso a recursos del sistema
 Exposición de contenido de bundles mínima mediante
modificadores de acceso de las clases Java o haciendo que los
paquetes sean visibles sólo dentro de un bundle
 Permisos de paquete OSGi limitan quién puede importar o
exportar paquetes o mediante
org.osgi.framework.ServicePermission

53/142

Servicios Estándar en OSGi (1)

 Servicios del Framework:


 Admin los permisos de bundles actuales o futuros
Permission Admin:
pueden ser manipulados a través de este servicio
 Conditional Permission Admin: Admin extiende el Permission
Admin con permisos que son aplicados cuando ciertas
condiciones son cumplidas
 Package Admin: provee información sobre el estado compartido
por un paquete y permite refrescarlos
 Start Level: conjunto de bundles que deben ejecutarse
conjuntamente precediendo o siguiendo a otros niveles de
comienzo
 URL Handlers: permite a los bundles contribuir dinámicamente
con nuevos gestores de contenidos a la clase URL

54/142

27
Servicios Estándar en OSGi (2)

 Servicios del Sistema:


 Log Service: trazado de información, advertencias, información
de debug o errores es redireccionado a bundles subscritos con él
 Configuration Admin: modelo flexible y dinámico para obtener
información de configuración
 Event Admin: mecanismo general y flexible de publicar y
subscribirse a eventos
 Device Access: mecanismo para asociar un driver a un nuevo
dispositivo y descargar automáticamente un bundle
 User Admin: BBDD con información de usuario con propósito de
autenticación y autorización
 IO Conector: permite a los bundles proveer nuevos y alternativos
protocolos para javax.microedition.io
 Preferences Service: provee acceso a base de datos jerárquica
de propiedades. Similar al registro de Windows.

55/142

Servicios Estándar en OSGi (3)

 Servicios del Sistema:


 Servicio HTTP: este servicio ejecuta un contenedor de servlets,
los bundles pueden proveer servlets que son accesibles mediante
HTTP.
 Servicio UPnP: mapea dispositivos en una red UPnP al Registro
de Servicios.
 Wire Admin: permite la composición de diferentes servicios de
acuerdo a una conexión.

56/142

28
Servicios Estándar en OSGi (4)

 Soporte a la Programación:
 Service Tracker: simplifica la gestión de servicios proveyendo
una clase que sigue la pista de los servicios de una aplicación
 Declarative Services: permite leer una configuración XML de un
bundle con registro de servicios y dependencias. Será iniciado
solamente cuando los servicios declarados sean realmente
necesarios por otros bundles.

57/142

Knopflerfish

 Varias opciones de implementaciones open source


 Makewave Knopflerfish – http://www.knopflerfish.org/
 Equinox – implementación de OSGi usada por Eclipse
(http://www.eclipse.org/equinox/)
 Apache Felix (http://felix.apache.org)
 Knopflerfish ofrece la mejor documentación y acabado
 Muy sencilla de utilizar
 Provee herramienta de gestión de bundles fantástica
 Producida por Makewave (antes Gatespace Telematics)
 Una de las implementaciones de pago más utilizadas
 Para una comparativa entre las ventajas y desventajas de las
diferentes implementaciones open source de OSGi visitar:
 http://www.pierocampanelli.info/articles/2007/01/22/status-of-opensource-
osgi-containers

58/142

29
Instalación de Knoplerfish

 Prerrequisito: tener una versión de Java 1.2.2 o superior


en tu máquina
 Descargar knopflerfish_osgi_2.0.1.jar (11 MB)
 Framework completa, incluyendo código fuente, documentación,
ejecutable autoextraíble:
 http://www.knopflerfish.org/download.html#2.0.1
 Instalar Knoplerfish con el siguiente comando:
 java -jar knopflerfish_osgi_<version>.jar
 Ejecutar Knoplerfish mediante:
 cd
%KNOPFLERFISH_INTALL_DIR%/knopflerfish.org/osgi
 java –jar framework.jar
 Abrirá el Knopplerfish OSGi Desktop

59/142

Knoplerfish OSGi Desktop

60/142

30
Instalación Plug-in Eclipse OSGi

 Pasos necesarios para su instalación:


1. Seleccionar la opción de menú en Eclipse HelpSoftware
UpdatesFind and Install....
2. Seleccionar Search for new features to install e introducir
los detalles de un nuevo site remoto: Knopflerfish update site, y
la URL http://www.knopflerfish.org/eclipse-update/.
3. Hacer clic sobre la caja Knopflerfish update site y pulsar
Finish.
 Documentado en: http://www.knopflerfish.org/eclipse_install.html

 Pasos necesarios para su configuración:


 Seleccionar opción de menú WindowPreferences y en Framework
añadir el directorio de instalación de Knopflerfish.
 Seleccionar Default JRE como el entorno de ejecución de bundles.
 Podrían seleccionarse otras opciones como CLDC u OSGi Minimum
 Asociar un Bunde repository donde Eclipse pueda resolver
dependencias durante la compilación y ejecución de los bundles.
 Documentado en: http://www.knopflerfish.org/eclipse_preferences.html

61/142

Configuración de un Proyecto Knopflerfish en


Eclipse

1. Seleccionar la opción de menú


FileNewProject...
2. Seleccionar la opción Bundle Project e introducir la
información del proyecto.
3. Editar y compilar el proyecto creado.
 La primera vez que se vaya a compilar y ejecutar el proyecto
habrá que introducir una nueva configuración de lanzamiento,
yendo a la opción del menú Run: OSGiKnopflerfish.
 Documentación adicional en:
http://www.knopflerfish.org/eclipse_plugin.html

62/142

31
Usando Ant para Compilar Bundles

 Knopflerfish viene con un fichero build.xml


preconfigurado que permite la generación y compilación
de bundles en OSGi
 Pasos para configurar el proyecto:
1. Crear un nuevo directorio donde colocar el código del nuevo
bundle. Por ejemplo, holamundobundle.
2. Copiar el fichero
knopflerfish_osgi_2.0.1\knopflerfish.org\ant\bui
ld_example.xml a holamundobundle\build.xml.
3. Configurar la plantilla de fichero build.xml a tu proyecto. Entre
otras cosas deberás configurar las propiedades impl.pattern
y api.pattern.
4. Invocar ant.
5. Instalar el bundle, bien usando la interfaz gráfica o bien los
comandos de línea de comando provistos por Knopflerfish.

63/142

Nuestro Propio Fichero Ant

 Nosotros vamos a utilizar una versión simplificada del


build.xml, no autogenera manifest.mf, pero sí
compila (compile), crea el .jar (jar) correspondiente al
bundle y lo despliega en Knopflerfish (deploy)
 IMPORTANTE: hay que crear la variable de entorno OSGI_HOME
para que apunte al directorio de instalación de Knopflerfish,
por ejemplo:
c:\knopflerfish_osgi_2.0.1\knopflerfish.org

64/142

32
Nuestro Propio Fichero Ant

<?xml version="1.0"?>
<project name="nombre-bundle" default="all">
<property name="app.name" value="nombre-bundle"/>
<property name="output.home" value="./build"/>
<property environment="env"/>
<property name="osgi.deploy" value="${env.OSGI_HOME}/jars"/>
<path id="lib.class.path">
<fileset dir="${env.OSGI_HOME}">
<include name="**/*.jar"/>
</fileset>
</path>
<target name="all" depends="init,compile,jar,deploy"/>
<target name="init">
<mkdir dir="./classes"/><mkdir dir="./build"/>
</target>
<target name="compile">
name="compile">
<javac destdir = "./classes
"./classes"
classes" debug = "on
"on">
on">
<src path=
path= "./src
"./src"/><
src"/><classpath
"/><classpath refid="
refid="lib.class.path
="lib.class.path"/>
lib.class.path"/>
</javac
</javac>
javac>
</target
</target>
target>

65/142

Nuestro Propio Fichero Ant

<target name="
name="jar
="jar">
jar">
<jar basedir = "./classes"
jarfile = "./build/${app.name}.jar"
compress = "true" includes = "**/*"
manifest = "./meta-inf/MANIFEST.MF"/>
</target>
<target name="
name="clean
="clean">
clean">
<delete dir = "./classes"/><delete dir = "./build"/>
</target>
<target name="
name="deploy
="deploy"
deploy" depends="
depends="jar
="jar">
jar">
<delete>
<fileset dir="${osgi.deploy}">
<include name="${app.name}.jar"/>
</fileset>
</delete>
<copy todir="${osgi.deploy}">
<fileset dir="${output.home}" includes="${app.name}.jar"/>
</copy>
</target>
</project>

66/142

33
Creando nuestro primer bundle

 Nuestro primer bundle contendrá un hilo que imprime el


mensaje “¡Hola Mundo!” cada cinco segundos.
 Pasos para implementar un bundle autónomo que no
exporta servicios a otros, pero sí puede consumirlos:
 Creación del fichero manifest.mf.
 Edición de una clase que implemente la interfaz
BundleActivator.
 Edición de la clase del bundle, compilación y despliegue del
bundle.

67/142

Pasos en detalle para crear nuestro primer


bundle

1. Creación de un directorio para el bundle


1. cd %KNOPFLERFISH_INSTALL%/knopflerfish.org/osgi
2. mkdir bundles
3. mkdir simplebundle
4. mkdir simplebundle/src
5. mkdir simplebundle/META-INF
2. Creación del fichero simplebundle/META-INF/manifest.mf
Manifest-Version: 1.0
Bundle-Name: simplebundle
Bundle-SymbolicName: simplebundle
Bundle-Version: 1.0.0
Bundle-Description: Demo Bundle
Bundle-Vendor: Universidad de Deusto-ko Unibertsitatea
Bundle-
Bundle-Activator:
Activator: es.deusto.simplebundle.impl.Activator
Bundle-Category: example
Import-
Import-Package:
Package: org.osgi.framework

68/142

34
Pasos en detalle para crear nuestro primer
bundle

 manifest.mf
 Fichero existente en todo archivo .jar
 Extendido por la especificación de OSGi para añadir información adicional
sobre un bundle.
 Indica los servicios ofrecidos por un bundle a otros bundles.
 Expresa las interdependencias existentes entre el bundle configurado y otros
- Un bundle no arranca hasta que todas sus dependencias han sido resueltas.
 En OSGi al fin y al cabo todo es un bundle, incluso la propia framework
 Su contenido documentado en página 3.2.1 Bundle Manifest Headers
(página 36) de la Especificación de OSGi
 Propiedad Bundle-
Bundle-Activator indica a la framework qué clase es la
Activator  clase principal a invocar por la framework cuando cargue
el bundle
 Import-Package indica al framework que nuestro bundle requiere
Import-
acceso a todas las clases en el paquete org.osgi.framework

69/142

Pasos en detalle para crear nuestro primer


bundle
3. Create
simplebundle/src/es/deusto/simplebundle/impl/Activator.java

package es.deusto.simplebundle.impl;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
public static BundleContext bc = null;
private HelloWorldThread thread = null;

public void start(BundleContext bc)


bc) throws Exception {
System.out.println("SimpleBundle starting...");
Activator.bc = bc;
this.thread = new HelloWorldThread();
HelloWorldThread
this.thread.start();
}
public void stop(BundleContext bc)
bc) throws Exception {
System.out.println("SimpleBundle stopping...");
this.thread.stopThread();
this.thread.join();
Activator.bc = null;
}
}

70/142

35
Pasos en detalle para crear nuestro primer
bundle

 Casi todos los bundles tienen una clase Activator


 Los Bundles que exportan funcionalidad pero no son ejecutados carecen de esta
clase
 Clase que implementa la interfaz org.osgi.framework.BundleActivator
 Los métodos start() y stop() permiten gestionar el ciclo de vida de un bundle
 La clase BundleContext permite a un bundle interactuar con la
framework OSGi:
 Subscribirse a eventos publicados por el framework (addXXXListener
addXXXListener)
addXXXListener
 Registrar servicios con el Registro de Servicios de la framework OSGi
(registerService
registerService)
registerService
 Recuperar ServiceReferences del Registro de Servicios
(getServiceReferences
getServiceReferences)
getServiceReferences
 Obtener y liberar objetos de servicios (getService
getService y ungetService)
ungetService
 Instalar nuevos bundles (installBundle
installBundle)
installBundle
 Obtener la lista de bundles disponibles (getBundles())
 Obtener el objeto Bundle asociado a una implementación de un bundle
(getBundle
getBundle)
getBundle
 Crear ficheros permanentes para el uso del bundle (getDataFile
getDataFile)
getDataFile

71/142

Pasos en detalle para crear nuestro primer


bundle

4. Create
simplebundle/src/es/deusto/simplebundle/impl/HelloWorldThread.j
ava

package es.deusto.simplebundle.impl;
public class HelloWorldThread extends Thread {
private boolean running = true;
public HelloWorldThread() {
}
public void run() {
while (running) {
System.out.println("Hello World!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("HelloWorldThread ERROR: " + e);
}
}
}
public void stopThread() {
this.running = false;
}
}

72/142

36
Pasos en detalle para crear nuestro primer
bundle

5. Compilarlo con fichero Ant provisto: ant


6. Importarlo usando el Knopplerfish OSGi Desktop

73/142

Ejecución del Bundle

74/142

37
Ciclo de Desarrollo de un Bundle en OSGi

 Los pasos a seguir son:


1. Creación del fichero manifest.mf
2. Definición de una interfaz Java con los métodos provistos por el
servicio a ofrecer.
3. Implementación de tal interfaz en una clase Java.
4. Activación de la clase creada mediante un BundleActivator
5. Compilación y despliegue del bundle

 Los ponemos en práctica mediante el desarrollo de la


aplicación datebundle
 Ofrece como servicio formatear una fecha como un string
 Principal novedad del fichero manifest.mf es la cabecera
Export-
Export-Package: es.deusto.firstservice

75/142

Creando tu primer bundle ofreciendo un


servicio

1. Definimos el fichero manifest.mf


Manifest-Version: 1.0
Bundle-Name: firstservice
Bundle-SymbolicName: firstservice
Bundle-Version: 1.0.0
Bundle-Description: Demo Bundle
Bundle-Vendor: Universidad de Duesto
Bundle-
Bundle-Activator:
es.deusto.firstservice.impl.Activator
Bundle-Category: example
Import-
Import-Package: org.osgi.framework
Export-
Export-Package: es.deusto.firstservice

76/142

38
Creando tu primer bundle ofreciendo un
servicio

2. Creamos la interfaz que define el servicio


src/es/deusto/dateservice/DateService.java
package es.deusto.dateservice;
import java.util.Date;

public interface DateService {


public String getFormattedDate(Date date);
}
3. Creamos la implementación del servicio en
src/es/deusto/dateservice/impl/DateServiceImpl.java
package es.deusto.dateservice.impl;
import java.text.DateFormat;
import java.util.Date;
import es.deusto.dateservice.DateService;
public class DateServiceImpl implements DateService {
public String getFormattedDate(Date date) {
return
DateFormat.getDateInstance(DateFormat.SHORT).format(date);
}
}

77/142

Creando tu primer bundle ofreciendo un


servicio
4. Creación de la clase que activa (Activator) el bundle en OSGi y exporta el servicio:
src/es/deusto/dateservice/impl/Activator.java:
package es.deusto.dateservice.impl;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import es.deusto.dateservice.DateService;

public class Activator implements BundleActivator {


public static BundleContext bc = null;
public void start(BundleContext bc)
bc) throws Exception {
System.out.println("Empezando " +
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME)
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " ...");
Activator.bc = bc;
DateService service = new DateServiceImpl();
ServiceRegistration registration =
bc.registerService(DateService.class.getName(),
bc.registerService(DateService.class.getName(), service, new Hashtable());
Hashtable());
System.out.println("Servicio registrado: dateservice");
}

public void stop(BundleContext bc)


bc) throws Exception {
System.out.println("Parando " +
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " ...");
Activator.bc = null;
}
}
5. Compilar y ejecutar la aplicación

78/142

39
Registro de Servicios en OSGi

 El método registerService de BundleContext


permite el registro de un servicio con el Registro de
Servicios de OSGI. Recibe tres parámetros:
 Nombre de la interfaz del servicio
 Implementación del servicio
 Información adicional (opcional) sobre el servicio en formato de
pares clave/value.
 Ejemplo de registro de servicio:
Long I = new Long(20);
Hashtable props = new Hashtable();
Hashtable();
props.put("description",
props.put("description", "This an long value");
bc.registerService(Long.class.getName(),
bc.registerService(Long.class.getName(), i, props);
props);

79/142

Más detalles sobre el Activator

 El método getBundle() de BundleContext devuelve


un objeto de tipo org.osgi.framework.Bundle
asociado con tal contexto.
 El objeto Bundle permite recuperar todo tipo de
metadatos:
 Su identificador (getBundleId
getBundleId()
getBundleId())
()
 Cabeceras de su fichero manifest.mf asociado
(getHeaders
getHeaders()
getHeaders()) ()
 Recursos asociados al bundle (getResources
getResources()
getResources()).
()
 La interfaz Constants define nombres estándar para
propiedades del entorno OSGi, sus servicios y las
cabeceras del fichero Manifest (e.g. BUNDLE_NAME,
BUNDLE_ACTIVATOR).
80/142

40
Consumiendo un Servicio en OSGi

 Creamos un nuevo proyecto denominado DateBundleUser con los


ficheros manifest.mf y Activator.java
 Manifest.mf:
Manifest-Version: 1.0
Bundle-Name: dateserviceuser
Bundle-SymbolicName: dateserviceuser
Bundle-Version: 1.0.0
Bundle-Description: Bundle that consumes dateservice
exported by another bundle
Bundle-Vendor: Revista Sólo Programadores
Bundle-
Bundle-Activator:
Activator: es.deusto.dateserviceuser.impl.
es.deusto.dateserviceuser.impl.
ActivatorWithoutCheckingReference
Import-
Import-Package:
Package: org.osgi.framework,es.deusto.dateservice

81/142

Consuming a Service in OSGi


 Creamos la clase
datebundleuser/src/es/deusto/dateserviceuser/impl/ActivatorWithoutChecking
Reference.java, que obtiene una referencia al servicio DateService de
manera incorrecta:
 Para dateservice y luego ejecuta dateserviceuser

package es.deusto.dateserviceuser.impl;

import java.util.Date;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import es.deusto.dateservice.DateService;

public class ActivatorWithoutCheckingReference implements BundleActivator {


public static BundleContext bc = null;
public void start(BundleContext bc) throws Exception {
System.out.println("Empezando" + bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME)
+ " ...");
ActivatorWithoutCheckingReference.bc = bc;
ServiceReference reference = bc.getServiceReference(DateService.class.getName());
bc.getServiceReference(DateService.class.getName());
DateService service = (DateService)bc.getService(reference
(DateService)bc.getService(reference);
DateService)bc.getService(reference);
System.out.println("Usando DateService: formatting date: " + service.getFormattedDate(new
Date()));
bc.ungetService(reference);
bc.ungetService(reference);
}

public void stop(BundleContext bc) throws Exception {


System.out.println("Parando " + bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + "
...");
ActivatorWithoutCheckingReference.bc = null;
}
}

82/142

41
Consumiendo Servicios en OSGi
proporcionados por ServiceFactory

 Una factoría de servicios permite la personalización del


objeto de servicio que es devuelto cuando un bundle
invoca a
BundleContext.getService(ServiceReference).
BundleContext.getService(ServiceReference)
 Normalmente, el objeto de servicio registrado por el bundle es
devuelto
 Si el objeto de servicio implementa la interfaz
org.osgi.framework.ServiceFactory, la Framework invoca el
método ServiceFactory.getService para crear un instancia
única no compartida del objeto de servicio por cada bundle que
quiere obtener el servicio.
 La framework cachea el objeto devuelto hasta que el bundle lo libere.

83/142

Declarando, Instanciando y Registrando un


Service Factory
 Definición del ServiceFactory:
import org.osgi.framework.ServiceFactory;
public class DisplayServiceFactory implements ServiceFactory {
public Object getService(Bundle bundle, ServiceRegistration registration)
{
Display newDisplay = new Display(Long.toString(bundle.getBundleId()));
return newDisplay;
}
public void ungetService(Bundle bundle, ServiceRegistration
registration,Object service) {
//Nothing needed here in this case
}
}
 Creando y registrando el ServiceFactory:
//Create the ServiceFactory
DisplayServiceFactory factory = new DisplayServiceFactory();
DisplayServiceFactory();
//Create the properties of the service. Not mandatory, but used to show
//how properties work
Hashtable properties = new Hashtable();
Hashtable();
properties.put("service.description",
properties.put("service.description", "Factory of Display Services");
properties.put("service.type",
properties.put("service.type", "Factory");

//Register the ServiceFactory for the type IDisplay


ServiceRegistration registration =
context.registerService(IDisplay.class.getName(),
context.registerService(IDisplay.class.getName(), factory, properties);

84/142

42
Usando un Servicio OSGi que Implementa
ServiceFactory

//Get and Use one Factory of DisplayService using a filter


String filter = "(service.type
"(service.type=Factory)";
service.type=Factory)";
ServiceReference[]
ServiceReference[] serviceRef =
context.getServiceReferences(IDisplay.class.getName(),filter);
context.getServiceReferences(IDisplay.class.getName(),filter);
//Here we now there should be only one
IDisplay display = (IDisplay)context.getService(serviceRef[0]);
display.showMessage("Using Display service from Display Consumer -
Search with a filter");
//Release the service reference. This MUST be done when the
// service is no longer going to be used by the consumer bundle
context.ungetService(serviceRef[0]);

85/142

Consumiendo Servicios en OSGi

 OSGi es un lugar muy dinámico donde los servicios


aparecerán y desaparecerán continuamente
 Necesidad de comprobar que lo que se recupera del Registro
de Servicios de OSGi es realmente una implementación de
servicio válida y no null
 Después de haber utilizado el servicio es recomendable realizar
un unget
 Recuperación de una instancia de un servicio es un doble paso:
1. Recuperación de una referencia al servicio mediante el método
getServiceReference de BundleContext y
2. Recuperación de un una instancia del servicio mediante el método
getService de BundleContext

86/142

43
Consumiendo Servicios en OSGi

 Mejora 1  Comprobar que el servicio es disponible


antes de utilizarlo:
ServiceReference reference =
bc.getServiceReference(DateService.class.getName(
bc.getServiceReference(DateService.class.getName(
));
if (reference != null)
null) {
DateService service =
(DateService)bc.getService(reference);
System.out.println("Usando DateService:
formateando fecha: "
+service.getFormattedDate(new Date()));
bc.ungetService(reference);
} else {
System.out.println("¡Servicio no disponible!");
}

87/142

Consumiendo Servicios en OSGi

 Mejora 2  Usar ServiceListener


public class ActivatorWithServiceListener implements
BundleActivator, ServiceListener {
BundleActivator,
public static BundleContext bc = null;
private ServiceUserThread thread = null;
private DateService service = null;
public void start(BundleContext bc)
bc) throws Exception {
System.out.println("Empezando " + getClass().getName());
ActivatorWithServiceListener.bc = bc;
String filter = "(objectclass
"(objectclass="
objectclass=" +
DateService.class.getName()
DateService.class.getName() + ")";
bc.addServiceListener(this,
bc.addServiceListener(this, filter);
ServiceReference references[] =
bc.getServiceReferences(null, filter);
for (int i = 0; references != null && i <
references.length; i++) {
this.serviceChanged(new
ServiceEvent(ServiceEvent.REGISTERED, references[i]));
}
}
public void serviceChanged(ServiceEvent event) {

}
88/142

44
Consumiendo Servicios en OSGi
 Mejora 3  Usar ServiceTracker (BestActivator.java)
public class BestActivator implements BundleActivator {
public static BundleContext bc = null;
private ServiceTracker tracker = null;

public void start(BundleContext bc)


bc) throws Exception {
System.out.println("Arrancando " +
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + "
...");
BestActivator.bc = bc;
MyServiceTrackerCustomizer customizer = new
MyServiceTrackerCustomizer(bc);
MyServiceTrackerCustomizer(bc);
tracker = new ServiceTracker(bc,
ServiceTracker(bc,
DateService.class.getName(),
DateService.class.getName(), customizer);
customizer);
tracker.open();
tracker.open();
}

public void stop(BundleContext bc) throws Exception {


System.out.println("Parando " +
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + "
...");
tracker.close();
tracker.close();
BestActivator.bc = null;
}
} 89/142

Consumiendo Servicios en OSGi


 Mejora 3  Usando ServiceTracker (MyServiceTrackerCustomizer.java)
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import es.deusto.dateservice.DateService;
public class MyServiceTrackerCustomizer implements ServiceTrackerCustomizer {
private ServiceUserThread thread = null;
private BundleContext bc;
public MyServiceTrackerCustomizer(BundleContext bc) { this.bc = bc; }
public Object addingService(ServiceReference reference) {
DateService service = (DateService) bc.getService(reference);
if (this.thread == null) {
this.thread = new ServiceUserThread(service);
this.thread.start();
return service;
} else return service;
}
public void modifiedService(ServiceReference reference, Object serviceObject)
serviceObject) {
this.thread.stopThread();
try {
this.thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
DateService service = (DateService) bc.getService(reference);
this.thread = new ServiceUserThread(service);
this.thread.start();

public void removedService(ServiceReference reference, Object serviceObject)


serviceObject) {
this.thread.stopThread();
try {
this.thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.thread = null;
}
}
90/142

45
Comentarios Mejoras Activators

 Comparar si la referencia a un servicio no es null resuelve


el problema del NullPointerException
 PROBLEMA: si datebundle no es disponible cuando
datebundleuser es arrancado ya no puede usarlo

 BundleContext permite registrar un ServiceListener


con la framework indicándose un objeto de filtrado adicional
sobre los eventos de servicios (registro, desregistro) de
interés.
 String en formato LDAP especifica filtro:
"(&(" + Constants.OBJECTCLASS +
"=Person)(|(sn=Ipiña)(cn=Diego I*)))“
 Ahora no obtenemos una referencia directamente a DateService
en el método start().
 De manera indirecta con la ayuda del método serviceChanged que
debe implementar el Activator

91/142

Comentarios Mejoras Activators

 La clase de utilidad ServiceTracker automáticamente


monitoriza los ServiceEvents asociados a un servicio
dando al usuario la posibilidad de personalizar qué realizar
cada vez que un servicio aparezca o desaparezca.
 Requiere implementar la interfaz ServiceTrackerCustomizer y
proveer una clase instanciando tal interfaz como parámetro al objeto
ServiceTracker.
 Los métodos addingService, modifiedService y
removedService serán invocados por la clase ServiceTracker,
cada vez que un nuevo servicio sea añadido, modificado o borrado.
 Solventa el problema de la interfaz ServiceListener que sólo es
capaz de darse cuenta de la aparición de nuevos servicios o de la
desaparición de antiguos.
 Truco: generar en start() eventos ServiceEvent.REGISTERED a
partir de una búsqueda Registro Servicios

92/142

46
Resumen Desarrollo de Servicios en OSGi

 5 pasos requeridos por un bundle exportador de


servicios:
1. Implementación del fichero manifest.mf
2. Definición de una interfaz con el servicio a exportar por el
bundle
3. Implementación de tal servicio
4. Implementación de la clase principal del bundle
BundleActivator)
BundleActivator y
(BundleActivator
5. Compilación y despliegue del bundle en el servidor OSGi

 OSGi es un entorno muy dinámico donde aparecen y


desaparecen servicios continuamente, donde la interfaz
ServiceListener y la clase ServiceTracker nos
pueden ofrecer ayuda.

93/142

El Servicio Estándar LogService

 OSGi LogService permite la creación de trazas de depuración o


información durante la ejecución de un bundle
 La interfaz org.osgi.service.log.LogService define su
funcionalidad
 Tipos de logeo: LOG_ERROR, LOG_WARNING, LOG_INFO y LOG_DEBUG
 Método log() para logearlos
 La interfaz org.osgi.service.log.LogReaderService permite
recuperar objetos de tipo org.osgi.service.log.LogEntry del log
registrando un org.osgi.service.log.LogListener
 Normalmente, en la clase Activator crearemos una variable
estática donde guardaremos la referencia a LogService
 Para cambiar el nivel de traceo en Knopflerfish hay que cambiar el
fichero props.xargs modificando sus propiedades:
 Dorg.knopflerfish.log.out a true y
 -Dorg.knopflerfish.log.level a (debug, info, warning o
error)

94/142

47
El Servicio Estándar HttpService

 Puerta de entrada HTTP a la funcionalidad de la


plataforma OSGi
 Definido en la interfaz
org.osgi.service.http.HttpService
 Permite registrar servlets (registerServlet()) y recursos
(registerResources()) en la propia plataforma para que sean
accedidos desde el exterior, para:
 Control remoto
 Interfaces remotas
 Ventaja principal:
 Permite acceder a OSGi mediante peticiones HTTP-GET y POST
y de ahí redireccionar a servicios internos

95/142

Poniendo en Práctica el LogService y el


HttpService

 Objetivo: crear un cliente web del servicio dateservice a través


del servicio estándar de OSGi HttpService
 Pasos para su uso:
 La cabecera Import-Package del manifest.mf debe incluir los
siguientes elementos javax.servlet, javax.servlet.http,
org.osgi.service.http
 La clase Activator en su método start() obtiene una referencia al
servicio HttpService de OSGi y registra en él un servlet
 Implementamos una clase que herede de
javax.servlet.http.HttpServlet

96/142

48
Dateservicewebuser –
Activator.java
import org.osgi.service.http.HttpService
org.osgi.service.http.HttpService;
;
import org.osgi.service.log.LogService;
org.osgi.service.log.LogService;

public class Activator implements BundleActivator {


public static BundleContext bc = null;
public static LogService log = null;
public void start(BundleContext context) throws Exception {
Activator.bc = context;
ServiceReference refLog =
Activator.bc.getServiceReference(LogService.class.getName());
Activator.bc.getServiceReference(LogService.class.getName ());
Activator.log = (LogService
(LogService)
LogService) Activator.bc.getService(refLog);
Activator.bc.getService(refLog);
Activator.log.log(LogService.LOG_INFO,
Activator.log.log(LogService.LOG_INFO, "Empezando " +
Activator.bc.getBundle().
Activator.bc.getBundle().getHeaders
().getHeaders().
getHeaders().get(Constants.BUNDLE_NAME
().get(Constants.BUNDLE_NAME)
get(Constants.BUNDLE_NAME) + "
...");

Activator.bc = context;
//get a reference to the http service
ServiceReference ref =
context.getServiceReference(HttpService.class.getName());
context.getServiceReference(HttpService.class.getName ());
HttpService http = (HttpService
(HttpService)
HttpService) context.getService(ref);
context.getService(ref);
//register
//register the capabilities servlet
http.registerServlet("/
http.registerServlet("/example
("/example",
example", new DateServlet(context),
DateServlet(context),new
),new
Properties(),
Properties(),null
(),null);
null);
}

public void stop(BundleContext context) throws Exception {}


}
97/142

Dateservicewebuser –
DateServlet.java
public class DateServlet extends HttpServlet {
BundleContext context;
public DateServlet(BundleContext context) {
this.context = context;
}
protected void doGet(HttpServletRequest request,
request, HttpServletResponse response) throws
ServletException, IOException {
//strip the service id from the url
String req = request.getRequestURI();
String serviceId = req.substring(req.lastIndexOf('/')+1);
//find a service that matches up
ServiceReference[] refs = null;
try {
refs = context.getServiceReferences(DateService.class.getName(),null);
} catch (InvalidSyntaxException e) {
new IOException().initCause(e);
}
for (int i = 0; i < refs.length; i++) {
DateService service = (DateService) context.getService(refs[i]);
//perform the id match
Activator.log.log(LogService.LOG_INFO, "Comparando con clase " + DateService.class.getName());
if (serviceId.equals(DateService.class.getName())) {
//do it
response.getOutputStream().write(("Usando DateService: formateando fecha: " +
service.getFormattedDate(new Date())).getBytes());
context.ungetService(refs[i]);
return;
}
}
response.getOutputStream().write(("No pudo encontrar servicio con id:"+ serviceId).getBytes());
}
}

98/142

49
Desarrollo de un Servicio Avanzado en OSGi:
BundleDiscoverer

 Tradicionalmente, los entornos OSGi básicos requieren


que el administrador del entorno instale los bundles o
drivers que hablan con los nuevos dispositivos
desplegados o con aquellos que potencialmente vayan a
desplegarse.
 Queremos añadir extensibilidad dinámica a nuestro entorno
mediante un servicio de descubrimiento y despliegue
automático de bundles disponibles en un entorno LAN dentro
de un hogar, oficina o empresa
 Es un bundle que descubre, descarga e instala bundles anunciados
por dispositivos conectados a un canal multicast bien conocido
 Su protocolo sencillo consiste de 5 mensajes:
 BUNDLE_SEARCH
 BUNDLE_RESPONSE uuid ipAddress port
 BUNDLE_ANNOUNCE uuid ipAddress port
 BUNDLE_GET_METADATA uuid
 BUNDLE_GET_JAR uuid

99/142

BundleDiscoverer

100/142

50
BundleDiscoverer

101/142

BundleDiscoverer: Parte Servidora

102/142

51
BundleDiscoverer: Parte Cliente

103/142

Constantes del Protocolo

package es.deusto.bundlediscoverer;

public class BundleDiscoveryConstants {


public final static int DISCOVERY_PORT = 4445;
public final static String DISCOVERY_IP = "230.0.0.1";
public final static int MAX_BLOCK_SIZE = 1024;
public final static int BUNDLE_SEARCH_PERIOD = 5000;
public final static int BUNDLE_HEARTBEAT_PERIOD =
BUNDLE_SEARCH_PERIOD * 4;

public final static String BUNDLE_SEARCH = "BUNDLE_SEARCH";


public final static String BUNDLE_ANNOUNCE = "BUNDLE_ANNOUNCE";
public final static String BUNDLE_RESPONSE = "BUNDLE_RESPONSE";
public final static String BUNDLE_GET_METADATA =
"BUNDLE_GET_METADATA";
public final static String BUNDLE_GET_BUNDLE_JAR =
"BUNDLE_GET_BUNDLE_JAR";
}

104/142

52
Parte Servidora BundleDiscoverer

 El servicio que exporta define un único método que devuelve un listado con los bundles
descubiertos:
package es.deusto.bundlediscoverer;
public interface BundleDiscoverer {
public BundleMetadata[] getAvailableBundles();
}

 Fichero con metadatos del bundle:


package es.deusto.bundlediscoverer;
import java.io.Serializable;
import org.osgi.framework.Bundle;
public class BundleMetadata implements Serializable {
public String uuid;
public String ipAddress;
public int port;
public long timestamp;
public Bundle bundle;
public BundleMetadata(String uuid,
uuid, String ipAddress,
ipAddress, int port,
port, Bundle
bundle)
bundle) {
this.uuid = uuid;
this.ipAddress = ipAddress;
this.port = port;
this.timestamp = System.currentTimeMillis();
this.bundle = bundle;
}
}
105/142

BundleDiscoverImpl

 La clase BundleDiscovererImpl aparte de implementar la interfaz


BundleDiscoverer, también hereda de la clase Thread
 Implementa 2 timers:
 Primero es responsable de enviar regularmente el mensaje BUNDLE_SEARCH a través de
un canal multicast con el objeto de descubrir los servicios provistos por dispositivos en el
entorno controlado
 Segundo comprueba que los proveedores de servicios (dispositivos) antes descubiertos
siguen todavía activos, para en caso contrario proceder a la eliminación de los metadatos
de los servicios descubiertos y desinstalar los bundles que actúan como proxies
controladores de los dispositivos remotos
 Subscripción y recepción de datos en canal multicast:
this.socket = new
MulticastSocket(BundleDiscoveryConstants.DISCOVERY_PORT);
this.addressGroup =
InetAddress.getByName(BundleDiscoveryConstants.DISCOVERY_IP);
this.socket.joinGroup(addressGroup);

byte[] buf = new byte[BundleDiscoveryConstants.MAX_BLOCK_SIZE];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);

106/142

53
BundleDiscovererImpl.run()
public void run() {
this.initPeriodicSearchMessageDelivery();
this.initPeriodicRegistryCleanUp();
while (continueDiscovering) {
try {
String msgReceived = "";
do {
msgReceived = this.receiveMulticastMessage();
} while (msgReceived.startsWith(BundleDiscoveryConstants.BUNDLE_SEARCH));
if ((msgReceived.startsWith(BundleDiscoveryConstants.BUNDLE_ANNOUNCE)) ||
(msgReceived.startsWith(BundleDiscoveryConstants.BUNDLE_RESPONSE))) {
// Process BUNDLE_RESPONSE uuid serviceIP servicePort
StringTokenizer st = new StringTokenizer(msgReceived);
if (st.countTokens() == 4) {
String cmdMsg = st.nextToken();
String uuid = st.nextToken();
String ipAddress = st.nextToken();
String port = st.nextToken();
if (!this.bundlesAvailableMap.containsKey(uuid) ) {
new RetrieveRegisterBundleThread(this,
RetrieveRegisterBundleThread(this, uuid,
uuid, ipAddress,
ipAddress, Integer.parseInt(port)).start();
Integer.parseInt(port)).start();
} else {
synchronized (this.bundlesAvailableMap) {
Bundle oldBundle = this.bundlesAvailableMap.get(uuid).bundle;
int bundleState = oldBundle.getState();
if (bundleState == Bundle.UNINSTALLED) {
this.bundlesAvailableMap.remove(uuid);
} else if (bundleState == Bundle.ACTIVE) {
this.bundlesAvailableMap.get(uuid).timestamp = System.currentTimeMillis();
}
}
}
}
} else {
Activator.log.log(LogService.LOG_DEBUG, "BundleDiscovererImpl.run(): Ignored message: " + msgReceived);
}
} catch (IOException ioe) {
Activator.log.log(LogService.LOG_ERROR, "BundleDiscovererImpl.run(): " + ioe.getMessage());
}
}
}

107/142

org.osgi.framework.Bundle

 Esta clase es el punto de acceso para controlar el ciclo de


vida de un bundle ya instalado en la framework.
 getBundleId() – para obtener el identificador único de un
bundle
 start() para arrancarlo
 stop() para pararlo
 update() para actualizarlo
 uninstall() para desinstalarlo
 getState() para obtener su estado actual (UNINSTALLED,
INSTALLED, RESOLVED, STARTING, STOPPING o ACTIVE) o
 getHeaders() para obtener un Dictionary con las cabeceras
y valores declaradas en el manifiesto del bundle.

108/142

54
Eliminación Selectiva de Bundles

private void initPeriodicRegistryCleanUp()


initPeriodicRegistryCleanUp {
int delay = 0; // delay for 0 sec.
this.bundleGarbageCollectionTimer = new Timer();
this.bundleGarbageCollectionTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
long currentTime = System.currentTimeMillis();
synchronized (bundlesAvailableMap) {
for (BundleMetadata
BundleMetadata service: bundlesAvailableMap.values()
bundlesAvailableMap.values())
() {
if
(service.timestamp+BundleDiscoveryConstants.BUNDLE_HEARTBEAT_PERIOD <
currentTime) {
try {
service.bundle.stop();
service.bundle.stop();
service.bundle.uninstall();
service.bundle.uninstall();
bundlesAvailableMap.remove(service.uuid);
} catch (org.osgi.framework.BundleException be) {
Activator.log.log(LogService.LOG_ERROR,
"BundleDiscovererImpl.initPeriodicRegistryCleanUp(): " + be.getMessage());
}
}
}
}
}
}, delay, BundleDiscoveryConstants.BUNDLE_HEARTBEAT_PERIOD);
}

109/142

Recuperando e Instalando los .jar de los


bundles

ByteArrayOutputStream jarFile = new ByteArrayOutputStream();


do {
bytesRead = in.read(buf, 0, 1024);
jarFile.write(buf, 0, bytesRead);
} while (bytesRead == 1024);
String uploadedBundleDirectoryPath = System.getProperty("user.dir") +
System.getProperty("file.separator") + "uploadedBundles";
String jarFileName = uploadedBundleDirectoryPath +
System.getProperty("file.separator") + this.uuid+".jar";
FileOutputStream fos = new FileOutputStream(new File(jarFileName));
jarFile.writeTo(fos);
fos.close();
jarFile.close();
String bundleUrl = "file:///" + jarFileName;
try {
Bundle bundleInstalado = Activator.bc.installBundle(bundleUrl);
Activator.bc.installBundle(bundleUrl);
bundleInstalado.start();
bundleInstalado.start();
this.parent.updateBundlesAvailable(this.uuid, new
BundleMetadata(this.uuid, this.ipAddress, this.port, bundleInstalado));
} catch (BundleException be) {
Activator.log.log(LogService.LOG_ERROR, "
RetrieveRegisterBundleThread.run(): " + be.getMessage());
}

110/142

55
Servidor de Sockets para Proporcionar .jar en
Cliente

package es.solop.bundlediscoverer.impl.client;
public class UnicastListener extends Thread {
private ServerSocket server;
...
public UnicastListener(BundleDiscovererClient parent) throws IOException {
this.server = new ServerSocket (0);
this.parent = parent;
}
public void run() {
try {
while (continueProcessingRequests) {
Socket socket = server.accept();
BundleDiscoveryHandler handler = new
BundleDiscoveryHandler(socket, this.parent);
handler.start();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
...
}

111/142

Aplicación de Ejemplo Usando


BundleDiscoverer

 La clase WeatherForecastServer exporte dos


bundles que ofrecen el pronóstico del tiempo en un
conjunto de ciudades españolas:
 WeatherForecastBunde – se comunica con la estación
metereológica remota (WeatherForecastServer) para obtener
el pronóstico del tiempo en formato HTML.
 WeatherForecastWebBundle – requiere la previa instalación
de WeatherForecastBundle en el entorno en que se
despliegue y ofrece una interfaz web para seleccionar la ciudad de
la que se quiere obtener el pronóstico del tiempo y así obtenerlo
con la ayuda de WeatherForecastBundle

112/142

56
BundleDiscoverer

113/142

BundleDiscoverer

114/142

57
Patrón de Diseño Whiteboard

 El modelo tradicional de subscribir los consumidores a los


proveedores (patrón observer) requiere demasiadas clases y por
tanto carga en el entorno que lo implementa para gestionar la
notificación de eventos y no se ajusta al entorno dinámico de OSGi
(establece demasiadas dependencias entre productores y
consumidores)
 En el patrón de diseño Whiteboard:
 Cuando un consumidor quiere consumir se registra con el registro
de servicios
 El productor escucha al registro de servicios de manera que cuando
tenga que realizar una notificación contiene la lista actual activa de
consumidores
 Delega la responsabilidad de la gestión de consumidores al Service
Registry
 Se utiliza en la mayoría de servicios, excepto el LogService y el
HttpService que vienen de la versión R1.
 Para más info:
http://www.osgi.org/documents/osgi_technology/whiteboard.pdf

115/142

Declarative Services

 El modelo programático de activación bundles en OSGi se


basa en la publicación, búsqueda y enlazado de servicios
 Problemático cuando el tamaño del sistema empieza a
crecer:
 Tiempo de arranque: cada bundle tiene que registrar de forma
activa sus servicios, requiriendo que todas sus referencias estén
presentes de antemano. En sistemas grandes esto puede
provocar retrasos de inicialización demasiado elevados.
 Tamaño en memoria: Cuando se registra un servicio, éste es
cargado en memoria. Si no se utiliza es un espacio que se está
malgastando, aparte de la sobrecarga que supone tener que crear
el class loader correspondiente.
 Complejidad: en un entorno donde los servicios se consideran
dinámicos (pueden aparecer y desaparecer en cualquier
momento) el modelo de programación en sistemas complejos
puede resultar difícil de mantener.

116/142

58
Declarative Services

 Para resolver esta situación OSGi propone un modelo declarativo, basado en


el concepto de componente:
 Un componente es una clase Java con ciertas características especiales:
 Descripción XML que indica cómo debe gestionarse en OSGi
 Registro de servicios, comprobación de dependencias, registro de eventos se hace por nosotros
 Principales diferencias con el modelo tradicional:
 Se elimina el concepto de BundleActivator, el framework leerá el XML con los
componentes que estén definidos y los creará en función de la política definida:
 Immediate, se crea el componente nada más resolver todas sus dependencias
 Delayed, el servicio es registrado, pero no se crea la instancia hasta que alguien lo solicita
 Factory, se registra una factoría para crear las diferentes instancias.
 Cada componente debe implementar dos métodos, uno de activación
(activate
activate()
activate())() y otro de desactivación (deactivate
deactivate()
deactivate()),() que se invocarán
durante su ciclo de vida.
 Las referencias a otros servicios se declaran en el XML con ciertas propiedades (si
son obligatorias, opcionales o la cardinalidad permitida) y es el framework el que
se asegura de que estén correctamente enlazadas antes de activar el
componente.
 La gestión de las referencias a servicios que desaparecen mientras el componente está
activo también se pueden gestionar automáticamente sin necesidad de registrarse al
framework para escuchar los eventos.
 Excelente alternativa para el desarrollo de componentes complejos en OSGi,
muchas de las tareas a realizar se automatizan en el XML

117/142

Formato bundle.manifest en un Bundle


definido con el Declarative Services

Service-
Service-Component:
Component: OSGI-
OSGI-
INF/es.deusto.tecnologico.osgi.declarative.impl.Display.xml
INF/es.deusto.tecnologico.osgi.declarative.impl.Display.xml
Private-Package: es.deusto.tecnologico.osgi.declarative.impl
Bundle-Version: 1.0.0
Bundle-Name: declarative_example
Bundle-ManifestVersion: 2
Bundle-SymbolicName: declarative_example
Import-
Import-Package:
Package: org.osgi.service.component,
org.osgi.service.component,
org.osgi.service.log

118/142

59
Fichero XML de definición de un bundle

<?xml version='1.0' encoding='utf-8'?>


<component
name='
name='es.deusto.tecnologico.osgi.declarative.impl.Display
='es.deusto.tecnologico.osgi.declarative.impl.Display'>
es.deusto.tecnologico.osgi.declarative.impl.Display'>
<implementation
implementation
class='es.deusto.tecnologico.osgi.declarative.impl.Display'
class
/>
<reference
reference name='log'
interface='org.osgi.service.log.LogService'
interface bind='setLog'
bind
unbind='unsetLog'/>
unbind
</component
</component>
component>

119/142

Implementación del Bundle


import org.osgi.service.component.ComponentContext;
...
public class Display extends Thread {
LogService log;
private boolean quit = false;
protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component activated");
this.start();
}
protected void deactivate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component deactivated");
quit = true;
}
public synchronized void run() {
while (!quit)
try {
Date now = new Date();
log.log(LogService.LOG_INFO, now.toString());
wait(5000);
} catch (InterruptedException ie) { /*will recheck quit*/ }
}
public void setLog(LogService log) {
this.log = log;
log.log(LogService.LOG_INFO, "LogService bounded to Display");
}
public void unsetLog(LogService log) {
log.log(LogService.LOG_INFO, "LogService unbounded to Display");
this.log = null;
}
}
120/142

60
Event Admin Service
 Canal de eventos con opciones de filtrado y clasificado de eventos
sencillo y homogéneo dentro de la plataforma OSGi, ofreciendo un
mecanismo de comunicación entre bundles basado en paradigma
publish/subscribe
 Los elementos que intervienen en el esquema del Event Admin son:
 Event situación que un bundle quiere notificar, compuesto de:
Event):
Evento (Event
 Un tipo se utilizada para categorizar los eventos, su nombre es un espacio de nombres
jerárquico que se utiliza como un primer mecanismo de filtrado para saber cómo
despacharlos a los diferentes consumidores.
 Sintáxis: fully/qualified/package/ClassName/ACTION
 Un conjunto de propiedades, o pares atributo valor que proporcionan más información
sobre el evento. El atributo debe ser de tipo String, pero el valor puede ser cualquier
objeto Java primitivo o String.
 Handler interfaz bajo el cual debe registrarse un servicio que quiera
Event Handler,
escuchar eventos del EventAdmin. Se configura con dos propiedades:
 topic-scope: eventos a los que se suscribe
 event-filter: filtro en sintaxis LDAP que hay que aplicar
 Ejemplo: “Recibir evento LOG_WARNING de cualquier bundle cuyo nombre simbólico
empieza por com.acne”
 topic-scope  org/osgi/service/log/LogEntry/LOG_WARNING
 event-filter  (bundle.symbolicName=com.acme.*)
 Event Publisher – publicadores de eventos que no tienen ninguna
característica especial. Simplemente necesitan una referencia al servicio
EventAdmin donde publicar eventos.
 EventAdmin – servicio que implementa el canal de eventos, ofreciendo dos tipos
de envío: síncrono y asíncrono
121/142

bundle.manifest de bundle utilizando


servicio EventAdmin

Manifest-Version: 1.0
Bundle-Version: 1.0.0
Bundle-Name: event_admin_example
Bundle-ManifestVersion: 2
Bundle-SymbolicName: event_admin_example
Import-
Import-Package:
Package: org.osgi.service.component,
org.osgi.service.component,
org.osgi.service.event,
org.osgi.service.event, org.osgi.service.log
Service-Component: OSGI-INF/Display.xml,OSGI-
INF/Clock.xml

122/142

61
Ficheros de configuración de los componentes
productor y consumidor de eventos
 Productor: Clock.xml
<?xml version='1.0' encoding='utf-8'?>
<component name='es.deusto.tecnologico.osgi.eventadmin.impl.Clock'>
<implementation class='es.deusto.tecnologico.osgi.eventadmin.impl.Clock'/>
<reference name='log' interface='org.osgi.service.log.LogService'
bind='setLog' unbind='unsetLog'/>
<reference name='
name='eventAdmin
='eventAdmin'
eventAdmin' interface='
interface='org.osgi.service.event.EventAdmin
='org.osgi.service.event.EventAdmin'
org.osgi.service.event.EventAdmin'
bind='
bind='setEventAdmin
='setEventAdmin'
setEventAdmin' unbind='
unbind='unsetEventAdmin
='unsetEventAdmin'/>
unsetEventAdmin'/>
</component>

 Consumidor: Display.xml
<?xml version="1.0" encoding="utf-8"?>
<component name="es.deusto.tecnologico.osgi.eventadmin.impl.Display"
immediate="
immediate="true
="true"
true">
<implementation
class="es.deusto.tecnologico.osgi.eventadmin.impl.Display"/>
<property
name="
name="event.topics
="event.topics">es/
event.topics">es/deusto
">es/deusto/
deusto/tecnologico/
tecnologico/osgi/
osgi/eventadmin/
eventadmin/Clock/
Clock/NEW_DATE</
NEW_DATE</p
</p
roperty>
roperty>
<service>
service>
<provide interface="
interface="org.osgi.service.event.EventHandler
="org.osgi.service.event.EventHandler"
org.osgi.service.event.EventHandler" />
<provide interface="
interface="es.deusto.tecnologico.osgi.eventadmin.IDisplay
="es.deusto.tecnologico.osgi.eventadmin.IDisplay"
es.deusto.tecnologico.osgi.eventadmin.IDisplay" />
</service
</service>
service>
<reference name="log" interface="org.osgi.service.log.LogService"
bind="setLog" unbind="unsetLog"/>
</component>

123/142

Productor de Eventos: Clock


import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
public class Clock extends Thread {
LogService log = null;
EventAdmin eventAdmin = null;
boolean quit = false;
protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Clock component activated");
this.start();
}
protected void deactivate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Clock component deactivated");
quit = true;
}
public synchronized void run() {
while (!quit) {
try {
Date now = new Date();
String topic = "es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE
"es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE";
es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE";
Hashtable properties = new Hashtable();
Hashtable();
properties.put("currentTime",
properties.put("currentTime", now.toString()
now.toString() );
Event newEvent = new Event(topic,properties);
Event(topic,properties);
eventAdmin.sendEvent(newEvent);
eventAdmin.sendEvent(newEvent); // send it synchronously
wait(3000);
} catch (InterruptedException ie) {}
}
}

124/142

62
Productor de Eventos: Clock

public void setLog(LogService log) {


this.log = log;
log.log(LogService.LOG_INFO, "LogService bounded to Display");
}
public void unsetLog(LogService log) {
log.log(LogService.LOG_INFO, "LogService unbounded to Display");
this.log = null;
}
public void setEventAdmin(EventAdmin eventAdmin)
eventAdmin) {
this.eventAdmin = eventAdmin;
}
public void unsetEventAdmin(EventAdmin eventAdmin)
eventAdmin) {
this.eventAdmin = null;
}
}

125/142

Consumidor de Eventos: IDisplay

package es.deusto.tecnologico.osgi.eventadmin;

public interface IDisplay {


public String getLastMessage();
getLastMessage();
}

126/142

63
Consumidor de Eventos: Display
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
...
public class Display implements IDisplay,
IDisplay, EventHandler {
LogService log;
private String message;
final static String [] topics = new String[]
{"es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE" };
protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component activated");
}
protected void deactivate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component deactivated");
}
public void setLog(LogService log) {
this.log = log;
log.log(LogService.LOG_INFO, "LogService bounded to Display");
}
public void unsetLog(LogService log) {
log.log(LogService.LOG_INFO, "LogService unbounded to Display");
this.log = null;
}
public synchronized void handleEvent(Event newEvent)
newEvent) {
message = (String)newEvent.getProperty("currentTime");
}
public String getLastMessage() {
return message;
}
}
127/142

Configuration Admin

 Facilita las labores de configuración de las propiedades de los


diferentes bundles del sistema
 Consiste de un conjunto de interfaces que los servicios han de
implementar para ser avisados cuando sus configuraciones cambian
 Dos alternativas:
 ManagedService – para servicios con un único conjunto de
propiedades
 ManagedServiceFactory – para cuando se generan varias instancias
de un servicio y cada una necesitas sus propiedades
 El índice a las propiedades de un servicio es su PID
 Cuando un bundle necesita información de configuración debe
registrar uno o más objetos ManagedService
 El ConfigurationAdmin es capaz de enviar eventos cuando la
configuración cambia (CM_UPDATED) o es eliminada (CM_DELETED)
 Hay que registrarse previamente bajo el interfaz
ConfigurationListener
 En la cabecera Import-Package hay que usar
org.osgi.framework, org.osgi.service.cm

128/142

64
Obteniendo, creando o actualizando un
objeto de Configuración
//Search the reference to the ConfigurationAdmin
ServiceReference configAdminReference =
context.getServiceReference(ConfigurationAdmin.class.getName());
context.getServiceReference(ConfigurationAdmin.class.getName());
ConfigurationAdmin configAdmin =
(ConfigurationAdmin)context.getService(configAdminReference);
ConfigurationAdmin)context.getService(configAdminReference);
if (configAdmin == null) System.out.println("Configuration Admin Service not
found.");

//Create configuration for bundle configuration_admin_example


//This returns a new Configuration object.
//This new object is bound to the location and the properties set to null.
//If the location parameter is null, it will be set when a Managed Service
// with the corresponding PID is registered for the first time.
Configuration config =
configAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfiguration
configAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfiguration
", null );

//As this is the first time the properties must be created first
Hashtable properties = new Hashtable();
Hashtable();
properties.put("port",
properties.put("port", new Integer(6023));
properties.put("motto",
properties.put("motto", "Message set with the configuration admin");

//Update the properties


config.update(properties);
config.update(properties);

129/142

Usando un Objeto de Configuración


package es.deusto.tecnologico.osgi.configurationadmin;
public class GetConfiguration implements ManagedService {

public synchronized void init(BundleContext context) {
//Set default properties, SERVICE_PID is mandatory
properties = new Hashtable();
properties.put(Constants.SERVICE_PID , "es.deusto.tecnologico.osgi.GetConfiguration");
properties.put("port", new Integer(6123));
properties.put("motto", "First message of the day");
//Register the service as a ManagedService interface
registration = context.registerService(ManagedService.class.getName(), this, properties);
}
public synchronized void updated(Dictionary properties) throws ConfigurationException {
if (properties != null) {
try {
message = (String) properties.get("motto");
port = Integer.parseInt((String) properties.get("port"));
//It is advisable but not mandatory to update the properties of the service
registration.setProperties(properties);
} catch (Exception e) {// Ignore, use defaults}
}
if (motd != null) motd.kill(); //Restart the Motto of the Day server with the new configuration
motd = new MottoOfTheDay();
motd.setPort(port == 0 ? port = 6123 : port);
motd.setMotto(message == null ? "No motto" : message);
motd.start();
}
}
}

130/142

65
Wire Admin Service

 Objetivo: productor y el consumidor de datos o eventos conozcan lo mínimo


posible el uno del otro para que los cambios en cada uno no perjudiquen al otro.
 En los entornos orientados a servicios existen varias alternativas a la hora de
enlazar unos servicios con otros:
 Permitir al consumidor que elija al productor, siguiendo el tradicional patrón Observer
 Productor localiza a sus consumidores mediante el llamado patrón whiteboard
 Wire Admin Service – desligar completamente el productor y el consumidor
 Modelo de funcionamiento: productores (interfaz Producer) y consumidores
(interfaz Consumer) se asocian mediante la creación de objetos Wire
 Un Wire asocia a dos servicios identificados por su PID
 Son gestionados por el WireAdmin que notifica a producers y consumers cuando los enlaces
son activados
 Cuando un Producer tenga datos que notificar, actualizará el correspondiente Wire
 Se permite la definición de filtros
 Los datos que se envían entre el Consumer y el Producer deben ser compatibles: concepto
de flavors
 Soporta el mecanismo Push y el Pull
 Proporciona un conjunto de eventos para gestionar el ciclo de vida de los Wires
 La cabecera Import-Package: org.osgi.framework,
org.osgi.service.wireadmin

131/142

Definiendo un Consumidor

import org.osgi.service.wireadmin.Consumer;

public class Tv implements Consumer {
Wire[] producers;
public Tv (BundleContext context) {
Hashtable ht = new Hashtable();
ht.put( Constants.SERVICE_PID, "es.deusto.Tv" );
ht.put( WireConstants.WIREADMIN_CONSUMER_FLAVORS, new Class[] { String.class,
Date.class } );
context.registerService( Consumer.class.getName(), this, ht );
}
public void producersConnected(Wire[] producers) {
this.producers = producers;
}
public void updated(Wire arg0, Object in) {
if ( in instanceof Date ) {
System.out.println("[Tv] - New time shown as Date: " + in.toString());
} else if ( in instanceof String ) {
System.out.println("[Tv] - New time shown as String: " + in);
} else {
System.out.println("[Tv] Error: object type not supported.");
}
}

}

132/142

66
Definiendo un Productor
import org.osgi.service.wireadmin.Producer;
org.osgi.service.wireadmin.Producer;

public class Clock extends Thread implements Producer {
Wire wires[];
BundleContext context;
boolean quit = false;
Clock(BundleContext context) {
this.context = context;
registerProducer();
}
private void registerProducer() {
Hashtable p = new Hashtable();
Hashtable();
p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS
p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS,
R_FLAVORS, new
Class[] { Date.class,
Date.class, String.class });
p.put(org.osgi.framework.Constants.SERVICE_PID,
p.put(org.osgi.framework.Constants.SERVICE_PID, "es.deusto.Clock
"es.deusto.Clock");
es.deusto.Clock");
context.registerService(Producer.class.getName(),
context.registerService(Producer.class.getName(), this, p);
}
public synchronized void run() {
while (!quit)
try {
Date now = new Date();
for (int i = 0; wires != null && i < wires.length; i++) {

wires[i].update(now);
wires[i].update(now);
wires[i].update(now.toString());
wires[i].update(now.toString());
}
wait(3000);
} catch (InterruptedException ie) {}
}

133/142

Definiendo un Productor

public synchronized void consumersConnected(Wire[]


consumersConnected(Wire[] wires) {
this.wires = wires;
}
public synchronized Object polled(Wire wire) {
Class clazzes[] = wire.getFlavors();
for ( int i=0; i<clazzes.length; i++ ) {
Class clazz = clazzes[i];
if ( clazz.isAssignableFrom( Date.class ) )
return new Date();
else if (clazz.isAssignableFrom(String.class))
return new Date().toString();
}
return null;
}
}

134/142

67
Artículos de Investigación Usando OSGi

 Challenges in building service-oriented applications for OSGi,


 Hall, R.S. Cervantes, H. Lab. LSR IMAG, Domaine Univ., Grenoble, France, IEEE
Communications Magazine, May 2004
 Device and service discovery in home networks with OSGi,
 Dobrev, P. Famolari, D. Kurzke, C. Miller, B.A; IEEE Communications
Magazine, Aug 2002
 Enabling smart spaces with OSGi,
 Choonhwa Lee Nordstedt, D. Helal, S. University of Florida, Jul-Sept 2003
 The Gator Tech Smart House: a programmable pervasive space
 Helal, S. Mann, W. El-Zabadani, H. King, J. Kaddoura, Y. Jansen, E. Dept.
of Comput. & Inf. Sci. & Eng., Florida Univ., FL, USA, IEEE Computer, March 2005
 Toward an OSGi-based infrastructure for context-aware applications
 Gu, T. Pung, H.K. Zhang, D.Q. Sch. of Comput., Nat. Univ. of Singapore,
Singapore, Pervasive Computing, IEEE, Oct-Dec 2004
 Research and implementation of the context-aware middleware for controlling
home appliances,
 Jonghwa Choi Dongkyoo Shin Dongil Shin, Dept. of Comput. Sci. & Eng.,
Sejong Univ., Seoul, South Korea;IEEE Transactions on Consumer Electronics,
Feb 2005

135/142

Características Avanzadas de OSGi

 Integración con Servicios Web


 The Knopflerfish Axis port
 Provee acceso SOAP/Web service a cualquier bundle OSGi bien sea para
exportar un servicio OSGi como Servicio Web o para importar los servicios
web en una framework OSGi
 https://www.knopflerfish.org/svn/knopflerfish.org/trunk/osgi/bundles_opt/s
oap/axis.html
 Service Binder
 Simplifica el desarrollo de bundles OSGi automatizando la gestión de
dependencias de servicios.
 Elimina la lógica de gestión de dependencias de servicios de los bundles
 http://gravity.sourceforge.net/servicebinder/
 Bnd plugin de aqute que genera el manifest.mf por ti
 Wire Admin Service
 Permite enlazar dinámicamente servicios que producen datos con
servicios que los consumen.
 ¿Podríamos enlazar los servicios automáticamente si tuviéramos
descripciones de servicios mejoradas con semántica?  tema de
investigación

136/142

68
R-OSGi

 R--OSGi permite el descubrimiento e invocación de servicios


provistos en otras implementaciones OSGi
 Utiliza SLP para el descubrimiento de servicios
 Los proveedores de servicios tienen que registrar un servicio para
acceso remoto.
 Los consumidores en otras instancias de OSGi lo pueden descubrir
con la infraestructura R-OSGi y recuperar el servicio (sus propiedades
y su interfaz)
 La framework cliente construirá un proxy bundle sobre la marcha y lo
registrará en la framework local
 Los servicios locales podrán ahora acceder el servciio remoto de manera
transparente
 Desde la versión 0.5 es posible transferir el bundle completo al cliente
 Url: http://r-osgi.sourceforge.net/

137/142

Conclusion

 La plataforma OSGi es algo así como un sistema operativo Java para


componentes desplegados a través de la red, ofreciendo:
 Modelo de ejecución y programación orientada a servicios simple
 Despliegue dinámico
 Capa de módulos
 Capa de servicios
 Seguridad integral
 Su misión es simplificar y hacer más eficiente incluso para entornos
empotrados:
 Problemas de despliegue
 La composición de servicios
 La gestión vitalicia de los componentes
 Implementado por varios fabricantes y comunidades open source,
gran apoyo de la industria

138/142

69
References

 OSGi Tutorials
 OSGi Tutorial -- A Step by Step Introduction to OSGi Programming
Based on the Open Source Knopflerfish OSGi Framework
 http://www.knopflerfish.org/tutorials/osgi_tutorial.pdf
 Develop OSGi bundles
 http://www.knopflerfish.org/programming.html
 OSGi Service tutorial
 http://www.knopflerfish.org/osgi_service_tutorial.html
 OSGi and Gravity Service Binder Tutorial
 http://oscar-osgi.sourceforge.net/tutorial/
 Bundle Repository
 http://www.knopflerfish.org/repo/index.html

139/142

Apéndices

70
OSGi vs. UPnP

 There is no "versus" here. OSGi is fully complimentary to


UPnP. No overlap.
 UPnP = set of protocols to discover and communicate with
networked devices
 UPnP Implementations could use OSGi as execution environment like
they could use Windows, Linux or QNX operating systems
 OSGi = environment for Java programs to execute in a
well defined and managed environment
 OSGi implementations could use UPnP (or Jini, or SLP, or
Salutation) to discover and use networked devices

141/142

OSGi & UPnP: Comparison

 OSGi  UPnP
 Java  XML DTD
 Executing code  Communications
 Behaviour (Code)  Declarative
 Program-Program oriented  User oriented
 Standardizing Java interfaces  Standardizing XML templates
 Service is local and fast  Service is remote and slow to
execute

142/142

71

You might also like