apéndice a: osgi: open services gateway...
TRANSCRIPT
1
Apéndice A: OSGi: Open Services Gateway Interface
Dr. Diego Lz. de Ipiña Gz. de Artazahttp://paginaspesonales.deusto.es/dipina
http://www.morelab.deusto.eshttp://[email protected]
Contenido
1. Introducción (30’)a. ¿Qué proporciona?b. ¿Dónde se aplica?c. Especificaciones y Herramientas OSGi 2.
2. Arquitectura OSGi (30’)a. JVM, modularidad, gestión de ciclo de vida, seguridadb. Registro de Serviciosc. Concepto de Bundled. Servicios Estándar OSGi
3. Programando OSGi con Knopplerfish (75’) + Descanso (15’)a. Instalación y configuración de plug-in para Eclipseb. Usando Ant para compilar código OSGic. Desarrollando un primer bundled. Fichero de manifestoe. Creación de la clase Activatorf. Compilando e instalando un bundleg. Creando interfaces de servicioh. Usando el registro de serviciosi. Usando los servicios avanzados de servicios: ServiceListener y ServiceTracker
2/140
2
Contenido
4. Servicios Avanzados en OSGi (45’)a. Log Serviceb. Http Servicec. Declarative Serviced. Configuration Servicee. Event Admin Servicef. Wire Admin Serviceg. R-OSGi
5. Desarrollo de un ejemplo complejo en OSGi (60’)a. Diseño de un Servicio de Descubrimiento de Servicios distribuidosb. Usando el LogServicec. Implementando el servicio, bundle y activatord. Creación de Servicios Distribuidos descubribles mediante el Distributed Bundle
Discoverere. Aplicación Bundle ilustrando Declarative, Configuration, Event Admin y Wire
Admin services
6. Conclusión y preguntas (15’)
3/140
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/140
3
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/140
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/140
4
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/140
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/140
5
¿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/140
Complejidad del Software
Structured Programming
Pro
duct
ivity
Complexity and Size
Assembly
Service Oriented Programming
10/140
6
¿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/140
Ejemplo de Despliegue OSGi en el Hogar (1)
Home Office
HomeControl
DifferentNetworks
Security
ServicesProvider
Firewall
Aggregation & Management Platform
Subscriber, Service andDevice Management
Notification Server
FamilyPortal
Secure Tunnel
Entertainment/Gaming
InternetServices
Webpad
Internet
AccessGateway
ServiceOffering
Accessfrom any Web Terminal
e.g. access from office or via PDA/WAP phone
OSGi Service Gateway
12/140
7
Ejemplo de Despliegue OSGi en el Hogar (2)
13/140
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/140
8
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/140
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/140
9
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/140
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
IOCPU
OS
Java VM
18/140
10
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/140
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/140
11
Cooperación entre Aplicaciones (2)
� Arquitectura Orientada a Servicios (SOA):
� Separa el contrato de la implementación
� Permite implementaciones alternativas
� Descubre y asocia dinámicamente las aplicaciones
� 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
Service Contract
Componentprovides
uses
21/140
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/140
12
Arquitectura OSGi (1)
� OSGi proporciona un entorno de computación para bundles que se ejecutan conjuntamente en una JVM.
23/140
Arquitectura OSGi (2)
24/140
13
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ónentre aplicaciones
� Provee gestión del ciclo de vida (instalar, empezar, parar, actualizar)
� Libre de políticas� Éstas son impuestas por los bundles
25/140
Capas de la Framework OSGi (1)
Module
Life Cycle
Services
Sec
urity
Execution Environment
App
licat
ions
26/140
14
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/140
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
J2SE
CDC/FP
OSGiMin.
28/140
15
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/140
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/140
16
Capas de la Framework OSGi: Modularidad (3)
31/140
Capas de la Framework OSGi: Ciclo de Vida (1)
� El bundle del sistema representa a la framework OSGi.� Ofrece una API para gestionar bundles:
� Instalarlos� Resolverlos� Arrancar� Parar� Refrescar� Actualizar� Desinstalar Bundle
XBundle
X-v2
BundleB
BundleM
BundleA
Systembundle
State (active or not)
Manages
32/140
17
Capas de la Framework OSGi: Ciclo de Vida (2)
� Un bundle es iniciado por la clase BundleActivatorBundleActivatorBundleActivatorBundleActivator
� Una cabecera en el fichero JAR que define un bundle hace referencia a esta clase
� La interfaz BundleActivatortiene dos métodos:� Start()Start()Start()Start(): inicializa y retorna
inmediatamente� Stop()Stop()Stop()Stop(): limpia el bundle
� El BundleActivator recibe un BundleContextBundleContextBundleContextBundleContext que provee acceso a las funciones de la framework OSGi
� La Framework provee el servicio Start Level que controla el inicio/parada de grupos de aplicaciones
INSTALLED
RESOLVED
UNINSTALLED
ACTIVE
STOPPING
STARTING
start
stop
33/140
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/140
18
Capas de la Framework OSGi: Servicios(2)
35/140
36363636/142/142/142/142
Capas de la Framework OSGi: Seguridad
� Basado en Seguridad de Java 2� Permisos� Firma de bundles
36/140
19
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/140
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 Bundle Repository: http://oscar-osgi.sourceforge.net/
38/140
20
Bundles: Contenido interno
� Un bundle es un fichero JAR que contiene:� El fichero manifest.mfmanifest.mfmanifest.mfmanifest.mf con los metadatos del bundle:
� 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 BundleActivatorBundleActivatorBundleActivatorBundleActivator 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
Bundle A
{…}
39/140
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/140
21
Modelo de Colaboración en OSGi: Servicios
OSGi Framework
Bundle A
{…}
= service, defined by
java interface
Bundle B
{…}
Bundle C
{…}
= bundle
41/140
Modelo de Colaboración en OSGi: Dependencias
� La especificacion OSGi soporta la declaración de dependencias mediante las cabeceras: RequireRequireRequireRequire----BundleBundleBundleBundle e ImportImportImportImport----PackagePackagePackagePackage
� Require-Bundle crea una dependencia en un bundle completo� Muy fácil de usar� Importa paquetes que no son utilizados
� Import-Package crea una dependencia en un único paquete� Los bundles solamente importan lo que
necesitan
� Se recomienda usar Import-Package porque facilita el despliegue y la gestión de versiones
r
r
s
r
q
p
Require-Bundle
Import-Package
42/140
22
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á formado por:� Interfaz de Servicio, una clase o interfaz Java� Propiedades del servicio, pares nombre-valor
� Los servicios se implementan como objetos dentro del bundle
43/140
Modelo de Colaboración en OSGi: Servicios
44/140
23
Modelo de Colaboración en OSGi: Servicios
45/140
Modelo de Colaboración en OSGi: Servicios
JAVA
Operating System
Hardware
Java Application Manager
Serviceregistry
packagespackages
Midlet,Xlet,
orApplet
Midlet,Xlet,or
Applet
No native code
No package management(versions!)
No collaboration
No management bundles
46/140
24
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 BundleActivatorBundleActivatorBundleActivatorBundleActivator
con los métodos: a) start(BundleContext)start(BundleContext)start(BundleContext)start(BundleContext) y b) stop(BundleContext)stop(BundleContext)stop(BundleContext)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/140
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/140
25
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 componentes pequeños y desacoplados que pueden adaptarse al entorno cambiante en tiempo real� Estos componentes pueden ser combinados para crear
aplicaciones complejas
49/140
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 ServiceListenerServiceListenerServiceListenerServiceListener y la clase ServiceTrackerServiceTrackerServiceTrackerServiceTrackerpermiten recibir notificaciones de eventos de ciclo de vida de servicios de interés
� La interfaz BundleContextBundleContextBundleContextBundleContext 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/140
26
Detalles sobre Servicios
� Un servicio es un objeto registrado con el Framework por un bundle para su uso por otros bundles
� La semántica de un servicio es dada por su interfaz Java
� Un bundle puede registrar uno o varios servicios
� Un bundle puede usar un servicio (bind) con cierta cardinalidad� 1..1, 0..1, 0..n
� Un servicio puede ser descubierto dinámicamente� Búsqueda activa con filtro de
consulta� Interfaz listener
� ¡Los servicios pueden acabar en cualquier momento! ¡Todo es muy dinámico!
service
bind register
listen
package org.osgi.service.log;
import org.osgi.framework.ServiceReference;
public interface LogService {
static final intLOG_ERROR= 1;
static final intLOG_WARNING= 2;
static final intLOG_INFO= 3;
static final intLOG_DEBUG= 4;
void log(int level, String message);
void log(int level, String message,
Throwable exception);
void log(ServiceReference sr,int level,
String message);
void log(ServiceReference sr, int level,
String message, Throwable exception);
}
51/140
Manipulación de Servicios
� La interfaz BundleContextBundleContextBundleContextBundleContextfacilita los métodos para manipular el registro de servicios
� Los registros de servicio son gestionados por objetos de tipo ServiceRegistrationServiceRegistrationServiceRegistrationServiceRegistration
� Pueden utilizarse para desregistrar un servicio o modificar sus propiedades
� Los objetos ServiceReferenceServiceReferenceServiceReferenceServiceReferencedan acceso al servicio así como a sus propiedades
� El acceso a un servicio es mediante el método getServicegetServicegetServicegetService
� Los servicios se devuelven con el método ungetServiceungetServiceungetServiceungetService.
ServiceRegistration registerService(
String clss,
Object srvc,
Dictionary prprts)
ServiceReference[]
getServiceReferences(
String clss,
String fltr)
Object getService(
ServiceReference reference)
boolean ungetService(
ServiceReference rfrnc);
52/140
27
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/140
Servicios Estándar en OSGi (1)
� Servicios del Framework:
� Permission Admin: los permisos de bundles actuales o futuros pueden ser manipulados a través de este servicio
� Conditional Permission Admin: extiende el Permission Admincon 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/140
28
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/140
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/140
29
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/140
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/140
30
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.3.jar (8,6 MB)� Framework completa, incluyendo código fuente, documentación,
ejecutable autoextraíble:� http://www.knopflerfish.org/download.html#2.0.3
� 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/140
Knoplerfish OSGi Desktop
60/140
31
Instalación Plug-in Eclipse OSGi
� Download Eclipse Europa de: http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/20071103/eclipse-java-europa-fall2-win32.zip
� Pasos necesarios para su instalación:1. Seleccionar la opción de menú en Eclipse Help�Software
Updates�Find 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ú Window�Preferences 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/140
Configuración de un Proyecto Knopflerfish en Eclipse
1. Seleccionar la opción de menú File�New�Project...
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: OSGi�Knopflerfish.
� Documentación adicional en: http://www.knopflerfish.org/eclipse_plugin.html
62/140
32
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\build_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. � Prerrequisitos:
� Instalar ant y modificar variable PATH a directorio %ANT_HOME%\bin
63/140
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_HOMEOSGI_HOMEOSGI_HOMEOSGI_HOME
para que apunte al directorio de instalación de Knopflerfish, por ejemplo: C:\%INTALL_OSGI_DIR%\knopflerfish.org\osgi
64/140
33
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"><target name="compile"><target name="compile"><target name="compile">
<javac destdir = "./classes" debug = "on"><javac destdir = "./classes" debug = "on"><javac destdir = "./classes" debug = "on"><javac destdir = "./classes" debug = "on"><src path= "./src"/><classpath refid="lib.class.path"/><src path= "./src"/><classpath refid="lib.class.path"/><src path= "./src"/><classpath refid="lib.class.path"/><src path= "./src"/><classpath refid="lib.class.path"/>
</javac></javac></javac></javac></target></target></target></target>
65/140
Nuestro Propio Fichero Ant
<target name="jar"><target name="jar"><target name="jar"><target name="jar"><jar basedir = "./classes"
jarfile = "./build/${app.name}.jar"compress = "true" includes = "**/*"manifest = "./meta-inf/MANIFEST.MF"/>
</target><target name="clean"><target name="clean"><target name="clean"><target name="clean">
<delete dir = "./classes"/><delete dir = "./build"/></target><target name="deploy" depends="jar"><target name="deploy" depends="jar"><target name="deploy" depends="jar"><target name="deploy" depends="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/140
34
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.
� Repetiremos el mismo proceso desde Eclipse
67/140
Pasos en detalle para crear nuestro primer bundle
1. Creación de un directorio para el bundle1. 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.mfManifest-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
BundleBundleBundleBundle----Activator: es.deusto.simplebundle.impl.ActivatorActivator: es.deusto.simplebundle.impl.ActivatorActivator: es.deusto.simplebundle.impl.ActivatorActivator: es.deusto.simplebundle.impl.Activator
Bundle-Category: example
ImportImportImportImport----Package: org.osgi.frameworkPackage: org.osgi.frameworkPackage: org.osgi.frameworkPackage: org.osgi.framework
68/140
35
Pasos en detalle para crear nuestro primer bundle
� manifestmanifestmanifestmanifest....mfmfmfmf
� 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 la sección 3.2.1 Bundle Manifest Headers
(página 36) de la Especificación de OSGi
� Propiedad BundleBundleBundleBundle----ActivatorActivatorActivatorActivator indica a la framework qué clase es laActivatorActivatorActivatorActivator � clase principal a invocar por la framework cuando cargueel bundle
� ImportImportImportImport----PackagePackagePackagePackage indica al framework que nuestro bundle requiereacceso a todas las clases en el paquete org.osgi.framework
69/140
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 implementsActivator implementsActivator implementsActivator implements BundleActivatorBundleActivatorBundleActivatorBundleActivator {
public static BundleContext bc = null;private HelloWorldThread thread = null;
public void start(BundleContext bc) throws Exceptionpublic void start(BundleContext bc) throws Exceptionpublic void start(BundleContext bc) throws Exceptionpublic void start(BundleContext bc) throws Exception {System.out.println("SimpleBundle starting...");Activator.bc = bc;this.thread = new HelloWorldThreadHelloWorldThreadHelloWorldThreadHelloWorldThread();this.thread.start();
}public void stop(BundleContext bc) throws Exceptionpublic void stop(BundleContext bc) throws Exceptionpublic void stop(BundleContext bc) throws Exceptionpublic void stop(BundleContext bc) throws Exception {
System.out.println("SimpleBundle stopping...");this.thread.stopThread();this.thread.join(); Activator.bc = null;
}}
70/140
36
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.BundleActivatororg.osgi.framework.BundleActivatororg.osgi.framework.BundleActivatororg.osgi.framework.BundleActivator
� Los métodos start() y stop() permiten gestionar el ciclo de vida de un bundle
� La clase BundleContextBundleContextBundleContextBundleContext permite a un bundle interactuar con la framework OSGi:� Subscribirse a eventos publicados por el framework (addXXXListeneraddXXXListeneraddXXXListeneraddXXXListener)� Registrar servicios con el Registro de Servicios de la framework OSGi
(registerServiceregisterServiceregisterServiceregisterService)� Recuperar ServiceReferences del Registro de Servicios
(getServiceReferencesgetServiceReferencesgetServiceReferencesgetServiceReferences)� Obtener y liberar objetos de servicios (getServicegetServicegetServicegetService y ungetServiceungetServiceungetServiceungetService)� Instalar nuevos bundles (installBundleinstallBundleinstallBundleinstallBundle)� Obtener la lista de bundles disponibles (getBundles()getBundles()getBundles()getBundles())� Obtener el objeto Bundle asociado a una implementación de un bundle
(getBundlegetBundlegetBundlegetBundle)� Crear ficheros permanentes para el uso del bundle (getDataFilegetDataFilegetDataFilegetDataFile)
71/140
Pasos en detalle para crear nuestro primer bundle
4. Create simplebundle/src/es/deusto/simplebundle/impl/HelloWorldThread.java
package es.deusto.simplebundle.impl;public class HelloWorldThread extends Threadpublic class HelloWorldThread extends Threadpublic class HelloWorldThread extends Threadpublic 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/140
37
Pasos en detalle para crear nuestro primer bundle
5. Compilarlo con fichero Ant provisto: ant
6. Importarlo usando el Knopplerfish OSGi Desktop
73/140
Ejecución del Bundle
74/140
38
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 datebundledatebundledatebundledatebundle
� Ofrece como servicio formatear una fecha como un string
� Principal novedad del fichero manifest.mf es la cabecera ExportExportExportExport----Package: es.deusto.dateservicePackage: es.deusto.dateservicePackage: es.deusto.dateservicePackage: es.deusto.dateservice
75/140
Creando tu primer bundle ofreciendo un servicio
1. Definimos el fichero manifest.mf
Manifest-Version: 1.0
Bundle-Name: dateservice
Bundle-SymbolicName: dateservice
Bundle-Version: 1.0.0
Bundle-Description: Demo Bundle
Bundle-Vendor: Universidad de Duesto
BundleBundleBundleBundle----Activator: Activator: Activator: Activator: es.deusto.dateservice.impl.Activatores.deusto.dateservice.impl.Activatores.deusto.dateservice.impl.Activatores.deusto.dateservice.impl.Activator
Bundle-Category: example
ImportImportImportImport----Package: org.osgi.frameworkPackage: org.osgi.frameworkPackage: org.osgi.frameworkPackage: org.osgi.framework
ExportExportExportExport----Package: es.deusto.dateservicePackage: es.deusto.dateservicePackage: es.deusto.dateservicePackage: es.deusto.dateservice
76/140
39
Creando tu primer bundle ofreciendo un servicio
2. Creamos la interfaz que define el servicio src/es/deusto/dateservice/DateService.javapackage es.deusto.dateservice;import java.util.Date;
public interface DateServicepublic interface DateServicepublic interface DateServicepublic interface DateService {public String getFormattedDate(Date date);
}
3. Creamos la implementación del servicio en src/es/deusto/dateservice/impl/DateServiceImpl.javapackage es.deusto.dateservice.impl;import java.text.DateFormat;import java.util.Date;import es.deusto.dateservice.DateService;public class DateServiceImpl implements DateServiceDateServiceImpl implements DateServiceDateServiceImpl implements DateServiceDateServiceImpl implements DateService {
public String getFormattedDate(Date date)String getFormattedDate(Date date)String getFormattedDate(Date date)String getFormattedDate(Date date) {return DateFormat.getDateInstance(DateFormat.SHORT).format(date);}
}
77/140
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 BundleActivatorActivator implements BundleActivatorActivator implements BundleActivatorActivator implements BundleActivator {public static BundleContextBundleContextBundleContextBundleContext bc = null;public void start(BundleContext bc)start(BundleContext bc)start(BundleContext bc)start(BundleContext bc) throws Exception {System.out.println("Empezando " + bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME)bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME)bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME)bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " ...");Activator.bc = bc;DateService service = new DateServiceImpl();ServiceRegistration registration = ServiceRegistration registration = ServiceRegistration registration = ServiceRegistration registration = bc.registerService(DateService.class.getName(), service, new Hashtable());bc.registerService(DateService.class.getName(), service, new Hashtable());bc.registerService(DateService.class.getName(), service, new Hashtable());bc.registerService(DateService.class.getName(), service, new Hashtable());System.out.println("Servicio registrado: dateservice");}
public void stop(BundleContext bc)stop(BundleContext bc)stop(BundleContext bc)stop(BundleContext 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/140
40
Registro de Servicios en OSGi
� El método registerService de BundleContextpermite 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);Long I = new Long(20);Long I = new Long(20);Long I = new Long(20);
Hashtable props = new Hashtable();Hashtable props = new Hashtable();Hashtable props = new Hashtable();Hashtable props = new Hashtable();
props.put("description", "This an long value");props.put("description", "This an long value");props.put("description", "This an long value");props.put("description", "This an long value");
bc.registerService(Long.class.getName(), i, props);bc.registerService(Long.class.getName(), i, props);bc.registerService(Long.class.getName(), i, props);bc.registerService(Long.class.getName(), i, props);
79/140
Más detalles sobre el Activator
� El método getBundle() de BundleContext devuelve un objeto de tipo org.osgi.framework.Bundleasociado con tal contexto.
� El objeto BundleBundleBundleBundle permite recuperar todo tipo de metadatos:� Su identificador (getBundleId()getBundleId()getBundleId()getBundleId())� Cabeceras de su fichero manifest.mf asociado
(getHeaders()getHeaders()getHeaders()getHeaders()) � Recursos asociados al bundle (getResources()getResources()getResources()getResources()).
� La interfaz ConstantsConstantsConstantsConstants define nombres estándar para propiedades del entorno OSGi, sus servicios y las cabeceras del fichero Manifest (e.g. BUNDLE_NAME, BUNDLE_ACTIVATOR).
80/140
41
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
BundleBundleBundleBundle----Activator: es.deusto.dateserviceuser.impl. Activator: es.deusto.dateserviceuser.impl. Activator: es.deusto.dateserviceuser.impl. Activator: es.deusto.dateserviceuser.impl. ActivatorWithoutCheckingReferenceActivatorWithoutCheckingReferenceActivatorWithoutCheckingReferenceActivatorWithoutCheckingReference
ImportImportImportImport----Package: org.osgi.framework,es.deusto.dateservicePackage: org.osgi.framework,es.deusto.dateservicePackage: org.osgi.framework,es.deusto.dateservicePackage: org.osgi.framework,es.deusto.dateservice
81/140
Consuming a Service in OSGi
� Creamos la clase datebundleuser/src/es/deusto/dateserviceuser/impl/ActivatorWithoutCheckingReference.java, que obtiene una referencia al servicio DateService de manera incorrecta:� Para dateservice y luego ejecuta dateserviceuser, ¿por qué falla?
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 BundleActivatorActivatorWithoutCheckingReference implements BundleActivatorActivatorWithoutCheckingReference implements BundleActivatorActivatorWithoutCheckingReference 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());ServiceReference reference = bc.getServiceReference(DateService.class.getName());ServiceReference reference = bc.getServiceReference(DateService.class.getName());ServiceReference reference = bc.getServiceReference(DateService.class.getName());DateService service = (DateService)bc.getService(reference);DateService service = (DateService)bc.getService(reference);DateService service = (DateService)bc.getService(reference);DateService service = (DateService)bc.getService(reference);System.out.println("Usando DateService: formatting date: " + service.getFormattedDate(new
Date()));bc.ungetService(reference);bc.ungetService(reference);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/140
42
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)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/140
Declarando, Instanciando y Registrando un Service Factory
� Definición del ServiceFactory:import org.osgi.framework.ServiceFactory;public class DisplayServiceFactory implements ServiceFactorypublic class DisplayServiceFactory implements ServiceFactorypublic class DisplayServiceFactory implements ServiceFactorypublic class DisplayServiceFactory implements ServiceFactory {
public Object getService(Bundle bundle, ServiceRegistration registration)public Object getService(Bundle bundle, ServiceRegistration registration)public Object getService(Bundle bundle, ServiceRegistration registration)public Object getService(Bundle bundle, ServiceRegistration registration){
Display newDisplay = new Display(Long.toString(bundle.getBundleId()));return newDisplay;
}public void ungetService(Bundle bundle, ServiceRegistration public void ungetService(Bundle bundle, ServiceRegistration public void ungetService(Bundle bundle, ServiceRegistration public void ungetService(Bundle bundle, ServiceRegistration registration,Object service)registration,Object service)registration,Object service)registration,Object service) {
//Nothing needed here in this case}
}
� Creando y registrando el ServiceFactory://Create the ServiceFactoryDisplayServiceFactory factory = new DisplayServiceFactory();DisplayServiceFactory factory = new DisplayServiceFactory();DisplayServiceFactory factory = new DisplayServiceFactory();DisplayServiceFactory factory = new DisplayServiceFactory();//Create the properties of the service. Not mandatory, but used to show //how properties workHashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();properties.put("service.description", "Factory of Display Services");properties.put("service.description", "Factory of Display Services");properties.put("service.description", "Factory of Display Services");properties.put("service.description", "Factory of Display Services");properties.put("service.type", "Factory");properties.put("service.type", "Factory");properties.put("service.type", "Factory");properties.put("service.type", "Factory");
//Register the ServiceFactory for the type IDisplayServiceRegistration registration = ServiceRegistration registration = ServiceRegistration registration = ServiceRegistration registration =
context.registerService(IDisplay.class.getName(), context.registerService(IDisplay.class.getName(), context.registerService(IDisplay.class.getName(), context.registerService(IDisplay.class.getName(), factory, properties);factory, properties);factory, properties);factory, properties);
84/140
43
Usando un Servicio OSGi que Implementa ServiceFactory
//Get and Use one Factory of DisplayService using a filter
String filter = "(service.type=Factory)";String filter = "(service.type=Factory)";String filter = "(service.type=Factory)";String filter = "(service.type=Factory)";
ServiceReference[] serviceRef = ServiceReference[] serviceRef = ServiceReference[] serviceRef = ServiceReference[] serviceRef = context.getServiceReferences(IDisplay.class.getName(),filter);context.getServiceReferences(IDisplay.class.getName(),filter);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]);IDisplay display = (IDisplay)context.getService(serviceRef[0]);IDisplay display = (IDisplay)context.getService(serviceRef[0]);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]);context.ungetService(serviceRef[0]);context.ungetService(serviceRef[0]);context.ungetService(serviceRef[0]);
85/140
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 nullnullnullnull
� 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/140
44
Consumiendo Servicios en OSGi
� Mejora 1 � Comprobar que el servicio es disponible antes de utilizarlo:ServiceReference reference = ServiceReference reference = ServiceReference reference = ServiceReference reference = bc.getServiceReference(DateService.class.getName(bc.getServiceReference(DateService.class.getName(bc.getServiceReference(DateService.class.getName(bc.getServiceReference(DateService.class.getName());));));));
if (reference != null) {if (reference != null) {if (reference != null) {if (reference != 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/140
Consumiendo Servicios en OSGi
� Mejora 2 � Usar ServiceListenerpublic class ActivatorWithServiceListener implements ActivatorWithServiceListener implements ActivatorWithServiceListener implements ActivatorWithServiceListener implements
BundleActivator, ServiceListenerBundleActivator, ServiceListenerBundleActivator, ServiceListenerBundleActivator, ServiceListener {public static BundleContext bc = null;private ServiceUserThread thread = null;private DateService service = null;public void start(BundleContext bc)void start(BundleContext bc)void start(BundleContext bc)void start(BundleContext bc) throws Exception {System.out.println("Empezando " + getClass().getName());ActivatorWithServiceListener.bc = bc;String filter = "(objectclass=" + String filter = "(objectclass=" + String filter = "(objectclass=" + String filter = "(objectclass=" +
DateService.class.getName() + ")";DateService.class.getName() + ")";DateService.class.getName() + ")";DateService.class.getName() + ")";bc.addServiceListener(this, filter);bc.addServiceListener(this, filter);bc.addServiceListener(this, filter);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)public void serviceChanged(ServiceEvent event)public void serviceChanged(ServiceEvent event)public void serviceChanged(ServiceEvent event) {
…}
88/140
45
Consumiendo Servicios en OSGi
� Mejora 3 � Usar ServiceTracker (BestActivator.java)public class BestActivator implements BundleActivatorpublic class BestActivator implements BundleActivatorpublic class BestActivator implements BundleActivatorpublic class BestActivator implements BundleActivator {
public static BundleContext bc = null;private ServiceTracker tracker = null;
public void start(BundleContext bc)void start(BundleContext bc)void start(BundleContext bc)void start(BundleContext bc) throws Exception {System.out.println("Arrancando " +
bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " ...");
BestActivator.bc = bc;MyServiceTrackerCustomizer customizer = new MyServiceTrackerCustomizer customizer = new MyServiceTrackerCustomizer customizer = new MyServiceTrackerCustomizer customizer = new
MyServiceTrackerCustomizer(bc);MyServiceTrackerCustomizer(bc);MyServiceTrackerCustomizer(bc);MyServiceTrackerCustomizer(bc);tracker = new ServiceTracker(bc, tracker = new ServiceTracker(bc, tracker = new ServiceTracker(bc, tracker = new ServiceTracker(bc,
DateService.class.getName(), customizer);DateService.class.getName(), customizer);DateService.class.getName(), customizer);DateService.class.getName(), customizer);tracker.open();tracker.open();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();tracker.close();tracker.close();BestActivator.bc = null;
}} 89/140
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 ServiceTrackerCustomizerMyServiceTrackerCustomizer implements ServiceTrackerCustomizerMyServiceTrackerCustomizer implements ServiceTrackerCustomizerMyServiceTrackerCustomizer implements ServiceTrackerCustomizer {
private ServiceUserThread thread = null;private BundleContext bc;public MyServiceTrackerCustomizer(BundleContext bc) { this.bc = bc; }public Object addingService(ServiceReference reference)Object addingService(ServiceReference reference)Object addingService(ServiceReference reference)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)void modifiedService(ServiceReference reference, Object serviceObject)void modifiedService(ServiceReference reference, Object serviceObject)void modifiedService(ServiceReference reference, Object 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)void removedService(ServiceReference reference, Object serviceObject)void removedService(ServiceReference reference, Object serviceObject)void removedService(ServiceReference reference, Object serviceObject) {this.thread.stopThread();try {this.thread.join();
} catch (InterruptedException e) {e.printStackTrace();
}this.thread = null;
}}
90/140
46
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
� BundleContextBundleContextBundleContextBundleContext permite registrar un ServiceListenerServiceListenerServiceListenerServiceListenercon 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 DateServiceen el método start().
� De manera indirecta con la ayuda del método serviceChanged que debe implementar el Activator
91/140
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/140
47
Resumen Desarrollo de Servicios en OSGi
� 5 pasos requeridos por un bundle exportador de servicios: 1. Implementación del fichero manifest.mfmanifest.mfmanifest.mfmanifest.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 (BundleActivatorBundleActivatorBundleActivatorBundleActivator) y
5. Compilación y despliegue del bundle en el servidor OSGi
� RECUERDA!!! OSGi es un entorno muy dinámico donde aparecen y desaparecen servicios continuamente, donde la interfaz ServiceListenerServiceListenerServiceListenerServiceListener y la clase ServiceTrackerServiceTrackerServiceTrackerServiceTracker nos pueden ofrecer ayuda.
93/140
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.LogServiceorg.osgi.service.log.LogServiceorg.osgi.service.log.LogServiceorg.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/140
48
El Servicio Estándar HttpService
� Puerta de entrada HTTP a la funcionalidad de la plataforma OSGi
� Definido en la interfaz org.osgi.service.http.HttpServiceorg.osgi.service.http.HttpServiceorg.osgi.service.http.HttpServiceorg.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/140
Poniendo en Práctica el LogService y el HttpService
� Objetivo: crear un cliente web del servicio dateservicedateservicedateservicedateservice a través del servicio estándar de OSGi HttpServiceHttpServiceHttpServiceHttpService
� 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/140
49
Dateservicewebuser –Activator.java
import org.osgi.service.http.HttpService;import org.osgi.service.http.HttpService;import org.osgi.service.http.HttpService;import org.osgi.service.http.HttpService;import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;import org.osgi.service.log.LogService;
public class Activator implements BundleActivatorActivator implements BundleActivatorActivator implements BundleActivatorActivator implements BundleActivator {public static BundleContext bc = null;public static LogService log = null;public void start(BundleContext context) throws Exception {Activator.bc = context;ServiceReference refLog = ServiceReference refLog = ServiceReference refLog = ServiceReference refLog =
Activator.bc.getServiceReference(LogService.class.getName()); Activator.bc.getServiceReference(LogService.class.getName()); Activator.bc.getServiceReference(LogService.class.getName()); Activator.bc.getServiceReference(LogService.class.getName()); Activator.log = (LogService) Activator.bc.getService(refLog);Activator.log = (LogService) Activator.bc.getService(refLog);Activator.log = (LogService) Activator.bc.getService(refLog);Activator.log = (LogService) Activator.bc.getService(refLog);Activator.log.log(LogService.LOG_INFO, "Empezando " + Activator.log.log(LogService.LOG_INFO, "Empezando " + Activator.log.log(LogService.LOG_INFO, "Empezando " + Activator.log.log(LogService.LOG_INFO, "Empezando " +
Activator.bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " Activator.bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " Activator.bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " Activator.bc.getBundle().getHeaders().get(Constants.BUNDLE_NAME) + " ...");...");...");...");
Activator.bc = context;//get a reference to the http serviceServiceReference ref = ServiceReference ref = ServiceReference ref = ServiceReference ref =
context.getServiceReference(HttpService.class.getName()); context.getServiceReference(HttpService.class.getName()); context.getServiceReference(HttpService.class.getName()); context.getServiceReference(HttpService.class.getName()); HttpService http = (HttpService) context.getService(ref);HttpService http = (HttpService) context.getService(ref);HttpService http = (HttpService) context.getService(ref);HttpService http = (HttpService) context.getService(ref);//register the capabilities servlet//register the capabilities servlet//register the capabilities servlet//register the capabilities servlethttp.registerServlet("/example", new DateServlet(context),new http.registerServlet("/example", new DateServlet(context),new http.registerServlet("/example", new DateServlet(context),new http.registerServlet("/example", new DateServlet(context),new Properties(),null);Properties(),null);Properties(),null);Properties(),null);
}
public void stop(BundleContext context) throws Exception {}}
97/140
Dateservicewebuser –DateServlet.java
public class DateServlet extends HttpServletDateServlet extends HttpServletDateServlet extends HttpServletDateServlet extends HttpServlet {BundleContext context;public DateServlet(BundleContext context) {this.context = context;
}protected void doGet(HttpServletRequest request, HttpServletResponse response)doGet(HttpServletRequest request, HttpServletResponse response)doGet(HttpServletRequest request, HttpServletResponse response)doGet(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException {//strip the service id from the urlString req = request.getRequestURI();String serviceId = req.substring(req.lastIndexOf('/')+1);//find a service that matches upServiceReference[] 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 matchActivator.log.log(LogService.LOG_INFO, "Comparando con clase " + DateService.class.getName());if (serviceId.equals(DateService.class.getName())) {//do itresponse.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/140
50
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 sencillo protocolo consta de 5 mensajes:� BUNDLE_SEARCHBUNDLE_SEARCHBUNDLE_SEARCHBUNDLE_SEARCH
� BUNDLE_RESPONSE uuid ipAddress portBUNDLE_RESPONSE uuid ipAddress portBUNDLE_RESPONSE uuid ipAddress portBUNDLE_RESPONSE uuid ipAddress port
� BUNDLE_ANNOUNCE uuid ipAddress portBUNDLE_ANNOUNCE uuid ipAddress portBUNDLE_ANNOUNCE uuid ipAddress portBUNDLE_ANNOUNCE uuid ipAddress port
� BUNDLE_GET_METADATA uuidBUNDLE_GET_METADATA uuidBUNDLE_GET_METADATA uuidBUNDLE_GET_METADATA uuid
� BUNDLE_GET_JAR uuidBUNDLE_GET_JAR uuidBUNDLE_GET_JAR uuidBUNDLE_GET_JAR uuid
99/140
BundleDiscoverer
100/140
51
BundleDiscoverer
101/140
BundleDiscoverer: Parte Servidora
102/140
52
BundleDiscoverer: Parte Cliente
103/140
Constantes del Protocolo
package es.deusto.bundlediscoverer;
public class BundleDiscoveryConstantsBundleDiscoveryConstantsBundleDiscoveryConstantsBundleDiscoveryConstants {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/140
53
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 SerializableBundleMetadata implements SerializableBundleMetadata implements SerializableBundleMetadata implements Serializable {
public String uuid;public String ipAddress;public int port;public long timestamp;public Bundle bundle;public BundleMetadata(String uuid, String ipAddress, int port, Bundle public BundleMetadata(String uuid, String ipAddress, int port, Bundle public BundleMetadata(String uuid, String ipAddress, int port, Bundle public BundleMetadata(String uuid, String ipAddress, int port, Bundle bundle)bundle)bundle)bundle) {this.uuid = uuid;this.ipAddress = ipAddress;this.port = port;this.timestamp = System.currentTimeMillis();this.bundle = bundle;
}}
105/140
BundleDiscoverImpl
� La clase BundleDiscovererImpl aparte de implementar la interfaz BundleDiscoverer, también hereda de la clase Thread� Implementa 2 timers:
1. 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
2. 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/140
54
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 servicePortStringTokenizer 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, uuid, ipAddress, Integer.parseInt(port)).start();new RetrieveRegisterBundleThread(this, uuid, ipAddress, Integer.parseInt(port)).start();new RetrieveRegisterBundleThread(this, uuid, ipAddress, Integer.parseInt(port)).start();new RetrieveRegisterBundleThread(this, uuid, ipAddress, 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/140
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/140
55
Eliminación Selectiva de Bundles
private void initPeriodicRegistryCleanUpinitPeriodicRegistryCleanUpinitPeriodicRegistryCleanUpinitPeriodicRegistryCleanUp() {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 service: bundlesAvailableMap.values()BundleMetadata service: bundlesAvailableMap.values()BundleMetadata service: bundlesAvailableMap.values()BundleMetadata service: bundlesAvailableMap.values()) {
if (service.timestamp+BundleDiscoveryConstants.BUNDLE_HEARTBEAT_PERIOD < currentTime) {
try {service.bundle.stop();service.bundle.stop();service.bundle.stop();service.bundle.stop();service.bundle.uninstall();service.bundle.uninstall();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/140
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);Bundle bundleInstalado = Activator.bc.installBundle(bundleUrl);Bundle bundleInstalado = Activator.bc.installBundle(bundleUrl);Bundle bundleInstalado = Activator.bc.installBundle(bundleUrl);bundleInstalado.start();bundleInstalado.start();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/140
56
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/140
Aplicación de Ejemplo Usando BundleDiscoverer
� La clase WeatherForecastServer exporta 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/140
57
BundleDiscoverer
113/140
BundleDiscoverer
114/140
58
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/140
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/140
59
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()activate()) y otro de desactivación (deactivate()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/140
Formato bundle.manifest en un Bundle definido con el Declarative Services
ServiceServiceServiceService----Component: OSGIComponent: OSGIComponent: OSGIComponent: OSGI----INF/es.deusto.tecnologico.osgi.declarative.impl.Display.xmlINF/es.deusto.tecnologico.osgi.declarative.impl.Display.xmlINF/es.deusto.tecnologico.osgi.declarative.impl.Display.xmlINF/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
ImportImportImportImport----Package: org.osgi.service.component, Package: org.osgi.service.component, Package: org.osgi.service.component, Package: org.osgi.service.component, org.osgi.service.logorg.osgi.service.logorg.osgi.service.logorg.osgi.service.log
118/140
60
Fichero XML de definición de un bundle
<?xml version='1.0' encoding='utf-8'?>
<component <component <component <component name='es.deusto.tecnologico.osgi.declarative.impl.Display'>name='es.deusto.tecnologico.osgi.declarative.impl.Display'>name='es.deusto.tecnologico.osgi.declarative.impl.Display'>name='es.deusto.tecnologico.osgi.declarative.impl.Display'>
<implementationimplementationimplementationimplementationclassclassclassclass='es.deusto.tecnologico.osgi.declarative.impl.Display'/>
<referencereferencereferencereference name='log' interfaceinterfaceinterfaceinterface='org.osgi.service.log.LogService' bindbindbindbind='setLog' unbindunbindunbindunbind='unsetLog'/>
</component></component></component></component>
119/140
Implementación del Bundle
import org.osgi.service.component.ComponentContext;...public class Display extends Thread {public class Display extends Thread {public class Display extends Thread {public class Display extends Thread {
LogService log;private boolean quit = false;protected void activate(ComponentContext context)protected void activate(ComponentContext context)protected void activate(ComponentContext context)protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component activated");this.start();
}protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component deactivated");quit = true;
}public synchronized void run()public synchronized void run()public synchronized void run()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)public void setLog(LogService log)public void setLog(LogService log)public void setLog(LogService log) {
this.log = log;log.log(LogService.LOG_INFO, "LogService bounded to Display");
}public void unsetLog(LogService log)public void unsetLog(LogService log)public void unsetLog(LogService log)public void unsetLog(LogService log) {
log.log(LogService.LOG_INFO, "LogService unbounded to Display");this.log = null;
} }
120/140
61
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:� Evento (EventEventEventEvent): situación que un bundle quiere notificar, compuesto de:
� 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.
� Event HandlerEvent HandlerEvent HandlerEvent Handler, interfaz bajo el cual debe registrarse un servicio que quiera 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 PublisherEvent PublisherEvent PublisherEvent Publisher – publicadores de eventos que no tienen ninguna característica especial. Simplemente necesitan una referencia al servicio EventAdmin donde publicar eventos.
� EventAdminEventAdminEventAdminEventAdmin – servicio que implementa el canal de eventos, ofreciendo dos tipos de envío: síncrono y asíncrono
121/140
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
ImportImportImportImport----Package: org.osgi.service.component, Package: org.osgi.service.component, Package: org.osgi.service.component, Package: org.osgi.service.component, org.osgi.service.event, org.osgi.service.logorg.osgi.service.event, org.osgi.service.logorg.osgi.service.event, org.osgi.service.logorg.osgi.service.event, org.osgi.service.log
Service-Component: OSGI-INF/Display.xml,OSGI-INF/Clock.xml
122/140
62
Ficheros de configuración de los componentes productor y consumidor de eventos
� Productor: Clock.xmlClock.xmlClock.xmlClock.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='eventAdmin' interface='org.osgi.service.event.EventAdmin' <reference name='eventAdmin' interface='org.osgi.service.event.EventAdmin' <reference name='eventAdmin' interface='org.osgi.service.event.EventAdmin' <reference name='eventAdmin' interface='org.osgi.service.event.EventAdmin' bind='setEventAdmin' unbind='unsetEventAdmin'/>bind='setEventAdmin' unbind='unsetEventAdmin'/>bind='setEventAdmin' unbind='unsetEventAdmin'/>bind='setEventAdmin' unbind='unsetEventAdmin'/>
</component>
� Consumidor: Display.xmlDisplay.xmlDisplay.xmlDisplay.xml<?xml version="1.0" encoding="utf-8"?><component name="es.deusto.tecnologico.osgi.eventadmin.impl.Display"
immediate="true"immediate="true"immediate="true"immediate="true"><implementation class="es.deusto.tecnologico.osgi.eventadmin.impl.Display"/><property <property <property <property name="event.topics">es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE</pname="event.topics">es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE</pname="event.topics">es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE</pname="event.topics">es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE</property>roperty>roperty>roperty><service><service><service><service><provide interface="org.osgi.service.event.EventHandler" /><provide interface="org.osgi.service.event.EventHandler" /><provide interface="org.osgi.service.event.EventHandler" /><provide interface="org.osgi.service.event.EventHandler" /><provide interface="es.deusto.tecnologico.osgi.eventadmin.IDisplay" /><provide interface="es.deusto.tecnologico.osgi.eventadmin.IDisplay" /><provide interface="es.deusto.tecnologico.osgi.eventadmin.IDisplay" /><provide interface="es.deusto.tecnologico.osgi.eventadmin.IDisplay" /></service> </service> </service> </service> <reference name="log" interface="org.osgi.service.log.LogService" bind="setLog" unbind="unsetLog"/>
</component>
123/140
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 ThreadClock extends ThreadClock extends ThreadClock extends Thread {
LogService log = null;EventAdmin eventAdmin = null;boolean quit = false;protected void activate(ComponentContext context)protected void activate(ComponentContext context)protected void activate(ComponentContext context)protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Clock component activated");this.start();
}protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)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";String topic = "es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE";String topic = "es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE";String topic = "es/deusto/tecnologico/osgi/eventadmin/Clock/NEW_DATE";Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();properties.put("currentTime", now.toString() );properties.put("currentTime", now.toString() );properties.put("currentTime", now.toString() );properties.put("currentTime", now.toString() );Event newEvent = new Event(topic,properties);Event newEvent = new Event(topic,properties);Event newEvent = new Event(topic,properties);Event newEvent = new Event(topic,properties);eventAdmin.sendEvent(newEvent); // send it synchronouslyeventAdmin.sendEvent(newEvent); // send it synchronouslyeventAdmin.sendEvent(newEvent); // send it synchronouslyeventAdmin.sendEvent(newEvent); // send it synchronouslywait(3000);
} catch (InterruptedException ie) {}}
}
124/140
63
Productor de Eventos: Clock
public void setLog(LogService log)public void setLog(LogService log)public void setLog(LogService log)public void setLog(LogService log) {
this.log = log;
log.log(LogService.LOG_INFO, "LogService bounded to Display");
}
public void unsetLog(LogService log)public void unsetLog(LogService log)public void unsetLog(LogService log)public void unsetLog(LogService log) {
log.log(LogService.LOG_INFO, "LogService unbounded to Display");
this.log = null;
}
public void setEventAdmin(EventAdmin eventAdmin)public void setEventAdmin(EventAdmin eventAdmin)public void setEventAdmin(EventAdmin eventAdmin)public void setEventAdmin(EventAdmin eventAdmin) {
this.eventAdmin = eventAdmin;
}
public void unsetEventAdmin(EventAdmin eventAdmin)public void unsetEventAdmin(EventAdmin eventAdmin)public void unsetEventAdmin(EventAdmin eventAdmin)public void unsetEventAdmin(EventAdmin eventAdmin) {
this.eventAdmin = null;
}
}
125/140
Consumidor de Eventos: IDisplay
package es.deusto.tecnologico.osgi.eventadmin;
public interface IDisplay {public interface IDisplay {public interface IDisplay {public interface IDisplay {public String getLastMessage();public String getLastMessage();public String getLastMessage();public String getLastMessage();
}}}}
126/140
64
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, EventHandlerDisplay implements IDisplay, EventHandlerDisplay implements IDisplay, EventHandlerDisplay implements 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)protected void activate(ComponentContext context)protected void activate(ComponentContext context)protected void activate(ComponentContext context) {
log.log(LogService.LOG_INFO, "Display component activated");}protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)protected void deactivate(ComponentContext context)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)public synchronized void handleEvent(Event newEvent)public synchronized void handleEvent(Event newEvent)public synchronized void handleEvent(Event newEvent) {
message = (String)newEvent.getProperty("currentTime");}public String getLastMessage() {
return message;}
}
127/140
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 usarorg.osgi.framework, org.osgi.service.cm
128/140
65
Obteniendo, creando o actualizando un objeto de Configuración
//Search the reference to the ConfigurationAdminServiceReference configAdminReference = ServiceReference configAdminReference = ServiceReference configAdminReference = ServiceReference configAdminReference =
context.getServiceReference(ConfigurationAdmin.class.getName());context.getServiceReference(ConfigurationAdmin.class.getName());context.getServiceReference(ConfigurationAdmin.class.getName());context.getServiceReference(ConfigurationAdmin.class.getName());ConfigurationAdmin configAdmin = ConfigurationAdmin configAdmin = ConfigurationAdmin configAdmin = ConfigurationAdmin configAdmin =
(ConfigurationAdmin)context.getService(configAdminReference);(ConfigurationAdmin)context.getService(configAdminReference);(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 = Configuration config = Configuration config = Configuration config =
configAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfigurationconfigAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfigurationconfigAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfigurationconfigAdmin.getConfiguration("es.deusto.tecnologico.osgi.GetConfiguration", null );", null );", null );", null );
//As this is the first time the properties must be created firstHashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();Hashtable properties = new Hashtable();properties.put("port", new Integer(6023));properties.put("port", new Integer(6023));properties.put("port", new Integer(6023));properties.put("port", new Integer(6023));properties.put("motto", "Message set with the configuration admin");properties.put("motto", "Message set with the configuration admin");properties.put("motto", "Message set with the configuration admin");properties.put("motto", "Message set with the configuration admin");
//Update the propertiesconfig.update(properties);config.update(properties);config.update(properties);config.update(properties);
129/140
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 mandatoryproperties = 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 interfaceregistration = 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 serviceregistration.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/140
66
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/140
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/140
67
Definiendo un Productor
import org.osgi.service.wireadmin.Producer;import org.osgi.service.wireadmin.Producer;import org.osgi.service.wireadmin.Producer;import org.osgi.service.wireadmin.Producer;…public class Clock extends Thread implements Producerpublic class Clock extends Thread implements Producerpublic class Clock extends Thread implements Producerpublic 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 = new Hashtable();Hashtable p = new Hashtable();Hashtable p = new Hashtable();p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS, new p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS, new p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS, new p.put(org.osgi.service.wireadmin.WireConstants.WIREADMIN_PRODUCER_FLAVORS, new
Class[] { Date.class, String.class });Class[] { Date.class, String.class });Class[] { Date.class, String.class });Class[] { Date.class, String.class });p.put(org.osgi.framework.Constants.SERVICE_PID, "es.deusto.Clock");p.put(org.osgi.framework.Constants.SERVICE_PID, "es.deusto.Clock");p.put(org.osgi.framework.Constants.SERVICE_PID, "es.deusto.Clock");p.put(org.osgi.framework.Constants.SERVICE_PID, "es.deusto.Clock");
context.registerService(Producer.class.getName(), this, p);context.registerService(Producer.class.getName(), this, p);context.registerService(Producer.class.getName(), this, p);context.registerService(Producer.class.getName(), this, p);}public synchronized void run()public synchronized void run()public synchronized void run()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);wires[i].update(now);wires[i].update(now.toString());wires[i].update(now.toString());wires[i].update(now.toString());wires[i].update(now.toString());
}wait(3000);
} catch (InterruptedException ie) {}}
133/140
Definiendo un Productor
public synchronized void consumersConnected(Wire[] wires)public synchronized void consumersConnected(Wire[] wires)public synchronized void consumersConnected(Wire[] wires)public synchronized void consumersConnected(Wire[] wires) {
this.wires = wires;
}
public synchronized Object polled(Wire wire) public synchronized Object polled(Wire wire) public synchronized Object polled(Wire wire) 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/140
68
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/140
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/soap/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
� Eclipse Rich Ajax Platform (RAP) permite crear Rich Internet Applications (RIA) usando el modelo de componentes OSGi� Podemos compartir el mismo código para aplicaciones RCP y RIA
136/140
69
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 servcio 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/140
OSGi en la Empresa
� Existen varios proyectos que quieren integrar la capacidades de gestión dinámica de módulos de OSGi en servidores de aplicaciones:� Spring Dynamic Modules for OSGi Services Plataform:
http://www.springframework.org/osgi� JOnAS – Java Open Application Server:
http://wiki.jonas.objectweb.org/xwiki/bin/view/Main/� Equinox Serverside Quickstart:
http://eclipse.org/equinox/documents/http_quickstart.php
138/140
70
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
139/140
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
� Mi página personal: http://paginaspersonales.deusto.es/dipina
140/140