Dependencias Bundle OSGI
Back
Este post describe un problema que hemos tenido con dependencias de otros bundle, en este caso uno de nuestros bundle fallaba con un java.lang.ClassNotFoundException de una clase existente en Servicemix y como ha sido solucionado.

Problema

Desarrollamos una solución que tiene 2 bundle, uno de librería (L) y otro que publica un servicio OSGI (S). Este servicio utiliza el bundle L para realizar llamadas HTTP. De esta forma el bundle S tiene la lógica de negocio y el bundle L la tecnología de comunicación. Esto nos permite tener independencia entre la lógica y la tecnología y poder eventualmente sustituirlo caso sea necesario.

 

El uso de servicios OSGI nos permitió implementar facilmente un mecanismo de pruebas unitarias utilizando JUnit y de esta forma realizar pruebas rápidas de la funcionalidad directamente desde el servidor de CI utilizando scripts Gradle.

 

El problema nos encontramos al desplegar la aplicación. Al instanciarse la clase responsable por realizar la llamada HTTP, esta fallaba con un ClassNotFoundException:

 

java.lang.ClassNotFoundException: org.apache.http.client.HttpClient 

Síntomas

Inicialmente estábamos seguros de que esta clase existia en Servicemix ya que teníamos instalado camel-http4 que incluye el bundle Apache Apache HttpClient OSGi. Revisando e. Jar del bunde si podímos encontrar esa clase y en el MANIFEST era visible el Export del package que la contenía.

 

En Servicemix revisamos las exportaciones de los package y pudimos comprobar que el package org.apache.http.client se exportaba.

 

exports | grep org.apache.http.client

 

Realizamos además la búsqueda por la clase HttpClient que también se encontraba localizada.

 

bundle:find-class HttpClient

 

camel-http4 (276)

...

org/apache/http/client/HttpClient.class

...

 

Revisamos también los Import-Package de nuestro bundle y todo parecía estar en su lugar. Aquí residia, como no podia dejar de ser, el problema.

Solución

El Import-Package del package org.apache.http.client existia a nivel del bundle S pero no del bundle L. Al tener cada bundle su propio classloader la clase HttpCliente se estaba cargando en el bundle S y no en el L donde si existía el Import-Package. Caso utilizáramos Fragment Bundle la cosa cambiaría pero no es el caso.

 

Curioso el hecho de que el plugin osgi de Gradle tampoco haya generado el correspondiente registro de Import-Package en el MANIFEST.