15 września 2008

Bundle.findEntries() i spring-osgi-bundle-archetype w akcji - monitorowanie pakunków OSGi z określoną strukturą katalogową

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!

2 komentarze:

  1. 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:
    * 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);
    }
    }

    OdpowiedzUsuń
  2. 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 ;-)).

    "Dodam jeszcze

    OdpowiedzUsuń