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.

2 komentarze:

  1. Cześć,
    jedno pytanie co do granulacji:) czy jak to nazwać, czy można na przykład za pomocą OSGi włączać i wyłączać algorytm (czy to już jest za mały bundle)? (przypuśćmy mamy serwer który robi jakiś load-balncing na przykład: pierwszy algorytm FIFO potem coś tam innego i czy można by je zmieniać, czy trzeba wymieniać cały load-balancing mechanizm). Mam nadzieje, że jest to w miarę jasne, co napisałem:)

    OdpowiedzUsuń
  2. OSGi wręcz wymusza takie tworzenie oprogramowania (pakunków), aby interfejs i klasy pomocnicze były w jednym, a implementacje w innych. Ilu? Tylu, ile będzie implementacji, albo ile sobie zażyczysz. Nie ma sztywnych reguł, jak prowadzisz rozwój swojej aplikacji (opartej o pakunki), a jedynie zalecenia i właśnie o najważniejszym przeczytałeś w pierwszym zdaniu - podział usług (funkcjonalności) na intf oraz implementację. Czym większa granulacja, tym większa szansa na możliwość podmiany podczas jej działania. Twój przykład jest wprost wymarzonym przykładem, choć wielu stwierdziłoby, że to jest raczej konfiguracja aplikacji z poziomu użytkownika, albo architekta aplikacji, niż później administratora (który zaktualizowałby pakunek). Najważniejsze, aby myśleć o OSGi jako o bogatszej ładowarce klas, gdzie możliwe jest wersjonowanie pakunków i dołączanie ich do aplikacji (również pakunków). Pytaj, jak coś niejasne, bo w ten sposób samemu zaczynam rozumieć temat ;-)

    OdpowiedzUsuń