24 września 2008

Equinox i jego diag do analizy wymagań pakunku OSGi

Dzisiaj postanowiłem spróbować odpowiedzieć kilku osobom o roli Spring Dynamic Modules (Spring-DM) w integracji Spring Framework, OSGi i aplikacji webowych. Efektem prac miała być demonstracyjna aplikacja webowa, gdzie biblioteki z WEB-INF/lib byłyby osobnymi pakunkami, a sam katalog byłby pusty. Już rozpisałem sobie plan działania - stworzenie projektu aplikacji webowej, pakunków, itp., uruchomienie platformy OSGi (w tej roli Equinox) ze Spring-DM, gdzie w roli głównej występowałby pakunek Spring-DM web extender (spring-osgi-web-extender), i...właśnie, w chwili kiedy napisałem nazwę tego pakunku postanowiłem zacząć od tyłu - od uruchomienia pakunku spring-osgi-web-extender. Jego rolą jest nasłuchiwanie na zdarzenia instalacji i odinstalowywania pakunków, i przy spełnieniu warunków dla pakunków OSGi będących aplikacjami webowymi - rozszerzenie war lub posiadanie katalogu WEB-INF - przekazanie ich do kontenera servletów (dostępne są Apache Tomcat lub Jetty). Już pisałem o nim trochę w notce Aplikacja webowa jako pakunek OSGi ze Spring Dynamic Modules, ale tamto dotyczyło Spring-DM 1.1.0 M2, a teraz pracuję z Spring-DM 1.2.0-m2-SNAPSHOT (zbudowanym samodzielnie ze źródeł - instrukcja w notce Budowanie Spring-DM ze źródeł) i wiele się zmieniło. Stwierdziłem, że do tematu podejdę na opak, gdzie narzędziami diagnostycznymi Equinoksa rozpoznam zależności pakunku spring-osgi-web-extender i po kolei będę je wczytywał. W końcu zbudowałem Spring-DM ze źródeł z włączonymi testami jednostkowymi, więc miałem pewność, że wszystkie niezbędne biblioteki-pakunki miałem w moim lokalnym repozytorium mavenowym.

Rozpocząłem od uruchomienia platformy OSGi, którą był Eclipse Equinox.
 jlaskowski@work /cygdrive/c/apps/equinox
$ java -jar org.eclipse.osgi_3.5.0.v20080804-1730.jar -console

osgi> ss

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.5.0.v20080804-1730
Następnie zainstalowałem pakunek spring-osgi-web-extender (z lokalnego repozytorium mavenowego).
 osgi> install file:/C:/.m2/org/springframework/osgi/spring-osgi-web-extender/
1.2.0-m2-SNAPSHOT/spring-osgi-web-extender-1.2.0-m2-SNAPSHOT.jar
Bundle id is 1

osgi> headers 1
Bundle headers:
Bnd-LastModified = 1222091464343
Build-Jdk = 1.5.0_14
Built-By = jlaskowski
Bundle-Activator = org.springframework.osgi.web.extender.internal.activator.WarLoaderListener
Bundle-Description = Spring/OSGi web extender. Detects war bundles and deployes them into the configured web container.
Bundle-DocURL = http://www.springframework.org
Bundle-License = http://www.apache.org/licenses/LICENSE-2.0
Bundle-ManifestVersion = 2
Bundle-Name = spring-osgi-web-extender
Bundle-SymbolicName = org.springframework.bundle.osgi.web.extender
Bundle-Vendor = Spring Framework
Bundle-Version = 1.2.0.m2-SNAPSHOT
Import-Package = org.apache.commons.logging,org.osgi.framework;version="1.3",org.springframework.beans.factory;version="2.5.4",
org.springframework.core;version="2.5.4",org.springframework.core.task;version="2.5.4",org.springframework.osgi;version="1.2.0.m2",
org.springframework.osgi.context;version="1.2.0.m2",org.springframework.osgi.context.support;version="1.2.0.m2",
org.springframework.osgi.util;version="1.2.0.m2",org.springframework.osgi.web.deployer;version="1.2.0.m2",
org.springframework.osgi.web.deployer.jetty;resolution:=optional;version="1.2.0.m2",
org.springframework.osgi.web.deployer.support;version="1.2.0.m2",org.springframework.osgi.web.deployer.tomcat;
resolution:=optional;version="1.2.0.m2",org.springframework.scheduling.timer;version="2.5.4",
org.springframework.util;version="2.5.4"
Manifest-Version = 1.0
Private-Package = org.springframework.osgi.extender.internal.util,
org.springframework.osgi.extender.internal.util.concurrent,
org.springframework.osgi.web.extender.internal.activator,
org.springframework.osgi.web.extender.internal.scanner
Spring-DM-Version = 1.2.0-m2-SNAPSHOT
Spring-Version = 2.5.6-SNAPSHOT
Tool = Bnd-0.0.238
UWAGA: Na zrzucie linia z poleceniem install oraz dla nagłówków Import-Package i Private-Package są "złamane" dla celów prezentacji.

