Spring Dynamic Modules (dalej Spring-DM) umożliwia tworzenie ziaren springowych jako pakunki OSGi umożliwiając skorzystanie z cech obu środowisk - Spring Framework i OSGi. Tak określiłbym motto projektu. Jednym z elementów wspomagających tworzenie aplikacji korporacyjnych ze Spring-DM jest stworzenie środowiska uruchomieniowego, w którym cechy OSGi są integralną częścią środowiska. W ten sposób aplikacja webowa może być dystrybuowana w postaci pakunku (wystarczy jedynie dopisanie kilku nagłówków w META-INF/MANIFEST.MF) i uruchomiona w ramach Platformy OSGi (Equinox, Felix czy Knopflerfish). Teoretycznie (jeszcze) możemy sobie wyobrazić sytuację, w której poszczególne części aplikacji są dystrybuowane jako pakunki OSGi, które z kolei składają się na większy pakunek OSGi będący nota bene aplikacją webową. "A po co?" - możnaby zapytać. Odpowiedź sama się nasuwa - wprowadzenie/podniesienie modularności w aplikacji. Jeśli weźmiemy za przykład aplikację webową, to jej jedną z części mogą być servlety zgrupowane jako pakunek OSGi, który dzięki mechanizmom OSGi moglibyśmy podmienić...w trakcie działania naszej aplikacji (!) Czyż nie jest to cecha, której wprowadzenia pożądalibyśmy w naszych aplikacjach? Z pewnością!
W moim nowym artykule Bundle.findEntries() i spring-osgi-bundle-archetype w akcji - monitorowanie pakunków OSGi z określoną strukturą katalogową przedstawiłem funkcjonowanie metody org.osgi.framework.Bundle.findEntries(), której zadaniem jest zwrócenie zawartości odpytywanego pakunku jako listę URLi. W ten sposób możemy prześwietlić zawartość pakunków i poznać ich strukturę katalogową. Dodając do tego możliwość rejestracji słuchacza zdarzeń instalacja/odinstalowanie pakunków przy pomocy org.osgi.framework.BundleListener mamy doskonały sposób na monitorowanie zmian na Platformie OSGi i weryfikację, czy zainstalowany właśnie pakunek nie jest przypadkiem specjalnego traktowania przez naszą aplikację monitorującą. Zgłoszenie zdarzenia podmiany (=odinstalowania i instalacji) pakunku ponownie powoduje wzbudzenie BundleListener i wykonanie właściwej akcji. Mam wrażenie, że jest to jedyny tego typu szkielet aplikacyjny, który znosi z nas obowiązek własnoręcznego tworzenia mechanizmu monitorowania zmian w środowisku - w OSGi wystarczy jedynie implementacja BundleListener. Więcej w samym artykule. Miłej lektury!
Powyżej opisany został tzw. "extender model" lub "extender pattern". Jest to (wraz z "whiteboard pattern") jeden z kluczowych patternów przy tworzeniu systemów opartych o OSGi. Więcej można o nim przeczytać tu:
OdpowiedzUsuń* Book - OSGi in Practice - The Extender Model:
http://neilbartlett.name/blog/osgibook/
* Jayview nr 14: OSGi – not just a four letter word:
http://www.jayway.se/download/18.22f90280115a3439d1a80001597/jayview14.pdf
Ciekawy jest też projekt Pax Swissbox extender.
Dodam jeszcze że przykład Jacka ignoruje bundle które były wystartowane wcześniej - bo dla nich listener nie dostanie eventa.
Poza tym lepiej sprawdzać kundle w stanie resolved a nie installed.
Czyli powinno być coś w stylu:
public class Aktywator implements BundleActivator {
private final static BundleListener SLUCHACZ = new BundleListener() {
public void bundleChanged(BundleEvent event) {
System.out.println("Pakunek " + event.getBundle().getSymbolicName() + " zmienił stan");
switch (event.getType()) {
case BundleEvent.RESOLVED:
addingBundle(event.getBundle());
break;
case BundleEvent.UNRESOLVED:
System.out.println("...odinstalowano");
break;
}
}
};
private void addingBundle(Bundle bundle) {
System.out.println("...zainstalowano");
// sprawdź, czy zawiera META-INF/ejb-jar.xml, który oznacza moduł EJB
if (null != bundle.findEntries("META-INF", "ejb-jar.xml", false)){
System.out.println("...rozpoznano moduł EJB");
}
}
public void start(BundleContext context) throws Exception {
System.out.println("Instalacja " + SLUCHACZ);
context.addBundleListener(SLUCHACZ);
Bundle [] bundles = context.getBundles ( ) ;
for ( Bundle bundle : bundles ){
if (Bundle.RESOLVED == bundle.getState( ) )
addingBundle ( bundle );
}
}
}
public void stop(BundleContext context) throws Exception {
System.out.println("Usuniecie " + SLUCHACZ);
context.removeBundleListener(SLUCHACZ);
}
}
Muszę przyznać, że Damian nie mógł mnie bardziej publicznie zbesztać i wskazał wszystkie moje błędy w tak niewielkim funkcjonalnie aktywatorze ;-) Zaraz po tym, kiedy opublikowałem wpis zorientowałem się, że właśnie "przykład Jacka ignoruje bundle które były wystartowane wcześniej - bo dla nich listener nie dostanie eventa. Poza tym lepiej sprawdzać bundle w stanie resolved a nie installed." Zastanawiałem się, kto wskaże owe miejsca i nie długo trzeba było czekać, aż się doczekałem. Dobra robota Damian! Pogratulować wiedzy (i hojności publicznej krytyki ;-)).
OdpowiedzUsuń"Dodam jeszcze