12 marca 2008

Kolejny łyk OSGi - rozdział 3. Warstwa modułowa

Zabrałem się za rozdział 3. Module Layer specyfikacji OSGi Service Platform 4 i sprawy zaczynają stawać się bardziej zrozumiałe - co i jak w OSGi piszczy. Tworzę typowy projekt (z pomocą Maven), dodaję wtyczkę maven-bundle-plugin, która dodaje mi dodatkowe wpisy w META-INF/MANIFEST.MF i mam pakunek OSGi. Teraz wystarczy go zainstalować (polecenie install) i uruchomić (start). Aż tyle, albo tylko tyle. Diabeł tkwi w szczegółach, którym się teraz przyjrzę.

Powodem zdefiniowania warstwy modułowej (Module Layer) w OSGi jest niedoskonałość (!) mechanizmów pakowania (packaging), wdrażania (deployment) oraz kontroli poprawności (validation) aplikacji napisanych w Javie. Ciekawostką tego rozdziału jest uwaga dotycząca JBossa oraz NetBeans i ich własnej warstwy modułowej ze specjalizowanymi zarządcami klas. Odpowiedzią OSGi jest właśnie specyfikacja warstwy modułowej, która jest ujednoliconym i ustandaryzowanym mechanizmem dla modularyzacji w Javie.

OSGi wprowadza pojęcie jednostki modułowej - pakunku (ang. bundle). Pakunek składa się z klas Java i innych zasobów, które wspólnie dostarczają pewną funkcjonalność (możemy ją nazwać również usługą). Pakunki mogą udostępniać pakiety (ang. packages) między pakunkiem eksportującym/udostępniającym (ang. exporter bundle) a pakunkiem importującym (ang. importer bundle) w jasno określony sposób. Każdy z pakunków ma swoją własnego zarządcę klas (który faktycznie może nie być utworzony, aż do momentu jego użycia).

W OSGi pakunki są jedynymi bytami do wdrożenia aplikacji javowych.

Pojedyńczy pakunek jest plikiem jar z wymaganymi zasobami do poprawnego działania aplikacji. Zawiera wymagane i opcjonalne ustawienia konfiguracyjne w manifeście META-INF/MANIFEST.MF za pomocą nagłówków, które są wczytywane przez OSGi podczas instalacji i aktywacji pakunku. Dodatkowa dokumentacja pakunku specyficzne dla OSGi znajduje się w katalogu OSGI-OPT w pliku jar bądź jego podkatalogach. Specyfikacja wskazuje OSGI-OPT jako możliwe miejsce składowania źródeł pakunku.

(Meta)informacje o pakunku są zawarte w pliku META-INF/MANIFEST.MF. Wszystkie nagłówki są opcjonalne za wyjątkiem obowiązkowego Bundle-SymbolicName.

Bundle-SymbolicName przypisuje jednoznaczną i nie podlegającą tłumaczeniu nazwę pakunku. Zaleca się, aby nazwa pakunku była nazywana zgodnie z konwencją odwrotnej nazwy domeny, np. pl.jaceklaskowski.osgi.HighlyPerformantServerBundle.

Jednym z ważniejszych, opcjonalnych nagłówków pakunku jest Bundle-Activator, który określa klasę, która go uruchamia i zatrzymuje.

Innym nagłówkiem jest Bundle-Localization, który wskazuje na katalog pakunku, w którym znajdują się pliki lokalizacyjne. Domyślną wartością jest OSGI-INF/l10n/bundle, np. polskie tłumaczenie znajduje się w OSGI-INF/l10n/bundle_pl.properties.

Domyślną wartością dla nagłówka Bundle-ManifestVersion jest 1 dla pakunków w wersji 3, podczas gdy 2 jest dla wersji 4 i wyższych.

Nagłówek Bundle-UpdateLocation wskazuje na adres, skąd można pobrać uaktualnienie pakunku.

Wersja pakunku znajduje się w nagłówku Bundle-Version i jest w formacie x.y.z-kwalifikator.

Przestrzeń klas to wszystkie klasy, jakie dostępne są przez pakunek. Należą do niej klasy z nadrzędnego zarządcy klas, zazwyczaj klasy z pakietu java.*, zaimportowane pakiety, wymagane pakunki, prywatne pakiety (klasy z pakunku) oraz dołączone fragmenty. OSGi musi zawsze delegować rozwiązanie klas z pakietu java.* do nadrzędnego zarządcy klas.

Podczas uruchamiania pakunku OSGi rozwiązuje wszelkie zależności związane z importem/exportem pakietów. Rozwiązanie następuje przed uruchomieniem pakunku.

Istotną kwestią związaną z widocznością klas jest pojęcie eksportu/importu pakietów. Definicja eksportu pakietu nie oznacza jego automatycznego importu. Pakunek, który eksportuje pakiet bez jego importu korzysta z pakietu w ramach jego własnego zarządcy klas pakunku. Tak wyeksportowany jedynie pakiet nie pozwala na podmianę go przez inny pakunek.

Pakunek może posiadać opcjonalne pakiety, których brak nie powoduje błędu uruchomienia pakunku, np. brak pakietu związanego z notowaniem zdarzeń. Implementacja pakunku, który korzysta z opcjonalnych pakietów, musi poprawnie obsługiwać sytuację, w której klasa nie jest dostępna.

Wewnątrz-pakunkowa ścieżka klas konstruowana jest na podstawie Bundle-Classpath. Nagłówek pozwala na zdefiniowanie wewnętrznej ścieżki klas składającej się z plików JAR lub katalogów, które są zawarte w pliku JAR pakunku. Domyślną wartością jest kropka reprezentująca sam plik JAR pakunku. Jakiekolwiek nierozwiązane wpisy w nagłówku powinny być ignorowane. Brak powinien być zarejestrowany w dzienniku zdarzeń na poziomie INFO z odpowiednim komunikatem.

Zabrania się, aby pakunek deklarował importy/eksporty pakietów java.*. Złamanie zasady skutkuje błędem podczas instalacji pakunku. Wszystkie inne pakiety dostępne z poziomu nadrzędnego zarządcy klas muszą być niedostępne dla pakunku.

Zasób w pakunku może być dostępny przez zarządcę klas tego pakunku, lecz może być również dostępne poprzez metody getResource(), getEntry() oraz findEntries(). Wszystkie wspomniane metody zwracają egzemplarz URL lub Enumeration obiektów URL. Schematy (części URL przez pierwszym dwukropkiem, np. http, czy file) dla tych URLi mogą się różnić i są zależne od środowiska uruchomieniowego.

Tłumaczenia związane z pakunkami przechowywane są w postaci zasobów w ramach pakunku. Domyślną nazwą podstawową dla miejsca tłumaczeń jest OSGI-INF/l10n/bundle. Miejsce, katalog w ramach pliku pakunku, jest relatywne w stosunku do korzenia. Wartości tłumaczonych nagłówków rozpoczynają się procentem '%', a dalsza część to klucz w pliku tłumaczeń, np.
  Bundle-Name: %nazwa pakunku
gdzie OSGI-INF/l10n/bundle_pl.properties:
  nazwa\ pakunku=Polska nazwa pakunku
Pakunki rozszerzające (ang. extension bundles) mogą dostarczać opcjonalnych części implementacji OSGi lub dostarczać funkcjonalności, która musi być dostępna na uruchomieniowej ścieżce klas. Pakunek rozszerzający powinien użyć nazwy symbolicznej pakunku systemowego lub jego aliasu - system.bundle.

Pozostaje się więc popróbować z tymi wiadomościami w praktyce. Chętni?