Jak widać na powyższym zrzucie, w nagłówku Import-Package, pakunek spring-osgi-web-extender wymaga wielu pakietów udostępnianych przez inne (wspierające) pakunki. To właśnie wybrałem jako temat rozpoczynający prace - poprawnie zdefiniować wszystkie wymagane zależności pakunku spring-osgi-web-extender na podstawie Import-Package.

Przeglądając źródła Spring-DM, a konkretnie pomy, doszedłem do pierwszych wymaganych pakunków, które spełnią istnienie pierwszego pakietu na liście Import-Package - org.apache.commons.logging:
  • org/slf4j/com.springsource.slf4j.org.apache.commons.logging/1.5.0/com.springsource.slf4j.org.apache.commons.logging-1.5.0.jar
  • org/slf4j/com.springsource.slf4j.api/1.5.0/com.springsource.slf4j.api-1.5.0.jar
  • org/slf4j/com.springsource.slf4j.log4j/1.5.0/com.springsource.slf4j.log4j-1.5.0.jar
  • org/springframework/osgi/log4j.osgi/1.2.15-SNAPSHOT/log4j.osgi-1.2.15-SNAPSHOT.jar
Po ich zainstalowaniu i uruchomieniu pozostało określić dostawców pozostałych pakietów. Tylko, że po jakimś czasie może pojawić się pytanie - które jeszcze pakiety/pakunki nie są dostępne? Zacząłem rozmyślać, jak fajnie byłoby mieć narzędzie ala Maven w OSGi, które pobierze wymagane pakunki, aby środowisko było poprawnie zestawione dla wybranego pakunku, albo co najmniej ujawni brakujące pakiety. I jakoś szczęśliwie się zdarzyło, że przeglądając wynik equinoksowego polecenia help znalazłem odpowiedź - diag.
 osgi> help
---Eclipse Runtime commands---
diag - Displays unsatisfied constraints for the specified bundle(s).
enableBundle - enable the specified bundle(s)
disableBundle - disable the specified bundle(s)
disabledBundles - list disabled bundles in the system
Polecenie diag dokładnie spełnia moje oczekiwania - wyświetla wymagania niespełnione w środowisku dla wybranego pakunku.
 osgi> diag 1
file:/C:/.m2/org/springframework/osgi/spring-osgi-web-extender/
1.2.0-m2-SNAPSHOT/spring-osgi-web-extender-1.2.0-m2-SNAPSHOT.jar [1]
Direct constraints which are unresolved:
Missing imported package org.springframework.beans.factory_2.5.4.
Missing imported package org.springframework.core_2.5.4.
Missing imported package org.springframework.core.task_2.5.4.
Missing imported package org.springframework.osgi_1.2.0.m2.
Missing imported package org.springframework.osgi.context_1.2.0.m2.
Missing imported package org.springframework.osgi.context.support_1.2.0.m2.
Missing imported package org.springframework.osgi.util_1.2.0.m2.
Missing imported package org.springframework.osgi.web.deployer_1.2.0.m2.
Missing imported package org.springframework.osgi.web.deployer.jetty_1.2.0.m2.
Missing imported package org.springframework.osgi.web.deployer.support_1.2.0.m2.
Missing imported package org.springframework.osgi.web.deployer.tomcat_1.2.0.m2.
Missing imported package org.springframework.scheduling.timer_2.5.4.
Missing imported package org.springframework.util_2.5.4.
I to jest dokładnie to! Tych pakietów jeszcze nie zainstalowałem. To jest jednakże już praca na kolejne dni.